@agentikos/omega-os 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/bin/omega-os.js +48 -0
  4. package/bootstrap/lib/common.sh +73 -0
  5. package/bootstrap/lib/steps.sh +153 -0
  6. package/bootstrap/manifest.example.yaml +45 -0
  7. package/docs/ACCOUNT-AND-BILLING.md +95 -0
  8. package/docs/ARCHITECTURE.md +225 -0
  9. package/docs/AUTONOMOUS-AGENTS.md +128 -0
  10. package/docs/ENGINE-SPEC.md +174 -0
  11. package/docs/INSTALL.md +106 -0
  12. package/docs/MCP-AND-PLUGINS.md +121 -0
  13. package/docs/RUNTIME-PLAN.md +63 -0
  14. package/install.sh +54 -0
  15. package/omega/Agentik_Coding/README.md +21 -0
  16. package/omega/Agentik_Engine/README.md +58 -0
  17. package/omega/Agentik_Engine/omega_engine/__init__.py +58 -0
  18. package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
  19. package/omega/Agentik_Engine/omega_engine/__pycache__/audit.cpython-313.pyc +0 -0
  20. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_arsenal.cpython-313.pyc +0 -0
  21. package/omega/Agentik_Engine/omega_engine/__pycache__/barrier.cpython-313.pyc +0 -0
  22. package/omega/Agentik_Engine/omega_engine/__pycache__/bus.cpython-313.pyc +0 -0
  23. package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
  24. package/omega/Agentik_Engine/omega_engine/__pycache__/events.cpython-313.pyc +0 -0
  25. package/omega/Agentik_Engine/omega_engine/__pycache__/executor.cpython-313.pyc +0 -0
  26. package/omega/Agentik_Engine/omega_engine/__pycache__/mission.cpython-313.pyc +0 -0
  27. package/omega/Agentik_Engine/omega_engine/__pycache__/progress.cpython-313.pyc +0 -0
  28. package/omega/Agentik_Engine/omega_engine/__pycache__/project.cpython-313.pyc +0 -0
  29. package/omega/Agentik_Engine/omega_engine/__pycache__/provider.cpython-313.pyc +0 -0
  30. package/omega/Agentik_Engine/omega_engine/__pycache__/reducer.cpython-313.pyc +0 -0
  31. package/omega/Agentik_Engine/omega_engine/__pycache__/report.cpython-313.pyc +0 -0
  32. package/omega/Agentik_Engine/omega_engine/__pycache__/router.cpython-313.pyc +0 -0
  33. package/omega/Agentik_Engine/omega_engine/__pycache__/store.cpython-313.pyc +0 -0
  34. package/omega/Agentik_Engine/omega_engine/__pycache__/supervisor.cpython-313.pyc +0 -0
  35. package/omega/Agentik_Engine/omega_engine/__pycache__/task.cpython-313.pyc +0 -0
  36. package/omega/Agentik_Engine/omega_engine/__pycache__/telegram.cpython-313.pyc +0 -0
  37. package/omega/Agentik_Engine/omega_engine/audit.py +96 -0
  38. package/omega/Agentik_Engine/omega_engine/audit_arsenal.py +314 -0
  39. package/omega/Agentik_Engine/omega_engine/barrier.py +45 -0
  40. package/omega/Agentik_Engine/omega_engine/bus.py +45 -0
  41. package/omega/Agentik_Engine/omega_engine/cli.py +158 -0
  42. package/omega/Agentik_Engine/omega_engine/events.py +60 -0
  43. package/omega/Agentik_Engine/omega_engine/executor.py +167 -0
  44. package/omega/Agentik_Engine/omega_engine/mission.py +145 -0
  45. package/omega/Agentik_Engine/omega_engine/progress.py +75 -0
  46. package/omega/Agentik_Engine/omega_engine/project.py +92 -0
  47. package/omega/Agentik_Engine/omega_engine/provider.py +139 -0
  48. package/omega/Agentik_Engine/omega_engine/reducer.py +76 -0
  49. package/omega/Agentik_Engine/omega_engine/report.py +146 -0
  50. package/omega/Agentik_Engine/omega_engine/router.py +34 -0
  51. package/omega/Agentik_Engine/omega_engine/store.py +97 -0
  52. package/omega/Agentik_Engine/omega_engine/supervisor.py +69 -0
  53. package/omega/Agentik_Engine/omega_engine/task.py +91 -0
  54. package/omega/Agentik_Engine/omega_engine/telegram.py +115 -0
  55. package/omega/Agentik_Engine/pyproject.toml +31 -0
  56. package/omega/Agentik_Engine/tests/__pycache__/test_audit_arsenal.cpython-313.pyc +0 -0
  57. package/omega/Agentik_Engine/tests/__pycache__/test_executor.cpython-313.pyc +0 -0
  58. package/omega/Agentik_Engine/tests/__pycache__/test_mission.cpython-313.pyc +0 -0
  59. package/omega/Agentik_Engine/tests/__pycache__/test_progress.cpython-313.pyc +0 -0
  60. package/omega/Agentik_Engine/tests/__pycache__/test_project.cpython-313.pyc +0 -0
  61. package/omega/Agentik_Engine/tests/__pycache__/test_reducer.cpython-313.pyc +0 -0
  62. package/omega/Agentik_Engine/tests/__pycache__/test_report.cpython-313.pyc +0 -0
  63. package/omega/Agentik_Engine/tests/test_audit_arsenal.py +80 -0
  64. package/omega/Agentik_Engine/tests/test_executor.py +96 -0
  65. package/omega/Agentik_Engine/tests/test_mission.py +64 -0
  66. package/omega/Agentik_Engine/tests/test_progress.py +69 -0
  67. package/omega/Agentik_Engine/tests/test_project.py +61 -0
  68. package/omega/Agentik_Engine/tests/test_reducer.py +144 -0
  69. package/omega/Agentik_Engine/tests/test_report.py +88 -0
  70. package/omega/Agentik_Extra/README.md +37 -0
  71. package/omega/Agentik_Extra/etc/agentik.env.example +19 -0
  72. package/omega/Agentik_Extra/etc/structure.yaml +46 -0
  73. package/omega/Agentik_Orchestration/README.md +43 -0
  74. package/omega/Agentik_Orchestration/autonomous/README.md +29 -0
  75. package/omega/Agentik_Orchestration/autonomous/example-agents.yaml +85 -0
  76. package/omega/Agentik_Orchestration/educators/README.md +55 -0
  77. package/omega/Agentik_Orchestration/topologies/aisb-oracle-worker.yaml +42 -0
  78. package/omega/Agentik_Orchestration/verifier/audit-router.yaml +26 -0
  79. package/omega/Agentik_Providers/README.md +62 -0
  80. package/omega/Agentik_Providers/claude/accounts.example.yaml +28 -0
  81. package/omega/Agentik_Providers/registry.yaml +30 -0
  82. package/omega/Agentik_Runtime/README.md +30 -0
  83. package/omega/Agentik_SSOT/README.md +36 -0
  84. package/omega/Agentik_SSOT/VERSION +1 -0
  85. package/omega/Agentik_SSOT/audits/a11yaudit.yaml +69 -0
  86. package/omega/Agentik_SSOT/audits/apiaudit.yaml +71 -0
  87. package/omega/Agentik_SSOT/audits/automationaudit.yaml +77 -0
  88. package/omega/Agentik_SSOT/audits/codeaudit.yaml +63 -0
  89. package/omega/Agentik_SSOT/audits/copyaudit.yaml +68 -0
  90. package/omega/Agentik_SSOT/audits/dataaudit.yaml +76 -0
  91. package/omega/Agentik_SSOT/audits/debugaudit.yaml +75 -0
  92. package/omega/Agentik_SSOT/audits/dxaudit.yaml +78 -0
  93. package/omega/Agentik_SSOT/audits/featureaudit.yaml +73 -0
  94. package/omega/Agentik_SSOT/audits/flowaudit.yaml +72 -0
  95. package/omega/Agentik_SSOT/audits/logicaudit.yaml +75 -0
  96. package/omega/Agentik_SSOT/audits/motionaudit.yaml +67 -0
  97. package/omega/Agentik_SSOT/audits/perfaudit.yaml +71 -0
  98. package/omega/Agentik_SSOT/audits/refontaudit.yaml +77 -0
  99. package/omega/Agentik_SSOT/audits/retentionaudit.yaml +84 -0
  100. package/omega/Agentik_SSOT/audits/secaudit.yaml +73 -0
  101. package/omega/Agentik_SSOT/audits/seoaudit.yaml +75 -0
  102. package/omega/Agentik_SSOT/audits/uiuxaudit.yaml +61 -0
  103. package/omega/Agentik_SSOT/mcp/mcp-catalog.yaml +136 -0
  104. package/omega/Agentik_SSOT/rules/constitution.md +44 -0
  105. package/omega/Agentik_SSOT/schemas/event.schema.json +45 -0
  106. package/omega/Agentik_SSOT/schemas/task.schema.json +54 -0
  107. package/omega/Agentik_Tools/README.md +42 -0
  108. package/omega/Agentik_Tools/registry.json +15 -0
  109. package/package.json +43 -0
@@ -0,0 +1,80 @@
1
+ """The Quality Arsenal — forensic audits wired into the OmegaOS verification gate.
2
+
3
+ Standalone: python3 tests/test_audit_arsenal.py
4
+ """
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
9
+
10
+ from omega_engine.audit_arsenal import ( # noqa: E402
11
+ ArsenalGate,
12
+ AuditRegistry,
13
+ run_forensic_audit,
14
+ )
15
+ from omega_engine.provider import MockProvider # noqa: E402
16
+ from omega_engine.router import ModelRouter # noqa: E402
17
+
18
+ # the audit definitions live in the SSOT block of the repo
19
+ AUDITS_DIR = Path(__file__).resolve().parents[2] / "Agentik_SSOT" / "audits"
20
+
21
+
22
+ def test_registry_loads_audits():
23
+ reg = AuditRegistry.load(AUDITS_DIR)
24
+ assert len(reg.all()) >= 1, "no audits loaded from the SSOT"
25
+ code = reg.get("codeaudit")
26
+ assert code is not None and code.domain == "code"
27
+ assert len(code.phases) >= 5, "codeaudit has too few phases"
28
+ assert code.gather, "codeaudit declares no deterministic gather tools"
29
+ print(f" {len(reg.all())} audit(s) loaded from Agentik_SSOT/audits/")
30
+
31
+
32
+ def test_forensic_audit_runs_and_verdicts():
33
+ reg = AuditRegistry.load(AUDITS_DIR)
34
+ code = reg.get("codeaudit")
35
+ ctx = {"role": "worker", "changed": ["pricing.py"], "path": ".",
36
+ "artifacts": {"files": ["pricing.py"], "summary": "fixed pricing"}}
37
+ verdict = run_forensic_audit(code, ctx, MockProvider())
38
+ assert verdict.audit == "codeaudit"
39
+ assert verdict.verified, f"score={verdict.score}"
40
+ assert verdict.score >= 85
41
+ assert verdict.confidence in ("high", "medium", "low")
42
+
43
+
44
+ def test_arsenal_gate_selects_and_aggregates():
45
+ reg = AuditRegistry.load(AUDITS_DIR)
46
+ gate = ArsenalGate(reg, ModelRouter.single(MockProvider()))
47
+ ctx = {"role": "worker", "changed": ["pricing.py"], "path": ".",
48
+ "artifacts": {"files": ["pricing.py"], "summary": "done"},
49
+ "runtime_cmd": "true"}
50
+ verdict = gate.verify(ctx)
51
+ assert verdict.verified, f"gate rejected: score={verdict.score}"
52
+ assert gate.last_verdicts, "no forensic verdicts recorded for the report"
53
+ print(f" gate ran runtime + {len(gate.last_verdicts)} forensic audit(s)")
54
+
55
+
56
+ def test_gate_rejects_when_live_flow_fails():
57
+ # validate-live is non-negotiable: a broken flow can never be VERIFIED.
58
+ reg = AuditRegistry.load(AUDITS_DIR)
59
+ gate = ArsenalGate(reg, ModelRouter.single(MockProvider()))
60
+ ctx = {"role": "worker", "changed": ["x.py"], "path": ".",
61
+ "artifacts": {"files": ["x.py"]}, "runtime_cmd": "false"}
62
+ verdict = gate.verify(ctx)
63
+ assert not verdict.verified, "must reject when the live flow fails"
64
+ assert verdict.score == 0
65
+
66
+
67
+ def _run_all() -> bool:
68
+ tests = [v for k, v in sorted(globals().items())
69
+ if k.startswith("test_") and callable(v)]
70
+ passed = 0
71
+ for t in tests:
72
+ t()
73
+ print(f" PASS {t.__name__}")
74
+ passed += 1
75
+ print(f"\n{passed}/{len(tests)} arsenal tests passed")
76
+ return passed == len(tests)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,96 @@
1
+ """End-to-end: a real mission runs through the executor and reaches VERIFIED.
2
+
3
+ THE proof that OmegaOS orchestration works — verified completion, the join
4
+ barrier, and the audit gate (which really runs a subprocess) all exercised with
5
+ a deterministic MockProvider. Runs standalone: python3 tests/test_executor.py
6
+ """
7
+ import os
8
+ import sys
9
+ import tempfile
10
+ from pathlib import Path
11
+
12
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
13
+
14
+ from omega_engine.audit import AuditGate # noqa: E402
15
+ from omega_engine.bus import EventBus # noqa: E402
16
+ from omega_engine.executor import Executor # noqa: E402
17
+ from omega_engine.provider import MockProvider # noqa: E402
18
+ from omega_engine.reducer import reduce_task # noqa: E402
19
+ from omega_engine.router import ModelRouter # noqa: E402
20
+ from omega_engine.store import SQLiteStore # noqa: E402
21
+ from omega_engine.task import Kind, TaskState # noqa: E402
22
+
23
+
24
+ def _engine(plan_size: int = 2):
25
+ db = tempfile.mktemp(suffix=".db")
26
+ store = SQLiteStore(db)
27
+ bus = EventBus(store)
28
+ router = ModelRouter.single(MockProvider(plan_size=plan_size))
29
+ executor = Executor(store, bus, router, AuditGate())
30
+ return store, executor, db
31
+
32
+
33
+ def test_mission_runs_to_verified():
34
+ store, executor, db = _engine(plan_size=3)
35
+ result = executor.run_mission("fix the pricing bug")
36
+ assert result.verified, f"mission did not complete: {result.final_state}"
37
+ assert result.final_state is TaskState.COMPLETED
38
+ workers = [t for t in result.tasks.values() if t.kind is Kind.EXECUTOR]
39
+ assert len(workers) == 3, f"expected 3 workers, got {len(workers)}"
40
+ for w in workers:
41
+ assert reduce_task(store.events_for(w.id)) is TaskState.COMPLETED
42
+ store.close()
43
+ os.remove(db)
44
+
45
+
46
+ def test_every_emitted_sequence_is_fsm_legal():
47
+ # reduce_task raises IllegalTransition on a bad sequence. If this passes,
48
+ # every event the executor emitted is a legal FSM transition.
49
+ store, executor, db = _engine()
50
+ executor.run_mission("ship the feature")
51
+ for tid in store.task_ids():
52
+ reduce_task(store.events_for(tid)) # raises if illegal
53
+ store.close()
54
+ os.remove(db)
55
+
56
+
57
+ def test_worker_passes_through_the_audit_gate():
58
+ # completion is verified: a worker must go VERIFYING before VERIFIED.
59
+ store, executor, db = _engine(plan_size=1)
60
+ result = executor.run_mission("one task")
61
+ worker = next(t for t in result.tasks.values() if t.kind is Kind.EXECUTOR)
62
+ types = [e.type.value for e in store.events_for(worker.id)]
63
+ assert "task.verifying" in types
64
+ assert "task.verified" in types
65
+ assert types.index("task.verifying") < types.index("task.verified")
66
+ assert types[-1] == "task.completed"
67
+ store.close()
68
+ os.remove(db)
69
+
70
+
71
+ def test_root_completes_only_after_children():
72
+ # the join barrier: scope.joinable is emitted on the root, and only after
73
+ # every worker is already terminal.
74
+ store, executor, db = _engine(plan_size=2)
75
+ result = executor.run_mission("barrier check")
76
+ root_events = [e.type.value for e in store.events_for(result.root.id)]
77
+ assert "scope.joinable" in root_events
78
+ assert root_events.index("scope.joinable") < root_events.index("task.completed")
79
+ store.close()
80
+ os.remove(db)
81
+
82
+
83
+ def _run_all() -> bool:
84
+ tests = [v for k, v in sorted(globals().items())
85
+ if k.startswith("test_") and callable(v)]
86
+ passed = 0
87
+ for t in tests:
88
+ t()
89
+ print(f" PASS {t.__name__}")
90
+ passed += 1
91
+ print(f"\n{passed}/{len(tests)} executor tests passed")
92
+ return passed == len(tests)
93
+
94
+
95
+ if __name__ == "__main__":
96
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,64 @@
1
+ """Mission coordinator — run_mission end to end, always with a PDF report.
2
+
3
+ Standalone: python3 tests/test_mission.py
4
+ """
5
+ import os
6
+ import shutil
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
12
+
13
+ # force the deterministic provider even if ANTHROPIC_API_KEY is in the env
14
+ os.environ["OMEGA_PROVIDER"] = "mock"
15
+
16
+ from omega_engine.mission import run_mission # noqa: E402
17
+
18
+
19
+ def _pdfgen_bin() -> str | None:
20
+ env = os.environ.get("OMEGA_PDFGEN")
21
+ if env and Path(env).exists():
22
+ return env
23
+ fallback = Path.home() / ".claude" / "lib" / "pdfgen.sh"
24
+ return str(fallback) if fallback.exists() else None
25
+
26
+
27
+ def test_run_mission_end_to_end():
28
+ binary = _pdfgen_bin()
29
+ if binary:
30
+ os.environ["OMEGA_PDFGEN"] = binary
31
+ home = Path(tempfile.mkdtemp())
32
+ try:
33
+ outcome = run_mission("add a logout button", omega_home=home)
34
+ assert outcome.result.verified, (
35
+ f"mission failed: {outcome.result.final_state}")
36
+ assert outcome.progress_pct == 100, f"pct={outcome.progress_pct}"
37
+ if binary:
38
+ assert outcome.report_pdf is not None, "no report produced"
39
+ assert outcome.report_pdf.exists(), "report PDF missing on disk"
40
+ assert outcome.report_pdf.stat().st_size > 5000
41
+ print(f" mission verified + report: "
42
+ f"{outcome.report_pdf.stat().st_size // 1024} KB PDF")
43
+ else:
44
+ print(" mission verified (pdfgen not on host — report skipped)")
45
+ # the event log persisted under Agentik_Runtime
46
+ assert (home / "Agentik_Runtime" / "eventlog" / "omega.db").exists()
47
+ finally:
48
+ shutil.rmtree(home, ignore_errors=True)
49
+
50
+
51
+ def _run_all() -> bool:
52
+ tests = [v for k, v in sorted(globals().items())
53
+ if k.startswith("test_") and callable(v)]
54
+ passed = 0
55
+ for t in tests:
56
+ t()
57
+ print(f" PASS {t.__name__}")
58
+ passed += 1
59
+ print(f"\n{passed}/{len(tests)} mission tests passed")
60
+ return passed == len(tests)
61
+
62
+
63
+ if __name__ == "__main__":
64
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,69 @@
1
+ """Progress tracking — the bus subscriber turns events into a progress bar.
2
+
3
+ Standalone: python3 tests/test_progress.py
4
+ """
5
+ import os
6
+ import sys
7
+ import tempfile
8
+ from pathlib import Path
9
+
10
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
11
+
12
+ from omega_engine.audit import AuditGate # noqa: E402
13
+ from omega_engine.bus import EventBus # noqa: E402
14
+ from omega_engine.executor import Executor # noqa: E402
15
+ from omega_engine.progress import ProgressTracker # noqa: E402
16
+ from omega_engine.provider import MockProvider # noqa: E402
17
+ from omega_engine.router import ModelRouter # noqa: E402
18
+ from omega_engine.store import SQLiteStore # noqa: E402
19
+
20
+
21
+ def _run(plan_size=3):
22
+ db = tempfile.mktemp(suffix=".db")
23
+ store = SQLiteStore(db)
24
+ bus = EventBus(store)
25
+ tracker = ProgressTracker()
26
+ bus.subscribe(tracker.on_event) # <-- progress is a bus subscriber
27
+ executor = Executor(store, bus, ModelRouter.single(MockProvider(plan_size)),
28
+ AuditGate())
29
+ result = executor.run_mission("track me")
30
+ store.close()
31
+ os.remove(db)
32
+ return tracker, result
33
+
34
+
35
+ def test_progress_reaches_100():
36
+ tracker, result = _run(plan_size=3)
37
+ prog = tracker.progress(result.mission_id)
38
+ assert prog is not None, "no progress recorded"
39
+ # 1 oracle + 3 workers = 4 tasks, all verified
40
+ assert prog.total_tasks == 4, f"total={prog.total_tasks}"
41
+ assert prog.verified == 4, f"verified={prog.verified}"
42
+ assert prog.failed == 0
43
+ assert prog.pct == 100, f"pct={prog.pct}"
44
+
45
+
46
+ def test_progress_bar_renders():
47
+ tracker, result = _run(plan_size=2)
48
+ prog = tracker.progress(result.mission_id)
49
+ bar = prog.bar(width=20)
50
+ assert len(bar) == 20
51
+ block = prog.render(title="Mission")
52
+ assert "100%" in block
53
+ assert "Mission" in block
54
+
55
+
56
+ def _run_all() -> bool:
57
+ tests = [v for k, v in sorted(globals().items())
58
+ if k.startswith("test_") and callable(v)]
59
+ passed = 0
60
+ for t in tests:
61
+ t()
62
+ print(f" PASS {t.__name__}")
63
+ passed += 1
64
+ print(f"\n{passed}/{len(tests)} progress tests passed")
65
+ return passed == len(tests)
66
+
67
+
68
+ if __name__ == "__main__":
69
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,61 @@
1
+ """Project creation — structure + registry. Standalone: python3 tests/test_project.py"""
2
+ import shutil
3
+ import sys
4
+ import tempfile
5
+ from pathlib import Path
6
+
7
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
8
+
9
+ from omega_engine.project import create_project, load_projects, slugify # noqa: E402
10
+
11
+
12
+ def test_slugify():
13
+ assert slugify("My Cool Project!") == "my-cool-project"
14
+ assert slugify("Causio") == "causio"
15
+ assert slugify(" ") == "project"
16
+
17
+
18
+ def test_create_project_builds_structure():
19
+ home = Path(tempfile.mkdtemp())
20
+ try:
21
+ p = create_project("Pricing Tool", omega_home=home) # no Telegram
22
+ assert p.slug == "pricing-tool"
23
+ assert Path(p.path).is_dir()
24
+ assert (Path(p.path) / "README.md").exists()
25
+ assert p.topic_id is None # no Telegram bridge given
26
+ # registered
27
+ projects = load_projects(home)
28
+ assert len(projects) == 1
29
+ assert projects[0].slug == "pricing-tool"
30
+ finally:
31
+ shutil.rmtree(home, ignore_errors=True)
32
+
33
+
34
+ def test_duplicate_project_rejected():
35
+ home = Path(tempfile.mkdtemp())
36
+ try:
37
+ create_project("Dup", omega_home=home)
38
+ raised = False
39
+ try:
40
+ create_project("Dup", omega_home=home)
41
+ except ValueError:
42
+ raised = True
43
+ assert raised, "duplicate project must be rejected"
44
+ finally:
45
+ shutil.rmtree(home, ignore_errors=True)
46
+
47
+
48
+ def _run_all() -> bool:
49
+ tests = [v for k, v in sorted(globals().items())
50
+ if k.startswith("test_") and callable(v)]
51
+ passed = 0
52
+ for t in tests:
53
+ t()
54
+ print(f" PASS {t.__name__}")
55
+ passed += 1
56
+ print(f"\n{passed}/{len(tests)} project tests passed")
57
+ return passed == len(tests)
58
+
59
+
60
+ if __name__ == "__main__":
61
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,144 @@
1
+ """Tests for the reducer and the join barrier — the engine's anti-hallucination core.
2
+
3
+ Runs under pytest, or standalone: python3 tests/test_reducer.py
4
+ """
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ # allow `python3 tests/test_reducer.py` from anywhere
9
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
10
+
11
+ from omega_engine.barrier import ScopeStatus, scope_status # noqa: E402
12
+ from omega_engine.events import Event, EventType # noqa: E402
13
+ from omega_engine.reducer import IllegalTransition, reduce_task # noqa: E402
14
+ from omega_engine.task import TaskState # noqa: E402
15
+
16
+
17
+ def _ev(task_id: str, etype: EventType) -> Event:
18
+ return Event(task_id=task_id, type=etype)
19
+
20
+
21
+ def test_happy_path_to_completed():
22
+ events = [
23
+ _ev("t1", EventType.CREATED),
24
+ _ev("t1", EventType.DISPATCHED),
25
+ _ev("t1", EventType.STARTED),
26
+ _ev("t1", EventType.CLAIMED_DONE),
27
+ _ev("t1", EventType.VERIFYING),
28
+ _ev("t1", EventType.VERIFIED),
29
+ _ev("t1", EventType.COMPLETED),
30
+ ]
31
+ assert reduce_task(events) is TaskState.COMPLETED
32
+
33
+
34
+ def test_claimed_done_is_not_completion():
35
+ # THE crux test: a worker claiming done does NOT reach verified/terminal.
36
+ events = [
37
+ _ev("t1", EventType.CREATED),
38
+ _ev("t1", EventType.DISPATCHED),
39
+ _ev("t1", EventType.STARTED),
40
+ _ev("t1", EventType.CLAIMED_DONE),
41
+ ]
42
+ state = reduce_task(events)
43
+ assert state is TaskState.CLAIMED_DONE
44
+ assert state is not TaskState.VERIFIED
45
+ assert state is not TaskState.COMPLETED
46
+
47
+
48
+ def test_reject_then_retry_then_pass():
49
+ events = [
50
+ _ev("t1", EventType.CREATED),
51
+ _ev("t1", EventType.DISPATCHED),
52
+ _ev("t1", EventType.STARTED),
53
+ _ev("t1", EventType.CLAIMED_DONE),
54
+ _ev("t1", EventType.VERIFYING),
55
+ _ev("t1", EventType.REJECTED),
56
+ _ev("t1", EventType.DISPATCHED), # retry within budget
57
+ _ev("t1", EventType.STARTED),
58
+ _ev("t1", EventType.CLAIMED_DONE),
59
+ _ev("t1", EventType.VERIFYING),
60
+ _ev("t1", EventType.VERIFIED),
61
+ _ev("t1", EventType.COMPLETED),
62
+ ]
63
+ assert reduce_task(events) is TaskState.COMPLETED
64
+
65
+
66
+ def test_deadman_kills_a_live_task():
67
+ events = [
68
+ _ev("t1", EventType.CREATED),
69
+ _ev("t1", EventType.DISPATCHED),
70
+ _ev("t1", EventType.STARTED),
71
+ _ev("t1", EventType.FAILED), # deadman fires from RUNNING
72
+ ]
73
+ assert reduce_task(events) is TaskState.FAILED
74
+
75
+
76
+ def test_illegal_transition_raises():
77
+ # cannot START a task that was never DISPATCHED
78
+ events = [_ev("t1", EventType.CREATED), _ev("t1", EventType.STARTED)]
79
+ try:
80
+ reduce_task(events)
81
+ raised = False
82
+ except IllegalTransition:
83
+ raised = True
84
+ assert raised, "an illegal transition must raise, not corrupt"
85
+
86
+
87
+ def test_failed_on_terminal_is_illegal():
88
+ events = [
89
+ _ev("t1", EventType.CREATED),
90
+ _ev("t1", EventType.DISPATCHED),
91
+ _ev("t1", EventType.STARTED),
92
+ _ev("t1", EventType.CLAIMED_DONE),
93
+ _ev("t1", EventType.VERIFYING),
94
+ _ev("t1", EventType.VERIFIED),
95
+ _ev("t1", EventType.COMPLETED),
96
+ _ev("t1", EventType.FAILED), # cannot fail a COMPLETED task
97
+ ]
98
+ try:
99
+ reduce_task(events)
100
+ raised = False
101
+ except IllegalTransition:
102
+ raised = True
103
+ assert raised
104
+
105
+
106
+ def test_empty_stream_raises():
107
+ try:
108
+ reduce_task([])
109
+ raised = False
110
+ except IllegalTransition:
111
+ raised = True
112
+ assert raised
113
+
114
+
115
+ def test_barrier_running_until_all_terminal():
116
+ assert scope_status([TaskState.RUNNING, TaskState.COMPLETED]) is ScopeStatus.RUNNING
117
+
118
+
119
+ def test_barrier_joinable_when_all_completed():
120
+ assert scope_status([TaskState.COMPLETED, TaskState.COMPLETED]) is ScopeStatus.JOINABLE
121
+
122
+
123
+ def test_barrier_partial_when_a_child_failed():
124
+ assert scope_status([TaskState.COMPLETED, TaskState.FAILED]) is ScopeStatus.PARTIAL
125
+
126
+
127
+ def test_barrier_empty_scope_is_joinable():
128
+ assert scope_status([]) is ScopeStatus.JOINABLE
129
+
130
+
131
+ def _run_all() -> bool:
132
+ tests = [v for k, v in sorted(globals().items())
133
+ if k.startswith("test_") and callable(v)]
134
+ passed = 0
135
+ for t in tests:
136
+ t()
137
+ print(f" PASS {t.__name__}")
138
+ passed += 1
139
+ print(f"\n{passed}/{len(tests)} tests passed")
140
+ return passed == len(tests)
141
+
142
+
143
+ if __name__ == "__main__":
144
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,88 @@
1
+ """Mission report -> real PDF, end to end.
2
+
3
+ Runs a mission, builds the whitepaper report, renders it through the pdfgen
4
+ tool, and asserts a real PDF lands on disk. Standalone: python3 tests/test_report.py
5
+ """
6
+ import os
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
12
+
13
+ from omega_engine.audit import AuditGate # noqa: E402
14
+ from omega_engine.bus import EventBus # noqa: E402
15
+ from omega_engine.executor import Executor # noqa: E402
16
+ from omega_engine.provider import MockProvider # noqa: E402
17
+ from omega_engine.report import build_report, generate_mission_report # noqa: E402
18
+ from omega_engine.router import ModelRouter # noqa: E402
19
+ from omega_engine.store import SQLiteStore # noqa: E402
20
+
21
+
22
+ def _pdfgen_bin() -> str | None:
23
+ env = os.environ.get("OMEGA_PDFGEN")
24
+ if env and Path(env).exists():
25
+ return env
26
+ fallback = Path.home() / ".claude" / "lib" / "pdfgen.sh"
27
+ return str(fallback) if fallback.exists() else None
28
+
29
+
30
+ def _run_mission():
31
+ db = tempfile.mktemp(suffix=".db")
32
+ store = SQLiteStore(db)
33
+ bus = EventBus(store)
34
+ executor = Executor(store, bus, ModelRouter.single(MockProvider(plan_size=3)),
35
+ AuditGate())
36
+ result = executor.run_mission("fix the checkout flow")
37
+ return store, result, db
38
+
39
+
40
+ def test_build_report_shape():
41
+ """The report data matches the pdfgen whitepaper schema — no PDF needed."""
42
+ store, result, db = _run_mission()
43
+ data = build_report(result, store)
44
+ assert data["template"] == "whitepaper"
45
+ assert data["theme"] == "agentik"
46
+ assert data["abstract"] and data["title"]
47
+ assert len(data["sections"]) == 4
48
+ for s in data["sections"]:
49
+ assert s["index"] and s["title"] and s["body"]
50
+ store.close()
51
+ os.remove(db)
52
+ print(" report schema OK (4 sections, whitepaper/agentik)")
53
+
54
+
55
+ def test_render_real_pdf():
56
+ """Render the report through the real pdfgen tool — a genuine PDF on disk."""
57
+ binary = _pdfgen_bin()
58
+ if not binary:
59
+ print(" SKIP — pdfgen tool not found on this host")
60
+ return
61
+ store, result, db = _run_mission()
62
+ out_dir = tempfile.mkdtemp()
63
+ pdf = generate_mission_report(result, store, out_dir, pdfgen_bin=binary)
64
+ assert pdf.exists(), "no PDF produced"
65
+ size = pdf.stat().st_size
66
+ assert size > 5000, f"PDF suspiciously small: {size} bytes"
67
+ head = pdf.read_bytes()[:5]
68
+ assert head.startswith(b"%PDF"), "output is not a PDF"
69
+ print(f" real PDF rendered: {pdf} ({size // 1024} KB)")
70
+ pdf.unlink()
71
+ store.close()
72
+ os.remove(db)
73
+
74
+
75
+ def _run_all() -> bool:
76
+ tests = [v for k, v in sorted(globals().items())
77
+ if k.startswith("test_") and callable(v)]
78
+ passed = 0
79
+ for t in tests:
80
+ t()
81
+ print(f" PASS {t.__name__}")
82
+ passed += 1
83
+ print(f"\n{passed}/{len(tests)} report tests passed")
84
+ return passed == len(tests)
85
+
86
+
87
+ if __name__ == "__main__":
88
+ sys.exit(0 if _run_all() else 1)
@@ -0,0 +1,37 @@
1
+ # Agentik_Extra — ephemeral + config + secrets
2
+
3
+ > **Nature:** periphery · **Lifecycle:** disposable / sensitive · **Git:** not versioned
4
+
5
+ The eighth block absorbs everything that would otherwise clutter the master
6
+ folder, so `~/Omega/` stays at exactly eight clean entries.
7
+
8
+ ```
9
+ Agentik_Extra/
10
+ ├── var/
11
+ │ ├── cache/ XDG_CACHE_HOME points here
12
+ │ ├── tmp/ TMPDIR points here
13
+ │ ├── logs/ rotated automatically
14
+ │ └── .install-state the installer's resume marker
15
+ ├── staging/
16
+ │ └── promotion/ the educators' pipeline: staged → audited → promoted to SSOT
17
+ └── etc/
18
+ ├── agentik.env the environment that forces the tidy layout
19
+ ├── structure.yaml the arborescence manifest — checked hourly for drift
20
+ └── secrets/ the encrypted vault — API keys, tokens (chmod 700)
21
+ ```
22
+
23
+ ## Three regimes, one block
24
+
25
+ - **`var/`** — pure ephemeral. Safe to wipe at any time. All cache and temp files
26
+ point here, so nothing scatters across the home directory or `/tmp`.
27
+ - **`staging/`** — the educators' workspace. An educator writes a proposed change
28
+ to `promotion/`; the audit gate validates it; only then is it promoted into
29
+ `Agentik_SSOT/`. Never silent self-modification.
30
+ - **`etc/`** — configuration and secrets.
31
+
32
+ ## Secrets — a vault, not a folder
33
+
34
+ `etc/secrets/` is `chmod 700` and holds an **encrypted** vault (age/sops or the
35
+ OS keyring). The installer never writes a plaintext secret into the tree;
36
+ config files store a *reference* (`secret_ref: COMPOSIO_API_KEY`), resolved at
37
+ use time. `secrets/` is git-ignored without exception.
@@ -0,0 +1,19 @@
1
+ # Omega OS — environment.
2
+ # The installer copies this to agentik.env and sources it from the shell rc.
3
+ # These variables FORCE every tool to range its files inside the rack.
4
+
5
+ # --- the master folder ---
6
+ export OMEGA_HOME="$HOME/Omega"
7
+
8
+ # --- the only directory added to PATH (symlinks to installed tools) ---
9
+ export PATH="$OMEGA_HOME/Agentik_Tools/bin:$PATH"
10
+
11
+ # --- redirect all cache + temp into the Extra block ---
12
+ export XDG_CACHE_HOME="$OMEGA_HOME/Agentik_Extra/var/cache"
13
+ export TMPDIR="$OMEGA_HOME/Agentik_Extra/var/tmp"
14
+
15
+ # --- the runtime event log (the source of truth) ---
16
+ export OMEGA_EVENTLOG="$OMEGA_HOME/Agentik_Runtime/eventlog/omega.db"
17
+
18
+ # --- secrets are loaded from the encrypted vault, never set here ---
19
+ # export COMPOSIO_API_KEY=... # NO — use Agentik_Extra/etc/secrets/