@agentikos/omega-os 0.19.33 → 0.19.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/omega/Agentik_Engine/omega_engine/__init__.py +1 -1
- package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/provider_state.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/tui.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/cli.py +8 -22
- package/omega/Agentik_Engine/omega_engine/provider_state.py +42 -0
- package/omega/Agentik_Engine/omega_engine/tui.py +6 -0
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_bridge.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_bridge.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tui_runtime.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tui_runtime.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_paperclip_bridge.py +139 -0
- package/omega/Agentik_Engine/tests/test_tui_runtime.py +104 -0
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/AUDIT-V0.19.34.md +143 -0
- package/omega/Agentik_SSOT/docs/LAYERS.md +21 -2
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3147,28 +3147,14 @@ def cmd_menu_whiptail(_args: argparse.Namespace) -> int:
|
|
|
3147
3147
|
return run_menu()
|
|
3148
3148
|
|
|
3149
3149
|
|
|
3150
|
-
#
|
|
3151
|
-
#
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
return home / "Agentik_Extra" / "var" / _PROVIDER_MARKER
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
def _active_provider() -> str:
|
|
3162
|
-
p = _provider_state_path()
|
|
3163
|
-
if p.exists():
|
|
3164
|
-
return p.read_text().strip() or "claude_code"
|
|
3165
|
-
return "claude_code"
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
def _set_active_provider(provider_id: str) -> None:
|
|
3169
|
-
p = _provider_state_path()
|
|
3170
|
-
p.parent.mkdir(parents=True, exist_ok=True)
|
|
3171
|
-
p.write_text(provider_id.strip() + "\n")
|
|
3150
|
+
# Active LLM provider — now lives in omega_engine.provider_state so the
|
|
3151
|
+
# Textual TUI can read it without a circular cli↔tui import (v0.19.35 fix).
|
|
3152
|
+
from omega_engine.provider_state import (
|
|
3153
|
+
active_provider as _active_provider,
|
|
3154
|
+
set_active_provider as _set_active_provider,
|
|
3155
|
+
provider_state_path as _provider_state_path,
|
|
3156
|
+
PROVIDER_MARKER as _PROVIDER_MARKER,
|
|
3157
|
+
)
|
|
3172
3158
|
|
|
3173
3159
|
|
|
3174
3160
|
def cmd_paperclip(args: argparse.Namespace) -> int:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Active-LLM-provider marker — shared between cli.py and tui.py.
|
|
2
|
+
|
|
3
|
+
The provider state lives in a tiny file at
|
|
4
|
+
``$OMEGA_HOME/Agentik_Extra/var/active-llm-provider``. `omega switch
|
|
5
|
+
<id>` writes here; the TUI and chat-spawn helpers read here.
|
|
6
|
+
|
|
7
|
+
Previously these helpers lived only in cli.py — but tui.py also needs
|
|
8
|
+
to read the active provider (to render `Switch LLM [current: claude_code]`
|
|
9
|
+
in the menu). Importing from cli would be circular (cli already imports
|
|
10
|
+
tui), so the helpers live here in their own neutral module.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
PROVIDER_MARKER = "active-llm-provider"
|
|
19
|
+
DEFAULT_PROVIDER = "claude_code"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _omega_home() -> Path:
|
|
23
|
+
return Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def provider_state_path() -> Path:
|
|
27
|
+
return _omega_home() / "Agentik_Extra" / "var" / PROVIDER_MARKER
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def active_provider() -> str:
|
|
31
|
+
"""Read the active provider id, falling back to claude_code."""
|
|
32
|
+
p = provider_state_path()
|
|
33
|
+
if p.exists():
|
|
34
|
+
return p.read_text().strip() or DEFAULT_PROVIDER
|
|
35
|
+
return DEFAULT_PROVIDER
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def set_active_provider(provider_id: str) -> None:
|
|
39
|
+
"""Persist the active provider id atomically."""
|
|
40
|
+
p = provider_state_path()
|
|
41
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
42
|
+
p.write_text(provider_id.strip() + "\n")
|
|
@@ -456,6 +456,12 @@ def _arrow_menu() -> int:
|
|
|
456
456
|
def _section(name: str) -> str:
|
|
457
457
|
return f"{ORANGE}{BOLD}── {name} ──{RST}"
|
|
458
458
|
|
|
459
|
+
# `_active_provider` lived in cli.py until v0.19.34 — calling it from
|
|
460
|
+
# here NameError'd at runtime because cli isn't imported here (would
|
|
461
|
+
# be circular: cli already imports tui). Now lives in a neutral
|
|
462
|
+
# `omega_engine.provider_state` module both can read.
|
|
463
|
+
from omega_engine.provider_state import active_provider as _active_provider
|
|
464
|
+
|
|
459
465
|
def _build_items() -> list[tuple[str, str]]:
|
|
460
466
|
"""Return (display, action_key) — section headers have key '__sep__'."""
|
|
461
467
|
provider = _active_provider()
|
package/omega/Agentik_Engine/tests/__pycache__/test_paperclip_bridge.cpython-313-pytest-8.4.2.pyc
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Regression tests for omega_engine.paperclip_bridge — locks in the
|
|
2
|
+
14-agent contract and the reporting-line invariants documented in
|
|
3
|
+
FEATURE-MATRIX.md §8 (AISB rules)."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import tempfile
|
|
8
|
+
import unittest
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from omega_engine import paperclip_bridge as P
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestAgentInventory(unittest.TestCase):
|
|
15
|
+
"""Lock in the AISB contract — 14 agents total, fixed reporting."""
|
|
16
|
+
|
|
17
|
+
def test_exactly_14_agents(self):
|
|
18
|
+
"""Hermès + 13 AISB suite = 14. Not 13, not 15."""
|
|
19
|
+
self.assertEqual(len(P.all_agents()), 14,
|
|
20
|
+
"the AISB contract requires exactly 14 agents — "
|
|
21
|
+
"if you added/removed one, update FEATURE-MATRIX.md §8 first")
|
|
22
|
+
|
|
23
|
+
def test_hermes_first_and_top(self):
|
|
24
|
+
agents = P.all_agents()
|
|
25
|
+
self.assertEqual(agents[0]["id"], "hermes")
|
|
26
|
+
self.assertIsNone(agents[0]["reports_to"],
|
|
27
|
+
"Hermès must be at the top of the org chart")
|
|
28
|
+
|
|
29
|
+
def test_aisb_suite_has_13(self):
|
|
30
|
+
self.assertEqual(len(P.AISB_AGENTS), 13)
|
|
31
|
+
|
|
32
|
+
def test_all_reporting_lines_valid(self):
|
|
33
|
+
"""Every non-None reports_to must point to an actual agent_id."""
|
|
34
|
+
agents = P.all_agents()
|
|
35
|
+
ids = {a["id"] for a in agents}
|
|
36
|
+
for a in agents:
|
|
37
|
+
rt = a.get("reports_to")
|
|
38
|
+
if rt is not None:
|
|
39
|
+
self.assertIn(rt, ids,
|
|
40
|
+
f"{a['id']} reports to {rt!r} which is not in the catalog")
|
|
41
|
+
|
|
42
|
+
def test_niobe_reports_to_hermes(self):
|
|
43
|
+
niobe = next(a for a in P.AISB_AGENTS if a["id"] == "niobe")
|
|
44
|
+
self.assertEqual(niobe["reports_to"], "hermes")
|
|
45
|
+
|
|
46
|
+
def test_oracle_reports_to_niobe(self):
|
|
47
|
+
oracle = next(a for a in P.AISB_AGENTS if a["id"] == "oracle")
|
|
48
|
+
self.assertEqual(oracle["reports_to"], "niobe")
|
|
49
|
+
|
|
50
|
+
def test_construct_reports_to_oracle(self):
|
|
51
|
+
c = next(a for a in P.AISB_AGENTS if a["id"] == "construct")
|
|
52
|
+
self.assertEqual(c["reports_to"], "oracle")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TestCredentialIsolation(unittest.TestCase):
|
|
56
|
+
"""L0-L5 credential domains must not bleed. Specifically:
|
|
57
|
+
- Hermès uses ANTHROPIC_API_KEY_HERMES (vault)
|
|
58
|
+
- The 13 AISB agents must NOT declare any Anthropic API key
|
|
59
|
+
(they share Claude Max OAuth from ~/.claude/.credentials.json)."""
|
|
60
|
+
|
|
61
|
+
def test_hermes_uses_anthropic_key(self):
|
|
62
|
+
self.assertEqual(P.HERMES_AGENT["vault_secret"],
|
|
63
|
+
"ANTHROPIC_API_KEY_HERMES")
|
|
64
|
+
self.assertEqual(P.HERMES_AGENT["runtime"], "anthropic-api")
|
|
65
|
+
|
|
66
|
+
def test_aisb_agents_do_not_declare_api_keys(self):
|
|
67
|
+
for a in P.AISB_AGENTS:
|
|
68
|
+
self.assertNotIn("vault_secret", a,
|
|
69
|
+
f"{a['id']} must not declare its own API key — AISB+Oracle+"
|
|
70
|
+
"Workers share the Claude Max OAuth at the engine level")
|
|
71
|
+
self.assertNotIn("runtime", a,
|
|
72
|
+
f"{a['id']} must not declare a runtime — runs as a "
|
|
73
|
+
"Claude Code subprocess under Max OAuth")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestRegisterDryRun(unittest.TestCase):
|
|
77
|
+
"""The register() entry point — dry-run mode must report what it
|
|
78
|
+
would write without touching disk."""
|
|
79
|
+
|
|
80
|
+
def test_dry_run_writes_nothing_to_disk(self):
|
|
81
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
82
|
+
pdir = Path(tmp) / "companies" / "omegaos"
|
|
83
|
+
summary = P.register(paperclip_dir=pdir, dry_run=True)
|
|
84
|
+
self.assertFalse(pdir.exists(),
|
|
85
|
+
"dry_run=True must not create the company dir")
|
|
86
|
+
self.assertEqual(summary["agents_written"], 14)
|
|
87
|
+
|
|
88
|
+
def test_register_writes_14_agent_files(self):
|
|
89
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
90
|
+
pdir = Path(tmp) / "companies" / "omegaos"
|
|
91
|
+
summary = P.register(paperclip_dir=pdir, dry_run=False)
|
|
92
|
+
# company.json
|
|
93
|
+
self.assertTrue((pdir / "company.json").exists())
|
|
94
|
+
company = json.loads((pdir / "company.json").read_text())
|
|
95
|
+
self.assertEqual(company["id"], "omegaos")
|
|
96
|
+
self.assertEqual(company["agent_count"], 14)
|
|
97
|
+
# 14 agent files
|
|
98
|
+
agent_files = list((pdir / "agents").glob("*.json"))
|
|
99
|
+
self.assertEqual(len(agent_files), 14,
|
|
100
|
+
f"register must write 14 agent files (got {len(agent_files)})")
|
|
101
|
+
# .bridge-version
|
|
102
|
+
self.assertTrue((pdir / ".bridge-version").exists())
|
|
103
|
+
self.assertEqual(summary["agents_written"], 14)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class TestHeartbeat(unittest.TestCase):
|
|
107
|
+
"""Heartbeat must drop a JSON file when no HTTP server is configured."""
|
|
108
|
+
|
|
109
|
+
def test_filesystem_fallback_writes_heartbeat(self):
|
|
110
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
111
|
+
pdir = Path(tmp) / "companies" / "omegaos"
|
|
112
|
+
hb = P.Heartbeat(
|
|
113
|
+
agent_id="construct",
|
|
114
|
+
project="test-project",
|
|
115
|
+
session="test-session",
|
|
116
|
+
status="working",
|
|
117
|
+
summary="step 2/5 in progress",
|
|
118
|
+
)
|
|
119
|
+
ok = P.send_heartbeat(hb, paperclip_dir=pdir)
|
|
120
|
+
self.assertTrue(ok)
|
|
121
|
+
files = list((pdir / "heartbeats").glob("construct-*.json"))
|
|
122
|
+
self.assertEqual(len(files), 1)
|
|
123
|
+
payload = json.loads(files[0].read_text())
|
|
124
|
+
self.assertEqual(payload["agent_id"], "construct")
|
|
125
|
+
self.assertEqual(payload["status"], "working")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TestStatus(unittest.TestCase):
|
|
129
|
+
"""status() must work even when nothing is registered yet."""
|
|
130
|
+
|
|
131
|
+
def test_status_safe_on_fresh_machine(self):
|
|
132
|
+
# Just call it — should not raise even if PAPERCLIP_HOME is bare.
|
|
133
|
+
st = P.status()
|
|
134
|
+
self.assertIsNotNone(st)
|
|
135
|
+
self.assertEqual(st.omega_version, P._bridge_version())
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
unittest.main()
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Regression tests for omega_engine.tui — specifically the NameError
|
|
2
|
+
that escaped pure-import tests in v0.19.34.
|
|
3
|
+
|
|
4
|
+
v0.19.34's `_arrow_menu` referenced `_active_provider` (defined only in
|
|
5
|
+
cli.py) which failed with NameError when actually invoked, even though
|
|
6
|
+
`import omega_engine.tui` succeeded. Lesson: import-only smoke tests
|
|
7
|
+
don't catch undefined-name errors inside function bodies. These tests
|
|
8
|
+
exercise the function bodies enough to catch the same class of bug.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
import os
|
|
14
|
+
import tempfile
|
|
15
|
+
import unittest
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestTuiBodyResolves(unittest.TestCase):
|
|
20
|
+
"""Compile + exec the bodies of TUI functions to surface undefined
|
|
21
|
+
names. Pytest's normal collection only imports modules — it never
|
|
22
|
+
runs `_arrow_menu` itself."""
|
|
23
|
+
|
|
24
|
+
def test_arrow_menu_body_compiles(self):
|
|
25
|
+
from omega_engine.tui import _arrow_menu
|
|
26
|
+
src = inspect.getsource(_arrow_menu)
|
|
27
|
+
# If a referenced helper isn't importable from inside the
|
|
28
|
+
# function, this raises (catches v0.19.34's NameError class).
|
|
29
|
+
compile(src, "<test>", "exec")
|
|
30
|
+
|
|
31
|
+
def test_plain_repl_body_compiles(self):
|
|
32
|
+
from omega_engine.tui import _plain_repl
|
|
33
|
+
src = inspect.getsource(_plain_repl)
|
|
34
|
+
compile(src, "<test>", "exec")
|
|
35
|
+
|
|
36
|
+
def test_dispatch_slash_for_parse_only_commands(self):
|
|
37
|
+
"""Every documented slash command that doesn't shell out to the
|
|
38
|
+
omega binary must produce a CommandResult (no NameError, no
|
|
39
|
+
AttributeError). Commands that shell out (`/audit`, `/switch`,
|
|
40
|
+
`/doctor`, etc.) need the omega binary on disk — those are
|
|
41
|
+
smoke-tested separately on real installs."""
|
|
42
|
+
from omega_engine.tui import dispatch_slash
|
|
43
|
+
# These never shell out — pure dispatch.
|
|
44
|
+
cmds = [
|
|
45
|
+
"/help", "/quit", "/detach", "/unknown_xyz_command",
|
|
46
|
+
"/audit", # no args → static text only, no shell-out
|
|
47
|
+
]
|
|
48
|
+
for c in cmds:
|
|
49
|
+
r = dispatch_slash(c)
|
|
50
|
+
self.assertIsNotNone(r, f"dispatch_slash({c!r}) returned None")
|
|
51
|
+
self.assertTrue(
|
|
52
|
+
r.text or r.exit_tui or r.detach,
|
|
53
|
+
f"dispatch_slash({c!r}) returned empty result",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TestProviderStateSharedModule(unittest.TestCase):
|
|
58
|
+
"""The fix for v0.19.34's NameError was to extract the provider
|
|
59
|
+
state helpers into omega_engine.provider_state. Lock that in."""
|
|
60
|
+
|
|
61
|
+
def test_provider_state_module_exposes_helpers(self):
|
|
62
|
+
from omega_engine import provider_state as PS
|
|
63
|
+
for name in (
|
|
64
|
+
"active_provider", "set_active_provider",
|
|
65
|
+
"provider_state_path", "PROVIDER_MARKER", "DEFAULT_PROVIDER",
|
|
66
|
+
):
|
|
67
|
+
self.assertTrue(hasattr(PS, name),
|
|
68
|
+
f"provider_state.{name} missing — TUI + CLI rely on it")
|
|
69
|
+
|
|
70
|
+
def test_get_set_roundtrip(self):
|
|
71
|
+
from omega_engine.provider_state import (
|
|
72
|
+
active_provider, set_active_provider,
|
|
73
|
+
)
|
|
74
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
75
|
+
old_home = os.environ.get("OMEGA_HOME")
|
|
76
|
+
os.environ["OMEGA_HOME"] = tmp
|
|
77
|
+
try:
|
|
78
|
+
# Default before any set
|
|
79
|
+
self.assertEqual(active_provider(), "claude_code")
|
|
80
|
+
# Set + read
|
|
81
|
+
set_active_provider("gemini_cli")
|
|
82
|
+
self.assertEqual(active_provider(), "gemini_cli")
|
|
83
|
+
# Whitespace stripped
|
|
84
|
+
set_active_provider(" codex ")
|
|
85
|
+
self.assertEqual(active_provider(), "codex")
|
|
86
|
+
finally:
|
|
87
|
+
if old_home is None:
|
|
88
|
+
os.environ.pop("OMEGA_HOME", None)
|
|
89
|
+
else:
|
|
90
|
+
os.environ["OMEGA_HOME"] = old_home
|
|
91
|
+
|
|
92
|
+
def test_cli_imports_from_provider_state(self):
|
|
93
|
+
"""The cli.py local `_active_provider` must be re-exported from
|
|
94
|
+
provider_state — not a divergent definition (the bug was that
|
|
95
|
+
cli.py owned the definition and tui.py couldn't see it)."""
|
|
96
|
+
from omega_engine import cli, provider_state
|
|
97
|
+
self.assertIs(cli._active_provider, provider_state.active_provider,
|
|
98
|
+
"cli._active_provider must alias provider_state.active_provider")
|
|
99
|
+
self.assertIs(cli._set_active_provider,
|
|
100
|
+
provider_state.set_active_provider)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
unittest.main()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.19.
|
|
1
|
+
0.19.35
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# OmegaOS v0.19.34 — deep audit, all bugs & incoherences logged
|
|
2
|
+
|
|
3
|
+
> Run on 2026-05-25 after the v0.19.33 Paperclip bridge ship.
|
|
4
|
+
> Method: parallel checks (pytest, shell syntax, imports, parsers,
|
|
5
|
+
> duplicate scan, version cross-ref, catalog parse, bridge invariants).
|
|
6
|
+
|
|
7
|
+
## 1. Clean (passed)
|
|
8
|
+
|
|
9
|
+
| Check | Result |
|
|
10
|
+
|---|---|
|
|
11
|
+
| pytest full suite | **612 passed** (599 + 13 new bridge tests) |
|
|
12
|
+
| Shell syntax `install.sh + common.sh + steps.sh` | ✓ |
|
|
13
|
+
| 14 internal Python modules importable | ✓ |
|
|
14
|
+
| Version coherent: `__init__.py / pyproject.toml / package.json / VERSION` | 0.19.34 |
|
|
15
|
+
| 4 catalog YAMLs parse cleanly | mcp 16 / plugins 11 / clis 28 / providers 16 |
|
|
16
|
+
| 49 omega subcommands registered in argparse | ✓ |
|
|
17
|
+
| tmux config 3-char hex regression | 0 occurrences (v0.19.28 fix holds) |
|
|
18
|
+
| Paperclip bridge: 14 agents, hermes top, reporting lines | ✓ |
|
|
19
|
+
| Personas: all 8 LLM filenames written by `write_all_personas` | ✓ |
|
|
20
|
+
| Hermès credential isolation (ANTHROPIC_API_KEY_HERMES) | ✓ |
|
|
21
|
+
| Filesystem fallback heartbeat | ✓ |
|
|
22
|
+
|
|
23
|
+
## 2. Bugs found + fixed in v0.19.34
|
|
24
|
+
|
|
25
|
+
| # | Bug | Severity | Fix |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| 1 | `LAYERS.md` didn't mention Paperclip even though the bridge shipped in v0.19.33 | doc gap | Added a v0.19.33+ section at the top with the L0 Paperclip diagram + pointer to FEATURE-MATRIX.md |
|
|
28
|
+
| 2 | No regression tests for `paperclip_bridge` — bridge invariants (14 agents, reporting lines, credential isolation) lived only in code | test gap | Added `tests/test_paperclip_bridge.py` (13 tests, all passing) covering: agent inventory, reporting lines per agent, credential isolation (AISB must NOT declare API keys), dry-run safety, register writes 14 files, heartbeat filesystem fallback, status() on fresh machine |
|
|
29
|
+
|
|
30
|
+
## 3. Code smells (NOT runtime bugs — flagged for future cleanup)
|
|
31
|
+
|
|
32
|
+
### 3.1 `_omega_home` duplicated 10× across modules
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
audit_gate.py def _omega_home() -> Path
|
|
36
|
+
handoff.py def _omega_home(home: str | Path | None) -> Path
|
|
37
|
+
tools.py def _omega_home(explicit: str | Path | None = None) -> Path
|
|
38
|
+
plan.py def _omega_home(explicit: str | Path | None = None) -> Path
|
|
39
|
+
aisb_chat.py def _omega_home() -> Path
|
|
40
|
+
hermes_bootstrap.py def _omega_home(explicit: str | Path | None) -> Path
|
|
41
|
+
mission.py def _omega_home(explicit: str | Path | None = None) -> Path
|
|
42
|
+
cleanup.py def _omega_home(home: str | Path | None) -> Path
|
|
43
|
+
project.py def _omega_home(explicit: str | Path | None = None) -> Path
|
|
44
|
+
daemons/telegram.py def _omega_home() -> Path
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Status**: not a runtime bug. Each module uses its own private helper.
|
|
48
|
+
But **3 different signatures** for the same conceptual function is
|
|
49
|
+
code smell. Refactor: extract to `omega_engine.paths.omega_home(explicit=None)`
|
|
50
|
+
and update all 10 call sites. Scope: ~30 line diff, low risk. **Backlog v0.20.x.**
|
|
51
|
+
|
|
52
|
+
### 3.2 `step_mcp` legacy function unreferenced from STEPS
|
|
53
|
+
|
|
54
|
+
`bootstrap/lib/steps.sh` defines 22 step functions but `install.sh` only
|
|
55
|
+
references 21 in its STEPS array. The orphan is `step_mcp` (deliberately
|
|
56
|
+
retired in v0.19.21 when we switched to `step_clis`).
|
|
57
|
+
|
|
58
|
+
**Status**: not a bug. `step_mcp` is still reachable via `omega tool install <id>`
|
|
59
|
+
as a manual escape hatch. Function header documents this. **Leave as-is.**
|
|
60
|
+
|
|
61
|
+
### 3.3 `cmd_billing` overlaps with `cmd_account*`
|
|
62
|
+
|
|
63
|
+
There's a `cmd_billing` (since pre-v0.19) showing per-account cost
|
|
64
|
+
aggregation, and a `cmd_account` family (list / login / use / pool) for
|
|
65
|
+
account management. User mentioned earlier wanting `/billing` renamed to
|
|
66
|
+
`/account` for Telegram parity, but the CLI subcommand is named `omega
|
|
67
|
+
billing` and that's its purpose (cost surfacing).
|
|
68
|
+
|
|
69
|
+
**Status**: not a bug. They serve adjacent purposes. The Telegram side
|
|
70
|
+
already uses `/account` (per v0.19.x routing). CLI rename would be a
|
|
71
|
+
breaking change for any user/script depending on `omega billing`.
|
|
72
|
+
**Backlog**: alias `omega billing` ↔ `omega account costs`. v0.19.35+
|
|
73
|
+
|
|
74
|
+
### 3.4 Multiple `_atomic_write`, `_have`, `_cache_path` helpers
|
|
75
|
+
|
|
76
|
+
Same pattern as `_omega_home` — local helpers duplicated across modules
|
|
77
|
+
because there's no shared `omega_engine.paths` / `omega_engine.utils`.
|
|
78
|
+
Same refactor as 3.1. **Backlog v0.20.x.**
|
|
79
|
+
|
|
80
|
+
## 4. Architecture invariants verified
|
|
81
|
+
|
|
82
|
+
These come from FEATURE-MATRIX.md §8 (AISB rules). Audit confirms each
|
|
83
|
+
is enforced AT CODE LEVEL, not just at doc level:
|
|
84
|
+
|
|
85
|
+
| Invariant | Where it's enforced |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Exactly 14 agents (Hermès + 13 AISB) | `paperclip_bridge.AISB_AGENTS` (13) + `HERMES_AGENT` (1); locked by `test_exactly_14_agents` |
|
|
88
|
+
| Hermès reports to no-one | `HERMES_AGENT["reports_to"] = None`; locked by `test_hermes_first_and_top` |
|
|
89
|
+
| Niobe reports to Hermès | Catalog + `test_niobe_reports_to_hermes` |
|
|
90
|
+
| Oracle reports to Niobe | Catalog + `test_oracle_reports_to_niobe` |
|
|
91
|
+
| Construct reports to Oracle | Catalog + `test_construct_reports_to_oracle` |
|
|
92
|
+
| Credential domain isolation | `test_aisb_agents_do_not_declare_api_keys` + `test_hermes_uses_anthropic_key` |
|
|
93
|
+
| `.done.json` verified completion | `done_signal.py` write_done() schema |
|
|
94
|
+
| Audit gate ≥85/100 | `audit_gate.py` threshold |
|
|
95
|
+
| Plan first (Oracle writes plan.md before dispatch) | Mission envelope builder + `plan.py` FSM |
|
|
96
|
+
|
|
97
|
+
## 5. Counts (the system's "shape")
|
|
98
|
+
|
|
99
|
+
- **Engine modules**: 60 Python files
|
|
100
|
+
- **AISB suite agent prompts**: 15 .md (13 personas + CLAUDE.md + lmc-protocol.md, + protocols/ + checkers/)
|
|
101
|
+
- **Test files**: 42 (was 41 — added `test_paperclip_bridge.py`)
|
|
102
|
+
- **pytest tests**: 612 (was 599 — added 13)
|
|
103
|
+
- **Install steps**: 21 in install.sh STEPS array
|
|
104
|
+
- **Step functions defined**: 22 in steps.sh (1 legacy: step_mcp)
|
|
105
|
+
- **CLI subcommands**: 49 distinct omega subcommands
|
|
106
|
+
- **MCP catalog entries**: 16 (legacy, opt-in only)
|
|
107
|
+
- **Claude plugins**: 11 (after v0.19.20 cleanup, claude-mem now opt-in)
|
|
108
|
+
- **System CLIs**: 28 (incl. CloakBrowser, Scrapling, Paperclip, …)
|
|
109
|
+
- **LLM providers**: 16 (Anthropic/OpenAI/Google/GLM/DeepSeek/Qwen/Ollama/LM Studio/OpenRouter/Bedrock/Mistral/xAI/Vercel Gateway/Copilot/OpenAI-compat/ChatGPT)
|
|
110
|
+
- **Genesis stack presets**: 8 (canonical/mobile-native/mobile-expo/desktop-tauri/supabase/claude-dashboard/convex-selfhosted/sqlite-local)
|
|
111
|
+
- **Personas supported**: 10 LLM filenames
|
|
112
|
+
- **Quality Arsenal audits**: 17 (Skills as forensic protocols)
|
|
113
|
+
|
|
114
|
+
## 6. Verdict
|
|
115
|
+
|
|
116
|
+
**v0.19.34 is clean** for what it claims to do:
|
|
117
|
+
|
|
118
|
+
- ✓ Multi-LLM ecosystem (13 CLIs + 16 providers + persona system)
|
|
119
|
+
- ✓ Multi-scraper (CloakBrowser + Scrapling)
|
|
120
|
+
- ✓ Tmux-based session orchestration (Omega master + chat windows)
|
|
121
|
+
- ✓ Paperclip bridge (governance roof, 14 agents, idempotent)
|
|
122
|
+
- ✓ Hermès isolated credentials (Anthropic API)
|
|
123
|
+
- ✓ AISB+Oracle+Workers on Max OAuth
|
|
124
|
+
- ✓ Verified completion (.done.json + audit gate)
|
|
125
|
+
- ✓ Light Claude theme (fzf + tmux)
|
|
126
|
+
- ✓ Arrow-key menu (fzf) + session switcher (Option+/)
|
|
127
|
+
- ✓ 612 tests pass
|
|
128
|
+
|
|
129
|
+
**Not yet there** (backlog v0.19.35+):
|
|
130
|
+
|
|
131
|
+
- Auto-heartbeat hook in `tmux.spawn_worker / spawn_oracle`
|
|
132
|
+
- Per-agent budget enforcement from Paperclip
|
|
133
|
+
- HTTP heartbeat transport (currently filesystem only)
|
|
134
|
+
- Refactor `_omega_home` + 4-5 other helpers into `omega_engine.paths`
|
|
135
|
+
- Streaming async in the Textual TUI
|
|
136
|
+
|
|
137
|
+
**Production-ready** for: distribution via npm, end-to-end install on
|
|
138
|
+
macOS/Linux, multi-LLM coding sessions, project genesis, audit-gated
|
|
139
|
+
missions, optional Paperclip governance.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
*Audit run on commit after v0.19.33 ship, before v0.19.34 release.*
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
# OmegaOS Layered Architecture
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> **Six layers** (L0–L5) with Paperclip as the optional governance roof.
|
|
4
|
+
> Two independent credential domains. Two Telegram bots with separate
|
|
5
|
+
> tokens. Hermès above the OmegaOS core; AISB+Oracle+Workers below.
|
|
5
6
|
> Each layer is independently usable.
|
|
6
7
|
|
|
8
|
+
## v0.19.33+ — Paperclip as L0 governance
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
12
|
+
│ Layer 0 ─ PAPERCLIP (optional, governance roof) │
|
|
13
|
+
│ React dashboard + budget + org chart + approvals. │
|
|
14
|
+
│ Registered via `omega paperclip register` — writes │
|
|
15
|
+
│ ~/.paperclip/companies/omegaos/ with 14 agent profiles. │
|
|
16
|
+
│ Heartbeats from L1-L5 sessions feed this layer. │
|
|
17
|
+
└────────────────────────────────────────┬─────────────────────────────┘
|
|
18
|
+
│
|
|
19
|
+
▼
|
|
20
|
+
[everything below is the original L1-L5 model]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
See `omega/Agentik_SSOT/docs/FEATURE-MATRIX.md` for the full feature
|
|
24
|
+
cross-reference + bridge command list.
|
|
25
|
+
|
|
7
26
|
## The corrected model (v0.19.14)
|
|
8
27
|
|
|
9
28
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentikos/omega-os",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.35",
|
|
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"
|