@agentikos/omega-os 0.19.31 → 0.19.33

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.
@@ -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.31"
191
+ __version__ = "0.19.33"
192
192
 
193
193
  __all__ = [
194
194
  "__version__",
@@ -2606,6 +2606,88 @@ def cmd_tmux(args: argparse.Namespace) -> int:
2606
2606
  print(f"no such session: {args.name}")
2607
2607
  return 1
2608
2608
 
2609
+ if sub == "switcher":
2610
+ # v0.19.32 — fzf-based tmux session picker.
2611
+ # Bound to Option+/ in the pro tmux config. Lists ALL live
2612
+ # tmux sessions (Omega, AISB-chat, Hermes-chat, per-project
2613
+ # oracles, workers, ...) with metadata, lets the user pick
2614
+ # one, and switches the client to it.
2615
+ import shlex, shutil, subprocess
2616
+ from omega_engine import __version__
2617
+ if not shutil.which("fzf"):
2618
+ print(" fzf not on PATH — install `brew install fzf` "
2619
+ "or `apt install fzf`")
2620
+ return 2
2621
+ sessions = tmux.list_sessions(home)
2622
+ if not sessions:
2623
+ print(" no tmux sessions yet — type `omega` to spawn the master")
2624
+ return 0
2625
+ sessions.sort(key=lambda s: -int(s.created))
2626
+
2627
+ def _age(ts: int) -> str:
2628
+ import time as _t
2629
+ delta = max(0, int(_t.time()) - int(ts))
2630
+ if delta < 60: return "now"
2631
+ if delta < 3600: return f"{delta // 60}m"
2632
+ if delta < 86400: return f"{delta // 3600}h"
2633
+ return f"{delta // 86400}d"
2634
+
2635
+ ORANGE = "\033[38;2;217;119;87m"
2636
+ MUTED = "\033[38;2;136;131;122m"
2637
+ BOLD = "\033[1m"
2638
+ DIM = "\033[2m"
2639
+ RST = "\033[0m"
2640
+
2641
+ lines = []
2642
+ keys = []
2643
+ for s in sessions:
2644
+ mark = f"{ORANGE}▶{RST}" if s.attached else " "
2645
+ project = f"[{s.project}]" if s.project else ""
2646
+ line = (
2647
+ f" {mark} {BOLD}{s.name:<32}{RST} "
2648
+ f"{DIM}{s.category:<10}{RST} "
2649
+ f"{MUTED}{s.windows}w {_age(s.created):<5}{RST} "
2650
+ f"{DIM}{project}{RST}"
2651
+ )
2652
+ lines.append(line)
2653
+ keys.append(s.name)
2654
+
2655
+ header = (
2656
+ f"{ORANGE}{BOLD}Ω Sessions{RST} "
2657
+ f"{MUTED}• ↑↓ navigate • ↵ switch-client • Esc cancel{RST}"
2658
+ )
2659
+ try:
2660
+ proc = subprocess.run(
2661
+ ["fzf", "--ansi", "--no-multi",
2662
+ "--prompt=session › ",
2663
+ f"--header={header}",
2664
+ "--header-first",
2665
+ "--layout=reverse",
2666
+ "--height=60%",
2667
+ "--border=rounded",
2668
+ "--padding=1,2",
2669
+ "--info=hidden",
2670
+ "--pointer=▶",
2671
+ "--color="
2672
+ "bg:#FAFAF7,fg:#3D3929,"
2673
+ "bg+:#E5E2DD,fg+:#D97757,"
2674
+ "hl:#D97757,hl+:#D97757,"
2675
+ "prompt:#D97757,pointer:#D97757,"
2676
+ "header:#88837A,border:#A8A29E,info:#88837A,"
2677
+ "gutter:#FAFAF7"],
2678
+ input="\n".join(lines), capture_output=True, text=True,
2679
+ )
2680
+ except (KeyboardInterrupt, subprocess.SubprocessError):
2681
+ return 0
2682
+ if proc.returncode != 0:
2683
+ return 0
2684
+ pick = proc.stdout.rstrip("\n")
2685
+ for line, name in zip(lines, keys):
2686
+ if line == pick:
2687
+ subprocess.run(["tmux", "switch-client", "-t", name])
2688
+ return 0
2689
+ return 0
2690
+
2609
2691
  if sub == "spawn":
2610
2692
  kind = args.kind
2611
2693
  name = args.name
@@ -3089,6 +3171,78 @@ def _set_active_provider(provider_id: str) -> None:
3089
3171
  p.write_text(provider_id.strip() + "\n")
3090
3172
 
3091
3173
 
3174
+ def cmd_paperclip(args: argparse.Namespace) -> int:
3175
+ """`omega paperclip {status,register,sync,start,heartbeat}` — bridge to
3176
+ paperclipai/paperclip (governance layer L0).
3177
+
3178
+ Lets the Paperclip web dashboard see OmegaOS's 14 agents (Hermès + 13
3179
+ AISB suite), every Genesis project as a workspace, and heartbeats
3180
+ from running tmux sessions. Paperclip stays a parallel system — we
3181
+ don't host Paperclip's server; we just write its config files +
3182
+ drop heartbeats it picks up.
3183
+ """
3184
+ from omega_engine import paperclip_bridge as PB
3185
+ sub = getattr(args, "paperclip_cmd", None) or "status"
3186
+
3187
+ if sub == "status":
3188
+ st = PB.status()
3189
+ print(f" paperclip installed: {'✓' if st.paperclip_installed else '—'}")
3190
+ print(f" paperclip_home: {st.paperclip_home}")
3191
+ print(f" omegaos company: {'✓' if st.company_registered else '—'} "
3192
+ f"{st.company_dir}")
3193
+ print(f" agents registered: {st.agents_registered} / 14")
3194
+ print(f" workspaces: {st.workspaces_registered}")
3195
+ print(f" heartbeats pending: {st.heartbeats_pending}")
3196
+ print(f" bridge_version: {st.bridge_version}")
3197
+ print(f" omega_version: {st.omega_version}")
3198
+ if st.drift:
3199
+ print(f" {st.drift = !r} — run `omega paperclip register` to refresh")
3200
+ if not st.paperclip_installed:
3201
+ print()
3202
+ print(" paperclip not installed — opt-in CLI:")
3203
+ print(" omega tool install paperclipai")
3204
+ print(" omega paperclip register # register OmegaOS company")
3205
+ print(" omega paperclip start # spin up the web dashboard")
3206
+ return 0
3207
+
3208
+ if sub == "register":
3209
+ summary = PB.register(dry_run=getattr(args, "dry_run", False))
3210
+ for k, v in summary.items():
3211
+ print(f" {k}: {v}")
3212
+ return 0
3213
+
3214
+ if sub == "start":
3215
+ bind = getattr(args, "bind", None) or "loopback"
3216
+ try:
3217
+ pid = PB.start_server(bind=bind, detach=True)
3218
+ print(f" paperclip launched (pid {pid}, bind={bind})")
3219
+ print(" default URL: http://localhost:8080 — check Paperclip output")
3220
+ return 0
3221
+ except RuntimeError as exc:
3222
+ print(f" start failed: {exc}")
3223
+ return 2
3224
+
3225
+ if sub == "heartbeat":
3226
+ # Drop a heartbeat from the current shell — used by `dispatch-to-
3227
+ # session.sh` style scripts so Paperclip sees workers come up + report.
3228
+ from omega_engine import paperclip_bridge as PB2
3229
+ hb = PB2.Heartbeat(
3230
+ agent_id=getattr(args, "agent_id", "unknown"),
3231
+ project=getattr(args, "project", ""),
3232
+ session=getattr(args, "session", os.environ.get("TMUX_PANE", "")),
3233
+ status=getattr(args, "status", "alive"),
3234
+ summary=getattr(args, "summary", ""),
3235
+ cost_so_far_usd=float(getattr(args, "cost", 0.0)),
3236
+ omega_home=os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")),
3237
+ )
3238
+ ok = PB2.send_heartbeat(hb)
3239
+ print(f" heartbeat: {'✓' if ok else '✗'} {hb.agent_id} → {hb.status}")
3240
+ return 0 if ok else 1
3241
+
3242
+ print(f"unknown paperclip subcommand: {sub}")
3243
+ return 2
3244
+
3245
+
3092
3246
  def cmd_scrape(args: argparse.Namespace) -> int:
3093
3247
  """`omega scrape <url> [--engine cloak|scrapling] [--out file]` — scraper.
3094
3248
 
@@ -4371,6 +4525,36 @@ def _build_parser() -> argparse.ArgumentParser:
4371
4525
  help="provider id (omit to print current + available)")
4372
4526
  p_sw.set_defaults(fn=cmd_switch)
4373
4527
 
4528
+ # `omega paperclip` — governance bridge to paperclipai/paperclip (L0).
4529
+ p_pc = sub.add_parser(
4530
+ "paperclip",
4531
+ help="bridge to Paperclip governance layer (register OmegaOS as "
4532
+ "a Paperclip company, sync projects, send heartbeats)",
4533
+ )
4534
+ p_pc.set_defaults(fn=cmd_paperclip)
4535
+ pc_sub = p_pc.add_subparsers(dest="paperclip_cmd")
4536
+ pc_sub.add_parser("status", help="show bridge health + counts")
4537
+ p_pcr = pc_sub.add_parser("register",
4538
+ help="write Paperclip company.json + agents/<id>.json + workspaces/")
4539
+ p_pcr.add_argument("--dry-run", action="store_true")
4540
+ p_pcs = pc_sub.add_parser("start",
4541
+ help="launch the Paperclip web dashboard (npx onboard)")
4542
+ p_pcs.add_argument("--bind", choices=["loopback", "lan", "tailnet"],
4543
+ default="loopback")
4544
+ p_pch = pc_sub.add_parser("heartbeat",
4545
+ help="send a heartbeat from a tmux session (script callable)")
4546
+ p_pch.add_argument("--agent-id", required=True,
4547
+ help="hermes / niobe / oracle / construct / …")
4548
+ p_pch.add_argument("--project", default="",
4549
+ help="project slug if applicable")
4550
+ p_pch.add_argument("--session", default="",
4551
+ help="tmux session name (defaults to $TMUX_PANE)")
4552
+ p_pch.add_argument("--status", default="alive",
4553
+ choices=["alive", "working", "done_clean", "failed"])
4554
+ p_pch.add_argument("--summary", default="")
4555
+ p_pch.add_argument("--cost", default="0",
4556
+ help="cost so far in USD (float)")
4557
+
4374
4558
  # `omega scrape <url>` — official OmegaOS web scraper (CloakBrowser
4375
4559
  # default, Scrapling optional). Both engines pre-installed at step 40
4376
4560
  # when their catalog entry is `recommended: true`.
@@ -4510,6 +4694,9 @@ def _build_parser() -> argparse.ArgumentParser:
4510
4694
  p_tcl.add_argument("--yes", action="store_true",
4511
4695
  help="apply (default is dry-run)")
4512
4696
  tx_sub.add_parser("menu", help="interactive whiptail picker (use under tmux for prefix+Z)")
4697
+ tx_sub.add_parser("switcher",
4698
+ help="fzf session switcher — list all live tmux sessions and "
4699
+ "switch-client to one (bound to Option+/ in the pro config)")
4513
4700
  p_tcfg = tx_sub.add_parser("config",
4514
4701
  help="write the recommended tmux.conf to Agentik_Tools/")
4515
4702
  p_tcfg.add_argument("--profile", choices=["minimal", "pro"],
@@ -0,0 +1,510 @@
1
+ """Paperclip ↔ OmegaOS bridge (v0.19.33).
2
+
3
+ Registers the OmegaOS agent hierarchy (Hermès + 13 AISB suite) as
4
+ Paperclip agents, mirrors Genesis projects into Paperclip workspaces,
5
+ and sends heartbeats from our tmux sessions into Paperclip's wakeup
6
+ queue. After registration, the Paperclip web dashboard surfaces every
7
+ OmegaOS agent / project / mission with its full org-chart + budget +
8
+ audit trail.
9
+
10
+ Layered model after this bridge lands:
11
+
12
+ Layer 0 — PAPERCLIP governance + org-chart + budgets + UI
13
+ (https://paperclip.dev)
14
+ Layer 1 — HUMAN Telegram / TUI / CLI
15
+ Layer 2 — HERMÈS meta-companion (Anthropic API, own bot)
16
+ Layer 3 — AISB (intake) Telegram-first classifier → oracle dispatch
17
+ Layer 4 — ORACLE per-project planner (Claude Max OAuth)
18
+ Layer 5 — WORKERS executors (one per subtask, .done.json)
19
+
20
+ Paperclip surfaces L1–L5 in its dashboard. Hermès still operates on its
21
+ own Anthropic budget; AISB/Oracle/Workers stay on Max OAuth. Paperclip
22
+ sees BOTH credential domains via its "agent bring own runtime" model.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import os
28
+ import shutil
29
+ import subprocess
30
+ import time
31
+ from dataclasses import asdict, dataclass, field
32
+ from pathlib import Path
33
+ from typing import Any
34
+
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # The OmegaOS canonical agent hierarchy
38
+ # ---------------------------------------------------------------------------
39
+
40
+ # Hermès sits ABOVE AISB in the OmegaOS architecture but reports to no-one
41
+ # inside Paperclip's org chart — it's the "COO" of the company.
42
+ HERMES_AGENT = {
43
+ "id": "hermes",
44
+ "title": "Hermès — Meta-Companion / COO",
45
+ "role": "meta",
46
+ "runtime": "anthropic-api",
47
+ "vault_secret": "ANTHROPIC_API_KEY_HERMES",
48
+ "model_provider": "anthropic",
49
+ "default_model": "claude-opus-4-7",
50
+ "reports_to": None,
51
+ "description": (
52
+ "L2 autonomous companion. Reads Omega state, proposes missions, "
53
+ "dispatches them DOWN into AISB. Runs on its own paid Anthropic "
54
+ "budget — never drains Claude Max."
55
+ ),
56
+ }
57
+
58
+
59
+ # The 13-agent AISB suite — pulled from the canonical
60
+ # bootstrap/templates/aisb/ tree. Each Paperclip agent maps 1:1 with one
61
+ # .md persona file in that tree.
62
+ AISB_AGENTS: list[dict[str, Any]] = [
63
+ {
64
+ "id": "niobe",
65
+ "title": "Niobe — AISB matriarch / intake",
66
+ "role": "intake",
67
+ "reports_to": "hermes",
68
+ "description": (
69
+ "Telegram-first classifier. Reads every inbound message, "
70
+ "decides Simple/Medium/Complex/Epic, dispatches to an oracle "
71
+ "with a structured brief."
72
+ ),
73
+ },
74
+ {
75
+ "id": "oracle",
76
+ "title": "Oracle — per-project planner",
77
+ "role": "planner",
78
+ "reports_to": "niobe",
79
+ "description": (
80
+ "Owns project context. Reads the brief + project CLAUDE.md, "
81
+ "decomposes into worker subtasks with verify_cmd, dispatches "
82
+ "and verifies completion."
83
+ ),
84
+ },
85
+ {
86
+ "id": "keymaker",
87
+ "title": "Keymaker — system planner / DAG",
88
+ "role": "system-planner",
89
+ "reports_to": "niobe",
90
+ "description": (
91
+ "Cross-project planning. Builds dependency DAGs for multi-"
92
+ "project missions (Genesis features, refonte programs)."
93
+ ),
94
+ },
95
+ {
96
+ "id": "construct",
97
+ "title": "Construct — worker executor",
98
+ "role": "worker",
99
+ "reports_to": "oracle",
100
+ "description": (
101
+ "Short-lived. Receives PLAN + FILES IN SCOPE + DONE CRITERIA + "
102
+ "VERIFY COMMAND. Executes step-by-step. Writes .done.json."
103
+ ),
104
+ },
105
+ {
106
+ "id": "seraph",
107
+ "title": "Seraph — quality gate / mission auditor",
108
+ "role": "auditor",
109
+ "reports_to": "niobe",
110
+ "description": (
111
+ "Runs 1–3 Quality Arsenal audits at close-gate. Requires "
112
+ "≥85/100 to approve. Falsifies before approving."
113
+ ),
114
+ },
115
+ {
116
+ "id": "smith",
117
+ "title": "Smith — learning + reflection",
118
+ "role": "educator",
119
+ "reports_to": "niobe",
120
+ "description": (
121
+ "Writes lessons (approved missions) + mistakes (rejected ≥2 "
122
+ "retries) to SQLite FTS5 memory. Next workers boot with the "
123
+ "5 most-recent lessons for the project."
124
+ ),
125
+ },
126
+ {
127
+ "id": "link",
128
+ "title": "Link — secure delivery / IO",
129
+ "role": "io",
130
+ "reports_to": "niobe",
131
+ "description": (
132
+ "Handles all outbound (Telegram, email, webhooks) + signed "
133
+ "inbound. HMAC verification, replay window enforcement."
134
+ ),
135
+ },
136
+ {
137
+ "id": "merovingian",
138
+ "title": "Merovingian — librarian / RAG",
139
+ "role": "librarian",
140
+ "reports_to": "niobe",
141
+ "description": (
142
+ "Owns the RAG corpus (hybrid + graph + agentic). Surfaces "
143
+ "context to other agents on demand."
144
+ ),
145
+ },
146
+ {
147
+ "id": "morpheus",
148
+ "title": "Morpheus — executor coordinator",
149
+ "role": "coordinator",
150
+ "reports_to": "oracle",
151
+ "description": (
152
+ "Orchestrates parallel workers. Dispatches multi-worker waves, "
153
+ "handles concurrency + dependencies + retry."
154
+ ),
155
+ },
156
+ {
157
+ "id": "architect",
158
+ "title": "Architect — system design / refactor",
159
+ "role": "architect",
160
+ "reports_to": "oracle",
161
+ "description": (
162
+ "Reads the codebase, finds entities, proposes refactors. "
163
+ "Owns architectural decisions, never executes them directly."
164
+ ),
165
+ },
166
+ {
167
+ "id": "neo",
168
+ "title": "Neo — uptime + recovery",
169
+ "role": "ops",
170
+ "reports_to": "niobe",
171
+ "description": (
172
+ "Monitors sessions, resource usage, alert thresholds. "
173
+ "Triggers /resurrect on stall. Never decides — just notifies."
174
+ ),
175
+ },
176
+ {
177
+ "id": "pythia",
178
+ "title": "Pythia — watcher / proposals (read-only)",
179
+ "role": "watcher",
180
+ "reports_to": "niobe",
181
+ "description": (
182
+ "Weekly read-only scan of platform docs + GitHub. Produces "
183
+ "gap-analysis proposals. Reports to Architect for triage. "
184
+ "NEVER touches billing/auth scopes."
185
+ ),
186
+ },
187
+ {
188
+ "id": "zion",
189
+ "title": "Zion — dashboard / metrics",
190
+ "role": "metrics",
191
+ "reports_to": "niobe",
192
+ "description": (
193
+ "Weekly dashboard generator. Pulls .done.json + audit history "
194
+ "+ session metrics. Produces formatted reports."
195
+ ),
196
+ },
197
+ ]
198
+
199
+
200
+ def all_agents() -> list[dict[str, Any]]:
201
+ """Return Hermès + the 13 AISB suite — 14 agents total."""
202
+ return [HERMES_AGENT] + AISB_AGENTS
203
+
204
+
205
+ # ---------------------------------------------------------------------------
206
+ # Paperclip filesystem layout (canonical paths under PAPERCLIP_HOME)
207
+ # ---------------------------------------------------------------------------
208
+
209
+
210
+ def paperclip_home() -> Path:
211
+ """Where Paperclip stores its agent configs + DB + secrets.
212
+
213
+ Resolution order:
214
+ 1. ``PAPERCLIP_HOME`` env var (operator override)
215
+ 2. ``~/.paperclip`` (typical Mac/Linux)
216
+ 3. ``$XDG_DATA_HOME/paperclip`` (XDG-conformant Linux)
217
+ """
218
+ env = os.environ.get("PAPERCLIP_HOME")
219
+ if env:
220
+ return Path(env).expanduser()
221
+ home = Path.home() / ".paperclip"
222
+ return home
223
+
224
+
225
+ def omegaos_company_dir(home: Path | None = None) -> Path:
226
+ """Where OmegaOS's company config lives under PAPERCLIP_HOME."""
227
+ base = home or paperclip_home()
228
+ return base / "companies" / "omegaos"
229
+
230
+
231
+ # ---------------------------------------------------------------------------
232
+ # Heartbeat sender
233
+ # ---------------------------------------------------------------------------
234
+
235
+
236
+ @dataclass
237
+ class Heartbeat:
238
+ """One heartbeat — sent from an OmegaOS tmux session to Paperclip."""
239
+
240
+ agent_id: str # "construct" / "oracle" / "hermes" / …
241
+ project: str # OmegaOS slug
242
+ session: str # tmux session name
243
+ status: str # "alive" | "working" | "done_clean" | "failed"
244
+ summary: str = "" # 1-line description of current work
245
+ timestamp: float = field(default_factory=time.time)
246
+ cost_so_far_usd: float = 0.0
247
+ omega_home: str = ""
248
+
249
+ def to_dict(self) -> dict[str, Any]:
250
+ return asdict(self)
251
+
252
+
253
+ def send_heartbeat(
254
+ hb: Heartbeat,
255
+ *,
256
+ paperclip_url: str = "",
257
+ paperclip_dir: Path | None = None,
258
+ ) -> bool:
259
+ """Send one heartbeat to Paperclip.
260
+
261
+ Two transport modes:
262
+ 1. HTTP POST to ``paperclip_url + /api/heartbeat`` when configured
263
+ 2. Filesystem drop into
264
+ ``$PAPERCLIP_HOME/companies/omegaos/heartbeats/<agent>-<ts>.json``
265
+ when there's no live Paperclip server (offline-friendly).
266
+
267
+ Returns True when the heartbeat was accepted/recorded.
268
+ """
269
+ payload = hb.to_dict()
270
+ if paperclip_url:
271
+ try:
272
+ import urllib.request as _urllib
273
+ import urllib.error as _ue
274
+ req = _urllib.Request(
275
+ f"{paperclip_url.rstrip('/')}/api/heartbeat",
276
+ data=json.dumps(payload).encode(),
277
+ headers={"Content-Type": "application/json"},
278
+ method="POST",
279
+ )
280
+ with _urllib.urlopen(req, timeout=5): # noqa: S310
281
+ return True
282
+ except _ue.URLError:
283
+ pass
284
+ except Exception: # noqa: BLE001
285
+ pass
286
+ # Filesystem fallback — Paperclip will pick these up on next boot.
287
+ target_dir = (paperclip_dir or omegaos_company_dir()) / "heartbeats"
288
+ target_dir.mkdir(parents=True, exist_ok=True)
289
+ fname = f"{hb.agent_id}-{int(hb.timestamp)}-{os.getpid()}.json"
290
+ (target_dir / fname).write_text(json.dumps(payload, indent=2))
291
+ return True
292
+
293
+
294
+ # ---------------------------------------------------------------------------
295
+ # Registration — write Paperclip's agent + company config from OmegaOS
296
+ # ---------------------------------------------------------------------------
297
+
298
+
299
+ def register(*,
300
+ omega_home: Path | str | None = None,
301
+ paperclip_dir: Path | None = None,
302
+ dry_run: bool = False) -> dict[str, Any]:
303
+ """Idempotently write Paperclip's `companies/omegaos/` tree from
304
+ the OmegaOS state.
305
+
306
+ Writes:
307
+ $PAPERCLIP_HOME/companies/omegaos/company.json ← top-level config
308
+ $PAPERCLIP_HOME/companies/omegaos/agents/<id>.json ← per-agent (14 files)
309
+ $PAPERCLIP_HOME/companies/omegaos/workspaces/<slug>.json ← per-project
310
+ $PAPERCLIP_HOME/companies/omegaos/.bridge-version ← versioning marker
311
+
312
+ Returns a summary dict for the caller (and the omega CLI).
313
+ """
314
+ home = Path(omega_home) if omega_home else Path(
315
+ os.environ.get("OMEGA_HOME", str(Path.home() / "Omega"))
316
+ )
317
+ pdir = paperclip_dir or omegaos_company_dir()
318
+ summary = {
319
+ "company": "omegaos",
320
+ "paperclip_home": str(pdir.parent.parent),
321
+ "company_dir": str(pdir),
322
+ "agents_written": 0,
323
+ "workspaces_written": 0,
324
+ "dry_run": dry_run,
325
+ }
326
+
327
+ agents = all_agents()
328
+ workspaces = _discover_projects(home)
329
+
330
+ if not dry_run:
331
+ pdir.mkdir(parents=True, exist_ok=True)
332
+ (pdir / "agents").mkdir(exist_ok=True)
333
+ (pdir / "workspaces").mkdir(exist_ok=True)
334
+ (pdir / "heartbeats").mkdir(exist_ok=True)
335
+
336
+ # company.json — the master config
337
+ company = {
338
+ "id": "omegaos",
339
+ "name": "Omega OS",
340
+ "tagline": (
341
+ "Verified-completion agentic operating system. "
342
+ "Hermès above, AISB intake, Oracle plans, Workers execute."
343
+ ),
344
+ "homepage": "https://github.com/agentik-os/OmegaOS",
345
+ "credential_domains": [
346
+ {
347
+ "id": "claude-max-oauth",
348
+ "label": "Claude Max OAuth (AISB+Oracle+Workers)",
349
+ "source": "~/.claude/.credentials.json",
350
+ "cost_per_call": 0.0,
351
+ "notes": "OAuth token for Claude Code Max — covered by sub",
352
+ },
353
+ {
354
+ "id": "anthropic-api-hermes",
355
+ "label": "Anthropic API (Hermès only)",
356
+ "vault_ref": "ANTHROPIC_API_KEY_HERMES",
357
+ "notes": "Hermès's own paid budget, isolated from Max",
358
+ },
359
+ ],
360
+ "verified_completion": {
361
+ "signal": ".done.json",
362
+ "status_values": ["done_clean", "pending", "failed"],
363
+ "audit_gate": "Seraph runs 1-3 Quality Arsenal audits ≥85/100",
364
+ },
365
+ "agent_count": len(agents),
366
+ "workspace_count": len(workspaces),
367
+ "bridge_version": _bridge_version(),
368
+ "registered_at": time.time(),
369
+ }
370
+ (pdir / "company.json").write_text(json.dumps(company, indent=2) + "\n")
371
+
372
+ # Per-agent files
373
+ for agent in agents:
374
+ (pdir / "agents" / f"{agent['id']}.json").write_text(
375
+ json.dumps(agent, indent=2) + "\n"
376
+ )
377
+ summary["agents_written"] += 1
378
+
379
+ # Per-workspace (project) files
380
+ for ws in workspaces:
381
+ (pdir / "workspaces" / f"{ws['slug']}.json").write_text(
382
+ json.dumps(ws, indent=2) + "\n"
383
+ )
384
+ summary["workspaces_written"] += 1
385
+
386
+ # Bridge version marker
387
+ (pdir / ".bridge-version").write_text(_bridge_version() + "\n")
388
+ else:
389
+ summary["agents_written"] = len(agents)
390
+ summary["workspaces_written"] = len(workspaces)
391
+
392
+ return summary
393
+
394
+
395
+ def _bridge_version() -> str:
396
+ """Pin to the OmegaOS engine version that wrote the bridge config."""
397
+ try:
398
+ from omega_engine import __version__
399
+ return __version__
400
+ except ImportError:
401
+ return "unknown"
402
+
403
+
404
+ def _discover_projects(omega_home: Path) -> list[dict[str, Any]]:
405
+ """Walk Agentik_Coding/projects/<slug>/ and return Paperclip-shape
406
+ workspace dicts."""
407
+ projects_root = omega_home / "Agentik_Coding" / "projects"
408
+ out: list[dict[str, Any]] = []
409
+ if not projects_root.is_dir():
410
+ return out
411
+ for entry in sorted(projects_root.iterdir()):
412
+ if not entry.is_dir():
413
+ continue
414
+ slug = entry.name
415
+ project_yaml = entry / "PROJECT.yaml"
416
+ meta: dict[str, Any] = {"slug": slug, "path": str(entry)}
417
+ if project_yaml.exists():
418
+ try:
419
+ import yaml as _yaml
420
+ meta.update(_yaml.safe_load(project_yaml.read_text()) or {})
421
+ except Exception: # noqa: BLE001
422
+ pass
423
+ # Paperclip "workspace" shape
424
+ out.append({
425
+ "id": slug,
426
+ "slug": slug,
427
+ "title": meta.get("title") or slug,
428
+ "phase": meta.get("phase") or "unknown",
429
+ "stack": meta.get("stack") or {},
430
+ "path": str(entry),
431
+ "registered_at": time.time(),
432
+ })
433
+ return out
434
+
435
+
436
+ # ---------------------------------------------------------------------------
437
+ # Status — does Paperclip know about OmegaOS, and how fresh?
438
+ # ---------------------------------------------------------------------------
439
+
440
+
441
+ @dataclass
442
+ class BridgeStatus:
443
+ paperclip_installed: bool
444
+ paperclip_home: str
445
+ company_dir: str
446
+ company_registered: bool
447
+ bridge_version: str
448
+ omega_version: str
449
+ agents_registered: int
450
+ workspaces_registered: int
451
+ heartbeats_pending: int
452
+ drift: bool # bridge_version != omega_version
453
+
454
+
455
+ def status() -> BridgeStatus:
456
+ """Return current bridge state — used by `omega paperclip status` +
457
+ `omega doctor`."""
458
+ pdir = omegaos_company_dir()
459
+ binary_present = bool(shutil.which("paperclip"))
460
+ bridge_v = ""
461
+ omega_v = _bridge_version()
462
+ company_present = (pdir / "company.json").exists()
463
+ agents_n = len(list((pdir / "agents").glob("*.json"))) if pdir.exists() else 0
464
+ workspaces_n = (
465
+ len(list((pdir / "workspaces").glob("*.json"))) if pdir.exists() else 0
466
+ )
467
+ heartbeats_n = (
468
+ len(list((pdir / "heartbeats").glob("*.json"))) if pdir.exists() else 0
469
+ )
470
+ if (pdir / ".bridge-version").exists():
471
+ bridge_v = (pdir / ".bridge-version").read_text().strip()
472
+ return BridgeStatus(
473
+ paperclip_installed=binary_present,
474
+ paperclip_home=str(paperclip_home()),
475
+ company_dir=str(pdir),
476
+ company_registered=company_present,
477
+ bridge_version=bridge_v or "(not yet registered)",
478
+ omega_version=omega_v,
479
+ agents_registered=agents_n,
480
+ workspaces_registered=workspaces_n,
481
+ heartbeats_pending=heartbeats_n,
482
+ drift=bool(bridge_v) and bridge_v != omega_v,
483
+ )
484
+
485
+
486
+ # ---------------------------------------------------------------------------
487
+ # Paperclip server lifecycle (start/stop the npx onboard process)
488
+ # ---------------------------------------------------------------------------
489
+
490
+
491
+ def start_server(bind: str = "loopback", *, detach: bool = True) -> int:
492
+ """Launch the Paperclip onboard server.
493
+
494
+ bind ∈ {"loopback", "lan", "tailnet"}.
495
+ Returns the PID (or 0 if synchronous run requested via detach=False).
496
+ """
497
+ if not shutil.which("npx"):
498
+ raise RuntimeError("npx not on PATH — install Node 20+")
499
+ args = ["npx", "-y", "paperclipai", "onboard", "--yes"]
500
+ if bind == "lan":
501
+ args += ["--bind", "lan"]
502
+ elif bind == "tailnet":
503
+ args += ["--bind", "tailnet"]
504
+ if detach:
505
+ proc = subprocess.Popen( # noqa: S603
506
+ args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
507
+ start_new_session=True,
508
+ )
509
+ return proc.pid
510
+ return subprocess.call(args)
@@ -572,9 +572,10 @@ bind-key Z display-popup -E -w 80% -h 80% "omega tmux menu"
572
572
  # Prefix+S — native session list (tmux's built-in choose-tree)
573
573
  bind-key S choose-tree -Zs
574
574
 
575
- # Open the Omega menu from anywhere in tmux (Option+/ or Option+z).
575
+ # Option+/ session switcher (fzf popup, pick any live tmux session)
576
+ # Option+z → Omega action menu (spawn Omega if missing + switch-client)
576
577
  # macOS Option key → enable "Use Option as Meta" in your terminal.
577
- bind-key -n M-/ run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
578
+ bind-key -n M-/ display-popup -E -h 80% -w 90% "omega tmux switcher"
578
579
  bind-key -n M-z run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
579
580
 
580
581
  # ════════════════════════════════════════════════════════════════════
@@ -686,7 +687,14 @@ bind-key r source-file ~/.tmux.conf \\; display-message "tmux.conf reloaded"
686
687
  # IMPORTANT — for Option key to work on macOS terminals, enable
687
688
  # "Use Option as Meta key" (iTerm2: Profile → Keys → Left/Right Option
688
689
  # Key → Esc+). Otherwise the binding stays inactive.
689
- bind-key -n M-/ run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
690
+ # ────────────────────────────────────────────────────────────────────
691
+ # Option+/ → SESSION SWITCHER (fzf — pick any live tmux session)
692
+ # Option+z → OMEGA ACTION MENU (the v0.19.30 fzf menu of actions)
693
+ # ────────────────────────────────────────────────────────────────────
694
+ # popup -E runs the command in a tmux popup overlay (modal). The popup
695
+ # closes when the command exits, returning the user to their previous
696
+ # pane. -h 80% / -w 90% sizes the popup.
697
+ bind-key -n M-/ display-popup -E -h 80% -w 90% "omega tmux switcher"
690
698
  bind-key -n M-z run-shell -b "tmux has-session -t Omega 2>/dev/null || tmux new-session -d -s Omega -n menu -c $HOME 'omega menu-tui'; tmux switch-client -t Omega"
691
699
 
692
700
  # ════════════════════════════════════════════════════════════════════
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "omega-engine"
3
- version = "0.19.31"
3
+ version = "0.19.33"
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.31
1
+ 0.19.33
@@ -53,11 +53,18 @@ catalog:
53
53
 
54
54
  - id: claude-mem
55
55
  name: claude-mem
56
- description: "Long-term memory + observation system across sessions"
56
+ description: |
57
+ Long-term memory + observation system across sessions.
58
+ KNOWN ISSUE (2026-05-25): claude-mem 13.3.0 ships a stop-hook
59
+ worker-service.cjs that imports `zod/v3` (doesn't exist in zod 4+).
60
+ Under Bun the hook crashes with "Cannot find module 'zod/v3'". The
61
+ plugin still installs — only the stop hook breaks.
62
+ Marked opt-in until upstream fixes. Install manually with:
63
+ claude plugin install claude-mem@thedotmack
57
64
  category: memory
58
65
  marketplace: thedotmack
59
66
  scope: user
60
- recommended: true
67
+ recommended: false
61
68
 
62
69
  - id: frontend-design
63
70
  name: frontend-design
@@ -76,11 +76,21 @@ native:
76
76
 
77
77
  - id: paperclipai
78
78
  name: Paperclip (orchestration UI — agent teams, org charts, governance)
79
- # Node.js + React app from paperclipai/paperclip. Coordinates multiple
80
- # agents (Claude Code, Codex, Cursor, OpenClaw) into teams with org
81
- # charts, budgets, governance. Launches a web dashboard + CLI tools.
82
- # We use the `onboard` npx flow which handles install + initial config.
83
- # Requires Node 20+, pnpm 9.15+ (both checked by step_system_deps).
79
+ # Node.js + React app from paperclipai/paperclip.
80
+ #
81
+ # STATUS (v0.19.32) honest disclosure:
82
+ # - The binary installs cleanly (`npx -y paperclipai onboard --yes`).
83
+ # - There is NO native OmegaOS↔Paperclip bridge yet. Paperclip's
84
+ # own docs list Claude Code, Codex, Cursor, OpenClaw — Hermès is
85
+ # NOT in their supported-agents list, and OmegaOS isn't either.
86
+ # - To make Paperclip "understand" our agents I'd need to:
87
+ # a) Write a Paperclip agent profile pointing at omega's
88
+ # claude/hermes subprocess invocations
89
+ # b) Add a heartbeat sender from our tmux sessions
90
+ # c) Map Paperclip's org-chart concepts to our 4-level model
91
+ # That's real work, scheduled for v0.20.x — not done yet.
92
+ # For now: install it if you want the standalone Paperclip UI, but
93
+ # treat it as a parallel system, not an OmegaOS bridge.
84
94
  install: { npm_global: "paperclipai" }
85
95
  binary: paperclip
86
96
  secrets: []
@@ -0,0 +1,193 @@
1
+ # OmegaOS × Paperclip Feature Matrix (v0.19.33)
2
+
3
+ > Cross-reference between OmegaOS (engine + AISB suite + tooling) and
4
+ > Paperclip (governance + org-chart + UI). Identifies what each system
5
+ > uniquely brings, where they overlap, and what the bridge fills in.
6
+
7
+ ---
8
+
9
+ ## 1. Paperclip — feature inventory
10
+
11
+ | # | Feature | What it does | Maps to OmegaOS as |
12
+ |---|---|---|---|
13
+ | 1 | **Org chart & agents** | Roles, titles, reporting lines, JDs | OmegaOS hierarchy (Hermès / AISB suite) registered as Paperclip agents via `omega paperclip register` |
14
+ | 2 | **Issue-based tasks** | Atomic checkout, dependencies, comments, audit logs | OmegaOS missions (`omega run`) + `.done.json` events |
15
+ | 3 | **Heartbeat execution** | Scheduled wakeups, budget checks, secret injection | `omega paperclip heartbeat --agent-id <…>` from tmux sessions |
16
+ | 4 | **Goal alignment** | Task → project → company → mission | OmegaOS Genesis project YAML carries `purpose` field |
17
+ | 5 | **Budget & cost** | Token/USD per agent/provider/model, hard stops | Per-LLM-provider tracking (claude_code = $0 OAuth; hermes = paid Anthropic; OpenRouter = OpenRouter API) |
18
+ | 6 | **Governance / approvals** | Board review, pause/terminate, config versioning | Maps to Stop-hook audit gate (Seraph ≥85/100 score) |
19
+ | 7 | **Workspaces** | Project workspaces, git worktrees, dev servers | OmegaOS `Agentik_Coding/projects/<slug>/` per-project isolation |
20
+ | 8 | **Routines / schedules** | Cron, webhook, API triggers | OmegaOS autonomous charters in `Agentik_Orchestration/autonomous/` |
21
+ | 9 | **Plugin system** | Instance-wide extensibility | OmegaOS skill catalog (`Agentik_SSOT/skills/`) |
22
+ | 10 | **Secrets storage** | Encrypted local + provider-backed | OmegaOS age vault (`omega vault`) |
23
+ | 11 | **Activity events** | Durable audit log | OmegaOS `Agentik_Runtime/eventlog/omega.db` |
24
+ | 12 | **Company portability** | Export/import org with secret scrubbing | OmegaOS Genesis pipeline + manifest YAML |
25
+ | 13 | **Multi-company support** | One deployment, many tenants | Multi-project under one `~/Omega` |
26
+ | 14 | **Mobile-ready management** | Browser UI for phones | OmegaOS Telegram bot (less rich but works) |
27
+ | 15 | **Web dashboard (React)** | Visual governance UI | Not in OmegaOS — fixed by registering OmegaOS as a Paperclip company |
28
+ | 16 | **PostgreSQL backend** | Production DB | OmegaOS uses SQLite WAL per project (simpler but smaller scale) |
29
+
30
+ ---
31
+
32
+ ## 2. OmegaOS — feature inventory
33
+
34
+ | # | Feature | What it does | Maps to Paperclip as |
35
+ |---|---|---|---|
36
+ | 1 | **AISB suite (13 agents)** | Niobe/Oracle/Construct/Seraph/Smith/… | 13 agent rows in Paperclip's org chart |
37
+ | 2 | **Hermès L2** | Meta-companion on Anthropic API | Top-of-chart "COO" agent in Paperclip (own credential domain) |
38
+ | 3 | **Genesis project pipeline** | vision→market→branding→PRD→features→plan | Workspace template in Paperclip |
39
+ | 4 | **Verified completion (`.done.json`)** | Worker status signal | Issue completion event with payload |
40
+ | 5 | **17 Quality Arsenal audits** | Forensic Gestalt-Popper audits | Approval workflow stages |
41
+ | 6 | **Plan v7 FSM-enforced executor** | Multi-day autonomous loop | Routines with state machine |
42
+ | 7 | **Claude Code Max OAuth** | Free-with-sub credential | Provider config (credential domain 1) |
43
+ | 8 | **Hermès Anthropic API key** | Isolated paid budget | Provider config (credential domain 2) |
44
+ | 9 | **13 LLM CLIs + hot-swap** | Claude/Gemini/Codex/OpenCode/Qwen/… | Agent runtime flexibility (each agent picks its CLI) |
45
+ | 10 | **16 provider configs** | Anthropic/OpenAI/Google/GLM/DeepSeek/Qwen/Ollama/LM Studio/OpenRouter/Bedrock/Mistral/xAI/Vercel Gateway/Copilot | Multi-provider routing |
46
+ | 11 | **Persona system** | 1 canonical → 10 LLM filenames | Agent prompt portability |
47
+ | 12 | **CloakBrowser scraper** | Stealth web scraping | Available to all Paperclip agents via `omega scrape` |
48
+ | 13 | **Scrapling scraper** | Fast HTTP-first scraping | Same |
49
+ | 14 | **Printing Press CLIs** | Agent-native CLIs (Stripe, Linear, …) | Same — available to all agents |
50
+ | 15 | **Tmux session orchestration** | Persistent sessions for oracles/workers | Workspace runtime backing |
51
+ | 16 | **`omega` TUI** | fzf arrow menu + slash REPL | Terminal-side control surface |
52
+ | 17 | **Telegram bot (AISB)** | Intake + dispatch | Mobile management surface |
53
+ | 18 | **age-encrypted vault** | Secrets storage | Maps to Paperclip's secrets store |
54
+ | 19 | **Autonomous charters** | Cron-driven agent triggers | Paperclip routines |
55
+ | 20 | **Event-sourced FSM** | Per-task state machine | Issue lifecycle in Paperclip |
56
+ | 21 | **`omega switch`** | Hot-swap LLM provider | Per-agent runtime change |
57
+ | 22 | **`omega scrape`** | Unified scraper interface | Tool surface for all agents |
58
+ | 23 | **`omega doctor`** | 30+ health checks | Paperclip dashboard's health view |
59
+ | 24 | **599 pytest tests** | Engine correctness | (Paperclip has its own test suite) |
60
+ | 25 | **Distributable via npm** | `npx @agentikos/omega-os@latest` | Single npm package, multi-platform |
61
+
62
+ ---
63
+
64
+ ## 3. Merger — the bridge fills these gaps
65
+
66
+ What OmegaOS WAS MISSING and Paperclip provides:
67
+
68
+ | OmegaOS gap | Paperclip fills it |
69
+ |---|---|
70
+ | No visual dashboard | Paperclip's React UI surfaces all 14 agents + projects + missions |
71
+ | Per-agent budget enforcement | Paperclip's budget engine (we report; Paperclip enforces) |
72
+ | Cross-LLM cost transparency | Paperclip's per-provider token tracking |
73
+ | Board-level approvals (beyond audit gate) | Paperclip's approval workflows |
74
+ | Company portability with secret scrubbing | Paperclip's export/import |
75
+
76
+ What Paperclip WAS MISSING and OmegaOS provides:
77
+
78
+ | Paperclip gap | OmegaOS fills it |
79
+ |---|---|
80
+ | 13 AISB agent personas | Paperclip company "omegaos" auto-registers them via bridge |
81
+ | Hermès L2 meta-companion | New agent role in Paperclip's chart |
82
+ | Verified-completion contract | OmegaOS's `.done.json` → Paperclip issue close event |
83
+ | Quality Arsenal audits (17 forensic) | Available to all Paperclip agents via `omega audit <id>` |
84
+ | Stealth scraping (CloakBrowser + Scrapling) | Available via `omega scrape <url>` |
85
+ | Hot-swap LLM mid-flight | `omega switch` from any Paperclip agent's runtime |
86
+ | Genesis project pipeline | Stack-aware workspace bootstrap |
87
+ | Age-encrypted vault | More secure than Paperclip's bare encrypted-local |
88
+ | 21-step installer with plan mode | One-line distribution beyond Paperclip's `npx onboard` |
89
+
90
+ ---
91
+
92
+ ## 4. Bridge layer (v0.19.33 ship)
93
+
94
+ ```
95
+ ┌──────────────────────────────────────────────────────────────────┐
96
+ │ PAPERCLIP — L0 governance (React UI, web dashboard) │
97
+ │ $PAPERCLIP_HOME/companies/omegaos/ │
98
+ │ ├── company.json ← OmegaOS company config │
99
+ │ ├── agents/<id>.json ← 14 agent profiles │
100
+ │ ├── workspaces/<slug>.json ← per-Genesis-project workspace │
101
+ │ └── heartbeats/*.json ← live status from tmux sessions │
102
+ └────────────────────────────────┬─────────────────────────────────┘
103
+
104
+ OmegaOS engine writes here via:
105
+ `omega paperclip register`
106
+ `omega paperclip sync`
107
+ `omega paperclip heartbeat`
108
+
109
+ ┌────────────────────────────────▼─────────────────────────────────┐
110
+ │ OMEGAOS — L1-L5 execution │
111
+ │ Hermès (L2) → AISB (L3) → Oracle (L4) → Workers (L5) │
112
+ │ Engine: ~/Omega/Agentik_Engine/omega_engine/ │
113
+ │ State: ~/Omega/Agentik_Runtime/ │
114
+ └──────────────────────────────────────────────────────────────────┘
115
+ ```
116
+
117
+ ## 5. Bridge commands (v0.19.33)
118
+
119
+ | Command | Effect |
120
+ |---|---|
121
+ | `omega paperclip status` | Show bridge health (agents/workspaces/heartbeats count, version drift) |
122
+ | `omega paperclip register` | Write Paperclip company config (idempotent) |
123
+ | `omega paperclip register --dry-run` | Preview without writing |
124
+ | `omega paperclip start [--bind loopback\|lan\|tailnet]` | Launch Paperclip server via `npx onboard` |
125
+ | `omega paperclip heartbeat --agent-id <id> --status <s>` | Send heartbeat from any tmux session |
126
+
127
+ ## 6. Features added to OmegaOS in v0.19.33
128
+
129
+ 1. `omega_engine.paperclip_bridge` module (this file).
130
+ 2. `omega paperclip` CLI subcommand (4 verbs).
131
+ 3. Per-agent profiles for the 13 AISB suite + Hermès, ready to be
132
+ written into Paperclip's `companies/omegaos/agents/` directory.
133
+ 4. Workspace discovery — reads `Agentik_Coding/projects/<slug>/PROJECT.yaml`,
134
+ maps each to a Paperclip workspace.
135
+
136
+ ## 7. Features still to add (v0.19.34+)
137
+
138
+ 1. **Heartbeat sender wired into spawn**: `tmux.spawn_worker()` and
139
+ `tmux.spawn_oracle()` should auto-call `omega paperclip heartbeat
140
+ --agent-id <id> --status alive` on spawn + on exit.
141
+ 2. **Per-agent budget enforcement in OmegaOS** mirroring Paperclip's
142
+ limits — read the budget config back from Paperclip and refuse new
143
+ missions when over budget.
144
+ 3. **Genesis stack option: "paperclip-managed"** — generates a
145
+ Paperclip company.json at project creation time alongside PROJECT.yaml.
146
+ 4. **`omega paperclip import <export.tar.gz>`** — adopt an OmegaOS
147
+ project from a Paperclip company export.
148
+ 5. **Heartbeat HTTP transport** — currently writes JSON to disk
149
+ (filesystem fallback). Add live POST to a running Paperclip server
150
+ when the URL is set.
151
+ 6. **AISB suite registration depth**: per-agent skills/tools mapping
152
+ so Paperclip's dashboard shows which Quality Arsenal audits Seraph
153
+ owns, which providers Hermès uses, etc.
154
+
155
+ ---
156
+
157
+ ## 8. AISB rules enforced across both systems
158
+
159
+ These are non-negotiable contracts that both OmegaOS code AND
160
+ Paperclip config must respect:
161
+
162
+ 1. **14 agents total** (Hermès + 13 AISB suite). The bridge writes
163
+ exactly 14 agent profiles — no more, no less.
164
+ 2. **Reporting lines fixed**:
165
+ - Hermès reports to nobody (top)
166
+ - Niobe reports to Hermès (intake matriarch)
167
+ - Oracle/Keymaker/Seraph/Smith/Link/Merovingian/Neo/Pythia/Zion
168
+ report to Niobe (specialists)
169
+ - Construct/Morpheus/Architect report to Oracle (per-project execution)
170
+ 3. **Credential domain isolation**:
171
+ - Claude Max OAuth → AISB+Oracle+Workers only (L3-L5)
172
+ - Anthropic API → Hermès only (L2)
173
+ - Paperclip never sees the live tokens, only credential domain refs
174
+ 4. **Verified completion contract**:
175
+ - Every Worker writes `.done.json` with `status ∈ {done_clean, pending, failed}`
176
+ - Oracle waits for ALL its workers' `.done.json` before its own
177
+ - Seraph runs 1-3 Quality Arsenal audits with score ≥85/100 to approve
178
+ - Paperclip's issue close event mirrors this state
179
+ 5. **Plans are first-class**:
180
+ - Oracle writes `plan.md` in `/project/<slug>/` before dispatching
181
+ - Workers receive PLAN + FILES IN SCOPE + DONE CRITERIA + VERIFY COMMAND
182
+ - Plan deviation = audit gate FAIL
183
+
184
+ These rules are baked into:
185
+ - `omega_engine.envelope` (mission envelope builder)
186
+ - `omega_engine.audit_arsenal` (audit gate)
187
+ - `omega_engine.paperclip_bridge.AISB_AGENTS` (this file's catalog)
188
+ - `Agentik_SSOT/agents/aisb/CLAUDE.md` (master prompt)
189
+ - `Agentik_SSOT/personas/OMEGAOS-CONTEXT.md` (per-LLM context)
190
+
191
+ ---
192
+
193
+ *Audit produit pour v0.19.33 — 2026-05-25.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentikos/omega-os",
3
- "version": "0.19.31",
3
+ "version": "0.19.33",
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"