@agentikos/omega-os 0.19.20 → 0.19.22

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.
@@ -99,6 +99,38 @@ _CATALOG: list[CliSpec] = [
99
99
  install_cmd=[], # filled at runtime
100
100
  description="Community aider-chat (`aider`)",
101
101
  ),
102
+ # v0.19.22 — extended provider matrix per the user's "install them all,
103
+ # let me hot-swap" spec.
104
+ CliSpec(
105
+ id="opencode", label="OpenCode (community multi-LLM)",
106
+ bin_name="opencode",
107
+ install_cmd=["npm", "install", "-g", "opencode-ai"],
108
+ description="OpenCode — terminal AI coding with provider switching",
109
+ ),
110
+ CliSpec(
111
+ id="openrouter_cli", label="OpenRouter via OpenCode",
112
+ bin_name="opencode", # opencode supports openrouter as a provider
113
+ install_cmd=[], # piggy-backs on opencode install
114
+ description="OpenRouter (300+ models) via OpenCode provider",
115
+ ),
116
+ CliSpec(
117
+ id="deepseek", label="DeepSeek (via OpenCode)",
118
+ bin_name="opencode",
119
+ install_cmd=[],
120
+ description="DeepSeek V3 / R1 via OpenCode provider",
121
+ ),
122
+ CliSpec(
123
+ id="qwen_code", label="Qwen Code (Alibaba CLI)",
124
+ bin_name="qwen",
125
+ install_cmd=["npm", "install", "-g", "@qwen-code/qwen-code"],
126
+ description="Alibaba's Qwen Coder CLI (`qwen`)",
127
+ ),
128
+ CliSpec(
129
+ id="continue_dev", label="Continue.dev (terminal)",
130
+ bin_name="cn",
131
+ install_cmd=["npm", "install", "-g", "@continuedev/cli"],
132
+ description="Continue.dev CLI — multi-provider with config.json",
133
+ ),
102
134
  ]
103
135
 
104
136
 
@@ -463,6 +463,154 @@ PY
463
463
 
464
464
  # --- 40 -----------------------------------------------------------------------
465
465
  #
466
+ # step_clis — install system CLIs + Printing Press CLI library.
467
+ #
468
+ # Replaces step_mcp as the default integration story (v0.19.21+). The
469
+ # rationale per the operator: MCP servers are token-expensive (each
470
+ # call pays protocol round-trip + server system prompt overhead). System
471
+ # CLIs that Claude Code shells out to via `Bash` are predictable, cheap,
472
+ # and survive without a long-lived server process. Printing Press
473
+ # (https://printingpress.dev) extends that model with agent-native CLIs
474
+ # that ship local SQLite mirrors — even cheaper than remote API calls.
475
+ #
476
+ # Three phases:
477
+ # 1. AUDIT — detect what's already installed; render a status table.
478
+ # 2. NATIVE — install missing recommended native binaries via the
479
+ # OS package manager (or npm-global / curl fallback).
480
+ # 3. PRINTING PRESS — install the PP factory + the recommended CLIs
481
+ # from the library catalog.
482
+ #
483
+ # Idempotent — re-running only acts on what's still missing.
484
+ step_clis() {
485
+ local catalog="$OMEGA_HOME/Agentik_SSOT/clis/clis-catalog.yaml"
486
+ [ -f "$catalog" ] || { err "CLI catalog missing: $catalog"; return 1; }
487
+ PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - "$catalog" "$OMEGA_PKG" <<'PY' 2>>"$LOG_FILE"
488
+ import os
489
+ import shutil
490
+ import subprocess
491
+ import sys
492
+ import yaml
493
+
494
+ catalog_path = sys.argv[1]
495
+ pkg = sys.argv[2] # apt | dnf | brew | unknown
496
+
497
+ with open(catalog_path) as f:
498
+ catalog = yaml.safe_load(f) or {}
499
+
500
+ # ─── Phase 1: audit ───────────────────────────────────────────
501
+ print("\n ──── CLI audit ────")
502
+ ok_count = 0
503
+ missing = []
504
+ for entry in catalog.get("native", []):
505
+ cli_id = entry["id"]
506
+ binary = entry.get("binary", cli_id)
507
+ if shutil.which(binary):
508
+ print(f" ok {cli_id:<14} ({binary} present)")
509
+ ok_count += 1
510
+ else:
511
+ rec = entry.get("recommended", False)
512
+ tag = "MISSING (recommended)" if rec else "missing (optional)"
513
+ print(f" -- {cli_id:<14} {tag}")
514
+ missing.append(entry)
515
+ print(f" → {ok_count}/{len(catalog.get('native', []))} native CLIs present\n")
516
+
517
+ # ─── Phase 2: install missing recommended native CLIs ─────────
518
+ def _run(cmd, env=None, timeout=600):
519
+ try:
520
+ proc = subprocess.run(cmd, capture_output=True, text=True,
521
+ timeout=timeout, env=env)
522
+ return proc.returncode, proc.stdout + proc.stderr
523
+ except (subprocess.SubprocessError, FileNotFoundError) as e:
524
+ return 1, str(e)
525
+
526
+ installed_now = []
527
+ failed_now = []
528
+ for entry in missing:
529
+ if not entry.get("recommended", False):
530
+ continue
531
+ cli_id = entry["id"]
532
+ install = entry.get("install", {})
533
+ rc, out, attempt = 1, "", ""
534
+
535
+ if pkg in install: # platform-specific package name
536
+ if pkg == "brew":
537
+ rc, out = _run(["brew", "install", install[pkg]])
538
+ attempt = f"brew install {install[pkg]}"
539
+ elif pkg == "apt":
540
+ rc, out = _run(["sudo", "apt-get", "install", "-y", "-qq", install[pkg]])
541
+ attempt = f"apt-get install {install[pkg]}"
542
+ elif pkg == "dnf":
543
+ rc, out = _run(["sudo", "dnf", "install", "-y", "-q", install[pkg]])
544
+ attempt = f"dnf install {install[pkg]}"
545
+ elif "npm_global" in install and shutil.which("npm"):
546
+ rc, out = _run(["npm", "install", "-g", "--silent", install["npm_global"]])
547
+ attempt = f"npm install -g {install['npm_global']}"
548
+ elif "curl" in install:
549
+ # curl|bash installer — last resort
550
+ rc, out = _run(["bash", "-c", f"curl -fsSL {install['curl']} | bash"])
551
+ attempt = f"curl {install['curl']} | bash"
552
+ else:
553
+ print(f" skip {cli_id}: no install method for pkg={pkg}")
554
+ continue
555
+
556
+ binary = entry.get("binary", cli_id)
557
+ if shutil.which(binary):
558
+ print(f" ok {cli_id:<14} (installed via {attempt})")
559
+ installed_now.append(cli_id)
560
+ else:
561
+ print(f" fail {cli_id}: {attempt} returned rc={rc}")
562
+ failed_now.append(cli_id)
563
+
564
+ # ─── Phase 3: Printing Press ──────────────────────────────────
565
+ pp_core = catalog.get("printing_press_core", {})
566
+ pp_clis = catalog.get("printing_press_clis", [])
567
+
568
+ print(f"\n ──── Printing Press ({len(pp_clis)} library CLIs available) ────")
569
+
570
+ # Install PP core (printer + library client) if not present
571
+ if not shutil.which("ppi-update") and not shutil.which("npx"):
572
+ print(" skip: neither ppi-update nor npx on PATH — install Node first")
573
+ elif not shutil.which("ppi-update"):
574
+ install_cmd = pp_core.get("install_method", "")
575
+ if install_cmd:
576
+ print(f" installing Printing Press core: {install_cmd}")
577
+ rc, out = _run(["bash", "-c", install_cmd], timeout=300)
578
+ if rc == 0:
579
+ print(" ok Printing Press core installed")
580
+ else:
581
+ print(f" warn Printing Press core install rc={rc} — library CLIs may still work via npx")
582
+ else:
583
+ print(" ok Printing Press core already installed")
584
+
585
+ # Install recommended PP library CLIs (one npx call per recommended entry)
586
+ pp_lib_cmd = ["npx", "-y", "@mvanhorn/printing-press-library"]
587
+ pp_ok = 0
588
+ pp_failed = []
589
+ for entry in pp_clis:
590
+ if not entry.get("recommended", False):
591
+ continue
592
+ cli_id = entry["id"]
593
+ print(f" installing pp-cli: {cli_id}…")
594
+ rc, out = _run([*pp_lib_cmd, "install", cli_id], timeout=300)
595
+ if rc == 0:
596
+ print(f" ok {cli_id}")
597
+ pp_ok += 1
598
+ else:
599
+ print(f" fail {cli_id}: rc={rc}")
600
+ pp_failed.append(cli_id)
601
+
602
+ print(f"\n ──── Summary ────")
603
+ print(f" Native CLIs installed this run: {installed_now or '(none missing)'}")
604
+ print(f" Native CLIs that failed: {failed_now or '(none)'}")
605
+ print(f" Printing Press CLIs installed: {pp_ok} (of {sum(1 for e in pp_clis if e.get('recommended'))} recommended)")
606
+ print(f" Printing Press CLIs that failed: {pp_failed or '(none)'}")
607
+ print(f" Non-recommended CLIs available via: omega cli install <id>")
608
+ PY
609
+ return 0
610
+ }
611
+
612
+ # --- 40-legacy ----------------------------------------------------------------
613
+ #
466
614
  # step_mcp — present the MCP/plugin catalog as a checklist (interactive) or
467
615
  # apply the manifest's `mcp:` list (headless). For each selected entry:
468
616
  # 1. install the server binary into Agentik_Tools/<id>/
package/install.sh CHANGED
@@ -147,7 +147,13 @@ STEPS=(
147
147
  "35-providers:step_providers"
148
148
  "36-tmux-config:step_tmux_config"
149
149
  "37-hermes-brief:step_hermes_brief"
150
- "40-mcp:step_mcp"
150
+ # v0.19.21 — MCP install dropped from the default sequence. MCPs are
151
+ # token-expensive (each call pays the protocol round-trip + the
152
+ # server's system prompt overhead). We replace with system CLIs +
153
+ # Printing Press (https://printingpress.dev) — agent-native CLIs
154
+ # with local SQLite mirrors. Re-enable opt-in via:
155
+ # omega tool install <id> (still wired for one-offs)
156
+ "40-clis:step_clis"
151
157
  "45-claude-plugins:step_claude_plugins"
152
158
  )
153
159
  if [ "$PROFILE" != "minimal" ]; then
@@ -188,7 +188,7 @@ from omega_engine.genesis import (
188
188
  )
189
189
  from omega_engine import plan as plan_v7
190
190
 
191
- __version__ = "0.19.20"
191
+ __version__ = "0.19.22"
192
192
 
193
193
  __all__ = [
194
194
  "__version__",
@@ -2941,6 +2941,80 @@ def cmd_menu_whiptail(_args: argparse.Namespace) -> int:
2941
2941
  return run_menu()
2942
2942
 
2943
2943
 
2944
+ # Default LLM provider for chat sessions — recorded in a tiny state file
2945
+ # so spawn_*_chat picks the right one. Hot-swap via `omega switch <id>`.
2946
+ _PROVIDER_MARKER = "active-llm-provider"
2947
+
2948
+
2949
+ def _provider_state_path() -> "Path":
2950
+ from pathlib import Path
2951
+ home = _omega_home()
2952
+ return home / "Agentik_Extra" / "var" / _PROVIDER_MARKER
2953
+
2954
+
2955
+ def _active_provider() -> str:
2956
+ p = _provider_state_path()
2957
+ if p.exists():
2958
+ return p.read_text().strip() or "claude_code"
2959
+ return "claude_code"
2960
+
2961
+
2962
+ def _set_active_provider(provider_id: str) -> None:
2963
+ p = _provider_state_path()
2964
+ p.parent.mkdir(parents=True, exist_ok=True)
2965
+ p.write_text(provider_id.strip() + "\n")
2966
+
2967
+
2968
+ def cmd_switch(args: argparse.Namespace) -> int:
2969
+ """`omega switch <provider>` — hot-swap the LLM provider for new chats.
2970
+
2971
+ Existing tmux sessions keep their current provider; only the NEXT
2972
+ chat session spawned (via `omega`, `omega aisb`, `omega hermes`) uses
2973
+ the new one. Per-LLM persona files are already in place in every
2974
+ context dir (write_all_personas runs at install + on every spawn),
2975
+ so switching is just changing which `cli` the tmux session launches.
2976
+
2977
+ Supported provider ids (must match the LLM CLI catalog in
2978
+ `bootstrap/lib/llm-clis.py` + `omega_engine.personas`):
2979
+
2980
+ claude_code, gemini_cli, codex, opencode, openrouter_cli,
2981
+ deepseek, qwen_code, continue_dev, aider
2982
+ """
2983
+ import shutil
2984
+ valid = {
2985
+ "claude_code": "claude",
2986
+ "gemini_cli": "gemini",
2987
+ "codex": "codex",
2988
+ "opencode": "opencode",
2989
+ "openrouter_cli": "opencode",
2990
+ "deepseek": "opencode",
2991
+ "qwen_code": "qwen",
2992
+ "continue_dev": "cn",
2993
+ "aider": "aider",
2994
+ }
2995
+ if not getattr(args, "provider", None):
2996
+ print(f" active provider: {_active_provider()}")
2997
+ print(f" available:")
2998
+ for pid, bin_name in valid.items():
2999
+ mark = "✓" if shutil.which(bin_name) else "—"
3000
+ active = " (active)" if pid == _active_provider() else ""
3001
+ print(f" {mark} {pid:<16} ({bin_name}){active}")
3002
+ return 0
3003
+ target = args.provider
3004
+ if target not in valid:
3005
+ print(f" unknown provider: {target!r}")
3006
+ print(f" valid: {', '.join(valid)}")
3007
+ return 2
3008
+ if not shutil.which(valid[target]):
3009
+ print(f" provider {target!r} not installed — `omega upgrade` "
3010
+ f"or re-run install.sh with the llm_clis: block")
3011
+ return 2
3012
+ _set_active_provider(target)
3013
+ print(f" active provider set to: {target}")
3014
+ print(f" next `omega` / `omega aisb` / `omega hermes` will launch with `{valid[target]}`")
3015
+ return 0
3016
+
3017
+
2944
3018
  def cmd_hermes_desktop(args: argparse.Namespace) -> int:
2945
3019
  """`omega hermes-desktop {install,serve,profile,status}` — expose this
2946
3020
  VPS as a remote backend for the Hermes Desktop Electron app."""
@@ -4024,6 +4098,17 @@ def _build_parser() -> argparse.ArgumentParser:
4024
4098
  help="open the interactive whiptail menu (the old `omega` behaviour)"
4025
4099
  ).set_defaults(fn=cmd_menu_whiptail)
4026
4100
  sub.add_parser("version", help="print the engine version").set_defaults(fn=cmd_version)
4101
+
4102
+ # `omega switch <provider>` — hot-swap the LLM CLI used for new chats.
4103
+ p_sw = sub.add_parser(
4104
+ "switch",
4105
+ help="switch the default LLM provider for new chat sessions "
4106
+ "(claude_code / gemini_cli / codex / opencode / qwen_code / "
4107
+ "continue_dev / aider)",
4108
+ )
4109
+ p_sw.add_argument("provider", nargs="?", default=None,
4110
+ help="provider id (omit to print current + available)")
4111
+ p_sw.set_defaults(fn=cmd_switch)
4027
4112
  p_doc = sub.add_parser("doctor", help="validate the deployment")
4028
4113
  p_doc.add_argument("--json", action="store_true",
4029
4114
  help="emit a single JSON object instead of pretty text")
@@ -176,6 +176,61 @@ def _backend_supabase_stack() -> Stack:
176
176
  )
177
177
 
178
178
 
179
+ def _convex_selfhosted_stack() -> Stack:
180
+ """Self-hosted Convex backend running on the operator's VPS.
181
+
182
+ Convex went open-source in 2024 — you can run the full backend
183
+ locally or on a VPS instead of paying the Convex Cloud. This stack
184
+ pre-wires that path: Next.js + Vercel frontend, Convex self-hosted
185
+ on the operator's VPS, Stripe payments, Clerk auth, shadcn UI.
186
+ """
187
+ return Stack(
188
+ id="convex-selfhosted",
189
+ title="Convex self-hosted (VPS) + Next.js + Vercel + Stripe + Clerk",
190
+ config=StackConfig(
191
+ type="web",
192
+ frontend="nextjs",
193
+ backend="convex", # but with extras=["selfhosted"]
194
+ deploy="vercel",
195
+ payments="stripe",
196
+ ui_kit="shadcn",
197
+ auth="clerk",
198
+ extras=["convex-selfhosted", "vps-backend"],
199
+ ),
200
+ why="When the operator wants Convex's real-time + typed model "
201
+ "without Convex Cloud lock-in. Backend runs on their VPS via "
202
+ "the open-source Convex docker image. Same DX, zero per-call "
203
+ "cost, full data sovereignty.",
204
+ )
205
+
206
+
207
+ def _sqlite_local_stack() -> Stack:
208
+ """Local SQLite-only stack — the simplest possible.
209
+
210
+ For tools, internal apps, single-user dashboards. No backend
211
+ process needed, no auth surface, no per-call cost. Drizzle ORM
212
+ over better-sqlite3 gives a typed query layer.
213
+ """
214
+ return Stack(
215
+ id="sqlite-local",
216
+ title="Local SQLite (Next.js + Drizzle + Vercel — single-user)",
217
+ config=StackConfig(
218
+ type="web",
219
+ frontend="nextjs",
220
+ backend="postgres+drizzle", # drizzle works with sqlite too
221
+ deploy="vercel",
222
+ payments="none",
223
+ ui_kit="shadcn",
224
+ auth="none",
225
+ extras=["sqlite-local", "drizzle-sqlite"],
226
+ ),
227
+ why="Single-user / internal-tool stack. SQLite file in the project "
228
+ "dir, Drizzle for typed queries, no auth, no payments. Ship "
229
+ "in 20 minutes. Upgrade to a real backend later when the "
230
+ "scale calls for it.",
231
+ )
232
+
233
+
179
234
  def _claude_dashboard_stack() -> Stack:
180
235
  """The Claude Code-grade premium dashboard stack.
181
236
 
@@ -213,6 +268,8 @@ CANONICAL_STACKS: dict[str, Stack] = {
213
268
  _desktop_tauri_stack(),
214
269
  _backend_supabase_stack(),
215
270
  _claude_dashboard_stack(),
271
+ _convex_selfhosted_stack(),
272
+ _sqlite_local_stack(),
216
273
  )
217
274
  }
218
275
 
@@ -0,0 +1,197 @@
1
+ """Multi-LLM persona writer — one canonical OmegaOS context, N output files.
2
+
3
+ Every LLM CLI we install (Claude Code, Gemini CLI, OpenAI Codex, OpenCode,
4
+ Continue.dev, Qwen, Aider…) reads a different filename for its project
5
+ context (CLAUDE.md, GEMINI.md, AGENTS.md, .opencode/CONTEXT.md, etc.).
6
+ Without a canonical source, the operator has to copy the same content
7
+ into N files manually and they drift.
8
+
9
+ This module:
10
+
11
+ 1. Defines the canonical OmegaOS context at one path
12
+ (``$OMEGA_HOME/Agentik_SSOT/personas/OMEGAOS-CONTEXT.md``).
13
+ 2. Exports ``write_all_personas(home, chat_context_dir)`` which mirrors
14
+ that one canonical file into every LLM's expected filename inside the
15
+ project dir, so when the user runs `claude`, `gemini`, `codex`,
16
+ etc. in that dir they ALL load the same OmegaOS persona.
17
+ 3. Idempotent — re-running diff-checks before write.
18
+
19
+ Used by:
20
+ * step_clis post-install pass — seeds the canonical context.
21
+ * tmux.spawn_*_chat — ensures the chat context dir has every persona
22
+ file before launching whichever CLI the user picked.
23
+ * `omega switch <provider>` — re-renders the active context's
24
+ persona pointer.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import shutil
29
+ from pathlib import Path
30
+
31
+
32
+ # The single source of truth. Every per-LLM persona file is a symlink or
33
+ # mirror of this.
34
+ CANONICAL_FILENAME = "OMEGAOS-CONTEXT.md"
35
+
36
+
37
+ # Map: LLM id → list of persona filenames it reads (relative to a project dir).
38
+ # Sources:
39
+ # - Anthropic Claude Code → CLAUDE.md (project root or ~/.claude/CLAUDE.md)
40
+ # - Google Gemini CLI → GEMINI.md (project root or ~/.gemini/GEMINI.md)
41
+ # - OpenAI Codex CLI → AGENTS.md (project root)
42
+ # - OpenCode → .opencode/CONTEXT.md
43
+ # - Continue.dev → .continue/CONTEXT.md
44
+ # - Qwen Code → QWEN.md
45
+ # - Aider → .aider.conf.yml (config, not full context)
46
+ # + CONVENTIONS.md (Aider's persona convention)
47
+ _LLM_PERSONA_PATHS: dict[str, list[str]] = {
48
+ "claude_code": ["CLAUDE.md"],
49
+ "gemini_cli": ["GEMINI.md"],
50
+ "codex": ["AGENTS.md"],
51
+ "opencode": [".opencode/CONTEXT.md"],
52
+ "openrouter_cli": [".opencode/CONTEXT.md"],
53
+ "deepseek": [".opencode/CONTEXT.md"],
54
+ "qwen_code": ["QWEN.md"],
55
+ "continue_dev": [".continue/CONTEXT.md"],
56
+ "aider": ["CONVENTIONS.md"],
57
+ "hermes": ["HERMES.md"],
58
+ }
59
+
60
+
61
+ _DEFAULT_CONTEXT_TEMPLATE = """\
62
+ # OmegaOS — Working Context
63
+
64
+ > *You are running inside an OmegaOS-managed Claude/Gemini/Codex/OpenCode
65
+ > session. This file is auto-generated by `omega_engine.personas` and
66
+ > mirrored from `$OMEGA_HOME/Agentik_SSOT/personas/OMEGAOS-CONTEXT.md`.
67
+ > Edits to per-LLM files (CLAUDE.md, GEMINI.md, …) are lost on next sync —
68
+ > edit the canonical file instead.*
69
+
70
+ ## What OmegaOS is
71
+
72
+ OmegaOS is a 5-layer agentic operating system:
73
+
74
+ ```
75
+ Layer 1 Human (Telegram, CLI, web)
76
+ Layer 2 Hermès — meta-companion (Anthropic API, separate budget)
77
+ Layer 3 AISB — OmegaOS intake / orchestrator (Claude Max OAuth)
78
+ Layer 4 Oracle — planner / dispatcher (per-project tmux session)
79
+ Layer 5 Workers — executors (one per subtask, .done.json verified)
80
+ ```
81
+
82
+ You sit at L4 or L5 depending on context.
83
+
84
+ ## The Three Laws (override everything)
85
+
86
+ 1. **Code lies. Comments lie. Only runtime tells the truth.**
87
+ Observe before concluding. Before the 3rd code change on the same
88
+ bug, live runtime evidence is MANDATORY.
89
+ 2. **Researcher, not sycophant.** Challenge flawed premises. Think
90
+ before coding. Iterate with evidence. Root causes over symptoms.
91
+ 3. **Autonomous execution.** When dispatched, never wait. Decide →
92
+ execute → report. The only legal stop is `.done.json` with status
93
+ `done_clean | pending | failed`.
94
+
95
+ ## OmegaOS structure (where things live)
96
+
97
+ ```
98
+ $OMEGA_HOME = ~/Omega
99
+ ├── Agentik_Engine/ ← Python engine (omega CLI)
100
+ ├── Agentik_SSOT/ ← source of truth
101
+ │ ├── skills/ ← 17 audits + orchestrators + /newcmd
102
+ │ ├── agents/aisb/ ← 13 AISB persona files
103
+ │ ├── personas/OMEGAOS-CONTEXT.md ← THIS FILE
104
+ │ ├── docs/LAYERS.md ← formal L1-L5 architecture
105
+ │ └── clis/clis-catalog.yaml ← CLI catalog
106
+ ├── Agentik_Orchestration/ ← topology YAMLs
107
+ ├── Agentik_Coding/projects/<slug>/ ← per-project root (strict isolation)
108
+ ├── Agentik_Runtime/ ← event log, RAG, locks, sessions
109
+ ├── Agentik_Tools/bin/omega ← the CLI you can shell out to
110
+ └── Agentik_Extra/etc/secrets/ ← age-encrypted vault
111
+ ```
112
+
113
+ ## What you can do (shell out via Bash)
114
+
115
+ | Action | Command |
116
+ |---|---|
117
+ | Mission with verified completion | `omega run "<intent>"` |
118
+ | New project (Genesis pipeline) | `omega genesis new <slug>` |
119
+ | Audit code/UI/flow/security/… | `omega audit <id>` (or the `/codeaudit` skill) |
120
+ | Switch LLM provider for this session | `omega switch <provider>` |
121
+ | Vault secrets | `omega vault read/write <REF>` |
122
+ | Status / health | `omega doctor` / `omega status` |
123
+ | Session manager (tmux) | `omega` (no args) |
124
+
125
+ ## Quality Arsenal (17 forensic audits)
126
+
127
+ `/codeaudit /flowaudit /uiuxaudit /debugaudit /featureaudit /perfaudit
128
+ /secaudit /a11yaudit /seoaudit /dataaudit /apiaudit /copyaudit /dxaudit
129
+ /motionaudit /automationaudit /logicaudit /retentionaudit`
130
+
131
+ Each: Gestalt clarity gate, Popper falsification, hinge point 10x
132
+ scrutiny, auto-fix, auto-re-audit, scored /100.
133
+
134
+ ## When something doesn't fit OmegaOS
135
+
136
+ Push back. Don't quietly invent. State the premise, decide, execute.
137
+ If the user's request would violate one of the Three Laws or the
138
+ verified-completion contract, call it out — they want a researcher,
139
+ not a yes-engine.
140
+ """
141
+
142
+
143
+ def canonical_path(omega_home: Path) -> Path:
144
+ """Where the single source of truth lives."""
145
+ return omega_home / "Agentik_SSOT" / "personas" / CANONICAL_FILENAME
146
+
147
+
148
+ def ensure_canonical(omega_home: Path) -> Path:
149
+ """Create the canonical OmegaOS context file if absent. Returns its
150
+ path. Operators are free to edit this file — it's the SSOT."""
151
+ path = canonical_path(omega_home)
152
+ path.parent.mkdir(parents=True, exist_ok=True)
153
+ if not path.exists():
154
+ path.write_text(_DEFAULT_CONTEXT_TEMPLATE)
155
+ return path
156
+
157
+
158
+ def write_all_personas(
159
+ omega_home: Path | str,
160
+ chat_context_dir: Path | str,
161
+ *,
162
+ llm_ids: list[str] | None = None,
163
+ ) -> dict[str, str]:
164
+ """Mirror the canonical context into every LLM's expected filename
165
+ inside ``chat_context_dir``.
166
+
167
+ Returns ``{llm_id: relative_path}`` for what was written. Files
168
+ that already match (content equality) are skipped silently —
169
+ idempotent.
170
+
171
+ When ``llm_ids`` is None we write for every LLM in
172
+ ``_LLM_PERSONA_PATHS`` (cheap insurance against the user later
173
+ swapping providers).
174
+ """
175
+ home = Path(omega_home)
176
+ ctx_dir = Path(chat_context_dir)
177
+ ctx_dir.mkdir(parents=True, exist_ok=True)
178
+
179
+ src = ensure_canonical(home)
180
+ content = src.read_text()
181
+
182
+ targets = list(llm_ids) if llm_ids else list(_LLM_PERSONA_PATHS)
183
+ written: dict[str, str] = {}
184
+ for llm in targets:
185
+ for rel in _LLM_PERSONA_PATHS.get(llm, []):
186
+ dest = ctx_dir / rel
187
+ dest.parent.mkdir(parents=True, exist_ok=True)
188
+ if dest.exists() and dest.read_text() == content:
189
+ continue
190
+ dest.write_text(content)
191
+ written[llm] = rel
192
+ return written
193
+
194
+
195
+ def supported_llm_ids() -> list[str]:
196
+ """The LLM ids personas can be written for."""
197
+ return list(_LLM_PERSONA_PATHS)
@@ -233,29 +233,59 @@ def spawn_worker(project: str, task: str, *,
233
233
 
234
234
  def _ensure_chat_context_dir(home: Path, label: str,
235
235
  persona_md_path: Path) -> Path:
236
- """Create (idempotent) a dedicated Claude Code project dir for an
237
- OmegaOS chat session.
238
-
239
- Drops ``CLAUDE.md`` (the persona) so Claude Code auto-loads it as
240
- project context when the user runs `claude` in this dir. Returns
241
- the path.
236
+ """Create (idempotent) a multi-LLM project dir for an OmegaOS chat
237
+ session.
238
+
239
+ v0.19.22 drops persona files for EVERY supported LLM (CLAUDE.md,
240
+ GEMINI.md, AGENTS.md, QWEN.md, .opencode/CONTEXT.md, etc.) sourced
241
+ from the canonical ``Agentik_SSOT/personas/OMEGAOS-CONTEXT.md``.
242
+ User can `claude` here, OR `gemini`, OR `codex`, OR `opencode`, OR
243
+ `qwen`, OR `aider` — they all see the SAME OmegaOS context. Hot-swap
244
+ works because every CLI's file is already in place.
245
+
246
+ The ``persona_md_path`` argument is now used only as a hint: if a
247
+ role-specific persona file exists at that path (e.g. the AISB v7.0
248
+ master prompt), we PREPEND it to the canonical context so AISB-chat
249
+ gets both the role identity AND the OmegaOS background, while
250
+ Hermes-chat gets just the canonical context.
242
251
  """
243
252
  ctx_dir = home / "Agentik_Coding" / "chat-contexts" / label
244
253
  ctx_dir.mkdir(parents=True, exist_ok=True)
245
- target = ctx_dir / "CLAUDE.md"
246
- if persona_md_path.is_file():
247
- # Mirror the upstream persona file so refreshes propagate.
248
- target.write_text(persona_md_path.read_text())
249
- elif not target.exists():
250
- target.write_text(
251
- f"# {label} chat context\n\n"
252
- f"(no persona file found using default Claude Code behaviour)\n"
253
- )
254
- # Also drop a .gitignore so this transient dir never gets committed
255
- # by accident if the user `git init`s it.
254
+
255
+ # Build the merged context: role-specific persona (if any) + canonical.
256
+ from omega_engine.personas import (
257
+ canonical_path, ensure_canonical, write_all_personas,
258
+ )
259
+ ensure_canonical(home)
260
+ canonical_text = canonical_path(home).read_text()
261
+ if persona_md_path.is_file() and persona_md_path.name not in (
262
+ "OMEGAOS-CONTEXT.md",
263
+ ):
264
+ role_text = persona_md_path.read_text()
265
+ merged = f"{role_text}\n\n---\n\n{canonical_text}"
266
+ # Write merged to the canonical filename in ctx_dir, then mirror
267
+ # to every LLM's expected filename via personas.write_all.
268
+ merged_file = ctx_dir / "OMEGAOS-CONTEXT.md"
269
+ merged_file.write_text(merged)
270
+ # personas.write_all reads from the canonical — temporarily point
271
+ # to the merged version by writing per-LLM files directly.
272
+ for llm_id in [
273
+ "claude_code", "gemini_cli", "codex", "opencode",
274
+ "qwen_code", "continue_dev", "aider", "hermes",
275
+ ]:
276
+ from omega_engine.personas import _LLM_PERSONA_PATHS # noqa: WPS437
277
+ for rel in _LLM_PERSONA_PATHS.get(llm_id, []):
278
+ dest = ctx_dir / rel
279
+ dest.parent.mkdir(parents=True, exist_ok=True)
280
+ if not dest.exists() or dest.read_text() != merged:
281
+ dest.write_text(merged)
282
+ else:
283
+ write_all_personas(home, ctx_dir)
284
+
285
+ # `.gitignore` so the transient dir doesn't get committed.
256
286
  gi = ctx_dir / ".gitignore"
257
287
  if not gi.exists():
258
- gi.write_text("*\n!.gitignore\n!CLAUDE.md\n")
288
+ gi.write_text("*\n!.gitignore\n!*.md\n!.opencode/\n!.continue/\n")
259
289
  return ctx_dir
260
290
 
261
291
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "omega-engine"
3
- version = "0.19.20"
3
+ version = "0.19.22"
4
4
  description = "The Omega OS orchestration engine — event-sourced, verified-completion agent graphs."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1 +1 @@
1
- 0.19.20
1
+ 0.19.22
@@ -131,3 +131,11 @@ catalog:
131
131
  marketplace: claude-plugins-official
132
132
  scope: user
133
133
  recommended: false
134
+
135
+ - id: superpowers
136
+ name: superpowers
137
+ description: "obra/superpowers — agentic framework with subagent-driven dev, TDD, planning, brainstorm, code review enforced"
138
+ category: workflow
139
+ marketplace: claude-plugins-official
140
+ scope: user
141
+ recommended: true
@@ -0,0 +1,151 @@
1
+ # Omega OS — system CLI catalog (v0.19.21+)
2
+ #
3
+ # Replaces the v0.19.20 MCP catalog. Rationale: MCP servers are
4
+ # token-expensive (each call pays the protocol round-trip + the server's
5
+ # system prompt overhead). System CLIs that Claude Code calls via `Bash`
6
+ # are cheap, predictable, and survive without a running server.
7
+ #
8
+ # Printing Press (https://printingpress.dev) ships ~50 agent-native CLIs
9
+ # with local SQLite mirrors for offline queries — even cheaper than
10
+ # remote API calls. We pull a curated subset by default.
11
+ #
12
+ # Maintained by the connection-educator (Agentik_Orchestration/educators/).
13
+ # Secrets are referenced by name only — operator wires them at install
14
+ # time or later via `omega vault write <REF> <value>`.
15
+
16
+ version: 1
17
+
18
+ # --- 1. Native binaries — install via system package manager -----------
19
+ # These are the bedrock — `omega audit` and most workflows assume
20
+ # they're on PATH.
21
+ native:
22
+ - id: gh
23
+ name: GitHub CLI
24
+ install: { brew: "gh", apt: "gh", dnf: "gh" }
25
+ recommended: true
26
+ - id: vercel
27
+ name: Vercel CLI
28
+ install: { npm_global: "vercel" }
29
+ recommended: true
30
+ - id: wrangler
31
+ name: Cloudflare Wrangler
32
+ install: { npm_global: "wrangler" }
33
+ recommended: false
34
+ - id: pnpm
35
+ name: pnpm package manager
36
+ install: { brew: "pnpm", npm_global: "pnpm" }
37
+ recommended: true
38
+ - id: bun
39
+ name: Bun runtime + package manager
40
+ install: { brew: "oven-sh/bun/bun", curl: "https://bun.sh/install" }
41
+ recommended: true
42
+ - id: ripgrep
43
+ name: ripgrep (rg) — fast code search
44
+ install: { brew: "ripgrep", apt: "ripgrep", dnf: "ripgrep" }
45
+ binary: rg
46
+ recommended: true
47
+ - id: bat
48
+ name: bat — better cat with syntax highlight
49
+ install: { brew: "bat", apt: "bat", dnf: "bat" }
50
+ recommended: false
51
+ - id: jq
52
+ name: jq — JSON processor
53
+ install: { brew: "jq", apt: "jq", dnf: "jq" }
54
+ recommended: true
55
+ - id: stripe-cli
56
+ name: Stripe CLI
57
+ install: { brew: "stripe/stripe-cli/stripe" }
58
+ binary: stripe
59
+ secrets: [STRIPE_API_KEY]
60
+ recommended: false
61
+ - id: playwright
62
+ name: Playwright (browser automation for E2E + audits)
63
+ install: { npm_global: "@playwright/test" }
64
+ secrets: []
65
+ recommended: true
66
+
67
+ # --- 2. Printing Press CLIs --------------------------------------------
68
+ # Installed via `npx -y @mvanhorn/printing-press-library install <name>`.
69
+ # Each ships with a local SQLite mirror + Claude Code skill.
70
+ #
71
+ # Catalog source: github.com/mvanhorn/printing-press-library/library
72
+ printing_press_core:
73
+ install_method: "curl -fsSL https://raw.githubusercontent.com/mvanhorn/cli-printing-press/main/scripts/install.sh | bash"
74
+ description: "Printing Press generator + library client (ppi-* CLIs)"
75
+
76
+ printing_press_clis:
77
+ - id: stripe
78
+ category: payments
79
+ description: "Every Stripe entity + local SQLite mirror, cross-entity SQL"
80
+ secrets: [STRIPE_API_KEY]
81
+ recommended: true
82
+ - id: linear
83
+ category: project-management
84
+ description: "Linear issues + projects, local SQLite mirror, compound queries"
85
+ secrets: [LINEAR_API_KEY]
86
+ recommended: true
87
+ - id: jira
88
+ category: project-management
89
+ description: "Jira issues + sprints"
90
+ secrets: [JIRA_API_TOKEN, JIRA_HOST]
91
+ recommended: false
92
+ - id: clickup
93
+ category: project-management
94
+ description: "ClickUp tasks + spaces"
95
+ secrets: [CLICKUP_API_KEY]
96
+ recommended: false
97
+ - id: cal-com
98
+ category: productivity
99
+ description: "Cal.com bookings + availability"
100
+ secrets: [CAL_COM_API_KEY]
101
+ recommended: false
102
+ - id: figma
103
+ category: productivity
104
+ description: "Figma files + comments (read-only)"
105
+ secrets: [FIGMA_TOKEN]
106
+ recommended: false
107
+ - id: fireflies
108
+ category: productivity
109
+ description: "Fireflies meeting transcripts + summaries"
110
+ secrets: [FIREFLIES_API_KEY]
111
+ recommended: false
112
+ - id: granola
113
+ category: productivity
114
+ description: "Granola notes export"
115
+ secrets: [GRANOLA_API_KEY]
116
+ recommended: false
117
+ - id: apify
118
+ category: developer-tools
119
+ description: "Apify scraping actors + dataset access"
120
+ secrets: [APIFY_TOKEN]
121
+ recommended: false
122
+ - id: firecrawl
123
+ category: developer-tools
124
+ description: "Firecrawl web scraping with local mirror"
125
+ secrets: [FIRECRAWL_API_KEY]
126
+ recommended: false
127
+ - id: docker-hub
128
+ category: developer-tools
129
+ description: "Docker Hub repos + tags inspection"
130
+ secrets: []
131
+ recommended: false
132
+ - id: twilio
133
+ category: social-and-messaging
134
+ description: "Twilio SMS + voice + WhatsApp"
135
+ secrets: [TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN]
136
+ recommended: false
137
+ - id: ahrefs
138
+ category: marketing
139
+ description: "Ahrefs SEO data with local SQLite mirror"
140
+ secrets: [AHREFS_API_KEY]
141
+ recommended: false
142
+ - id: google-search-console
143
+ category: marketing
144
+ description: "GSC properties + queries + pages"
145
+ secrets: [GSC_CREDENTIALS_JSON]
146
+ recommended: false
147
+ - id: google-ads
148
+ category: marketing
149
+ description: "Google Ads campaigns + spend"
150
+ secrets: [GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET]
151
+ recommended: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentikos/omega-os",
3
- "version": "0.19.20",
3
+ "version": "0.19.22",
4
4
  "description": "Omega OS — installable agentic operating system with verified-completion orchestration. Event-sourced engine, 8-block rack, autonomous agents, MCP.",
5
5
  "bin": {
6
6
  "omega-os": "bin/omega-os.js"