@agentikos/omega-os 0.1.0 → 0.2.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.
- package/README.md +25 -13
- package/bootstrap/lib/steps.sh +214 -9
- package/bootstrap/manifest.example.yaml +6 -1
- package/docs/COMPLETION-PLAN.md +48 -0
- package/omega/Agentik_Engine/README.md +25 -10
- package/omega/Agentik_Engine/omega_engine/__init__.py +66 -2
- package/omega/Agentik_Engine/omega_engine/account.py +505 -0
- package/omega/Agentik_Engine/omega_engine/autonomous.py +538 -0
- package/omega/Agentik_Engine/omega_engine/cli.py +467 -29
- package/omega/Agentik_Engine/omega_engine/daemons/__init__.py +14 -0
- package/omega/Agentik_Engine/omega_engine/daemons/autonomous.py +56 -0
- package/omega/Agentik_Engine/omega_engine/daemons/engine.py +187 -0
- package/omega/Agentik_Engine/omega_engine/daemons/telegram.py +231 -0
- package/omega/Agentik_Engine/omega_engine/educators/__init__.py +51 -0
- package/omega/Agentik_Engine/omega_engine/educators/artifact.py +65 -0
- package/omega/Agentik_Engine/omega_engine/educators/automation.py +76 -0
- package/omega/Agentik_Engine/omega_engine/educators/base.py +327 -0
- package/omega/Agentik_Engine/omega_engine/educators/claudecode.py +71 -0
- package/omega/Agentik_Engine/omega_engine/educators/connection.py +75 -0
- package/omega/Agentik_Engine/omega_engine/educators/coworker.py +68 -0
- package/omega/Agentik_Engine/omega_engine/educators/loop.py +82 -0
- package/omega/Agentik_Engine/omega_engine/educators/prompt.py +68 -0
- package/omega/Agentik_Engine/omega_engine/educators/skill.py +69 -0
- package/omega/Agentik_Engine/omega_engine/executor.py +46 -6
- package/omega/Agentik_Engine/omega_engine/mission.py +13 -1
- package/omega/Agentik_Engine/omega_engine/provider.py +247 -1
- package/omega/Agentik_Engine/omega_engine/rag/__init__.py +21 -0
- package/omega/Agentik_Engine/omega_engine/rag/agentic.py +83 -0
- package/omega/Agentik_Engine/omega_engine/rag/base.py +42 -0
- package/omega/Agentik_Engine/omega_engine/rag/corrective.py +119 -0
- package/omega/Agentik_Engine/omega_engine/rag/graph.py +169 -0
- package/omega/Agentik_Engine/omega_engine/rag/hybrid.py +205 -0
- package/omega/Agentik_Engine/omega_engine/rag/multimodal.py +136 -0
- package/omega/Agentik_Engine/omega_engine/rag/router.py +110 -0
- package/omega/Agentik_Engine/omega_engine/reducer.py +21 -3
- package/omega/Agentik_Engine/omega_engine/store.py +65 -5
- package/omega/Agentik_Engine/omega_engine/sync.py +304 -0
- package/omega/Agentik_Engine/omega_engine/tools.py +272 -0
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/test_account.py +333 -0
- package/omega/Agentik_Engine/tests/test_autonomous.py +361 -0
- package/omega/Agentik_Engine/tests/test_educators.py +233 -0
- package/omega/Agentik_Engine/tests/test_rag.py +287 -0
- package/omega/Agentik_Engine/tests/test_snapshot_partial.py +172 -0
- package/omega/Agentik_Engine/tests/test_tools_and_sync.py +312 -0
- package/omega/Agentik_SSOT/skills/rag-route.md +73 -0
- package/package.json +1 -1
- package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/audit.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/audit_arsenal.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/barrier.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/bus.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__/events.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/executor.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/mission.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/progress.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/project.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/provider.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/reducer.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/report.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/router.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/store.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/supervisor.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/task.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/telegram.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_audit_arsenal.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_executor.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_mission.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_progress.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_project.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_reducer.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_report.cpython-313.pyc +0 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""The educator framework — generators that produce SSOT artifacts under a gate.
|
|
2
|
+
|
|
3
|
+
Where the Quality Arsenal verifies code (`CLAIMED_DONE → VERIFIED`), the educators
|
|
4
|
+
generate the genome itself: prompts, templates, skills, roles, connectors,
|
|
5
|
+
automations, adapters, loops. They are the self-improving layer.
|
|
6
|
+
|
|
7
|
+
Three pieces, shared by every educator:
|
|
8
|
+
- `Artifact` — what gets produced (with where in the SSOT it lands)
|
|
9
|
+
- `EducatorProposal` — the artifact plus the educator's self-critique
|
|
10
|
+
- `Educator` Protocol — the contract: `generate(intent, context, provider)`
|
|
11
|
+
- `EducatorRegistry` — discovery of every concrete educator
|
|
12
|
+
- `StagingPipeline` — writes proposals to staging (NEVER to SSOT)
|
|
13
|
+
— promotion is a separate step under the audit gate.
|
|
14
|
+
|
|
15
|
+
The doctrine for generation mirrors the doctrine for audit, inverted: produce a
|
|
16
|
+
high-quality artifact (Gestalt clarity), then self-criticize it (Popper: where
|
|
17
|
+
does it lie?), then refine. The shared shell lives in `build_education_prompt`.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any, Protocol, runtime_checkable
|
|
25
|
+
|
|
26
|
+
from omega_engine.provider import AgentProvider, AgentRequest
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
# Structured types — what an educator produces, what staging consumes.
|
|
31
|
+
# --------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Artifact:
|
|
36
|
+
"""One generated artifact, with the target SSOT path it should land at."""
|
|
37
|
+
|
|
38
|
+
id: str
|
|
39
|
+
kind: str # "prompt" | "template" | "skill" | "agent" | ...
|
|
40
|
+
content: str
|
|
41
|
+
target_path: str # POSIX path inside Agentik_SSOT/... (or Agentik_AI/...)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class EducatorProposal:
|
|
46
|
+
"""An artifact plus the educator's self-critique — what staging reviews."""
|
|
47
|
+
|
|
48
|
+
educator: str
|
|
49
|
+
artifact: Artifact
|
|
50
|
+
score: int # 0-100 self-critique
|
|
51
|
+
summary: str = ""
|
|
52
|
+
fix_plan: list[dict[str, Any]] = field(default_factory=list)
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> dict[str, Any]:
|
|
55
|
+
return {
|
|
56
|
+
"educator": self.educator,
|
|
57
|
+
"score": self.score,
|
|
58
|
+
"summary": self.summary,
|
|
59
|
+
"fix_plan": self.fix_plan,
|
|
60
|
+
"artifact": {
|
|
61
|
+
"id": self.artifact.id,
|
|
62
|
+
"kind": self.artifact.kind,
|
|
63
|
+
"target_path": self.artifact.target_path,
|
|
64
|
+
"content": self.artifact.content,
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# --------------------------------------------------------------------------
|
|
70
|
+
# The contract — every educator implements this.
|
|
71
|
+
# --------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@runtime_checkable
|
|
75
|
+
class Educator(Protocol):
|
|
76
|
+
"""One educator: a focused generator for one domain of the SSOT."""
|
|
77
|
+
|
|
78
|
+
name: str
|
|
79
|
+
domain: str
|
|
80
|
+
|
|
81
|
+
def generate(
|
|
82
|
+
self,
|
|
83
|
+
intent: str,
|
|
84
|
+
context: dict[str, Any],
|
|
85
|
+
provider: AgentProvider,
|
|
86
|
+
) -> EducatorProposal: ...
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# --------------------------------------------------------------------------
|
|
90
|
+
# Shared generation doctrine + helpers — used by every concrete educator.
|
|
91
|
+
# --------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
_DOCTRINE = """\
|
|
94
|
+
You are a senior generator, not a friendly drafter. The artifact you produce
|
|
95
|
+
becomes part of the system's genome — the SSOT. Apply the Gestalt-Popper
|
|
96
|
+
doctrine to GENERATION:
|
|
97
|
+
- GESTALT: identify the hinge — the one element that, if vague or wrong, makes
|
|
98
|
+
the whole artifact useless. Make THAT element razor-sharp first.
|
|
99
|
+
- POPPER: produce a draft, then attack it. Where does it lie, hand-wave, or
|
|
100
|
+
promise more than it delivers? List the falsifiable claims and fix them.
|
|
101
|
+
- ADVERSARIAL: assume the next reader is a hostile worker who will misuse any
|
|
102
|
+
vagueness. Be specific, complete, and runnable. No prose for prose's sake.
|
|
103
|
+
Banned: "should", "could", "TBD", filler. Every line must earn its place.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def build_education_prompt(
|
|
108
|
+
educator_name: str,
|
|
109
|
+
domain: str,
|
|
110
|
+
intent: str,
|
|
111
|
+
target_kind: str,
|
|
112
|
+
target_path_hint: str,
|
|
113
|
+
domain_instructions: str,
|
|
114
|
+
context: dict[str, Any],
|
|
115
|
+
) -> str:
|
|
116
|
+
"""Compose the agentic generation prompt — shared shell + domain payload.
|
|
117
|
+
|
|
118
|
+
Each educator passes its own `domain_instructions` — the actual signature of
|
|
119
|
+
the educator. Everything else (doctrine, output contract) is shared.
|
|
120
|
+
"""
|
|
121
|
+
ctx_brief = json.dumps(context, indent=2, default=str)[:2500]
|
|
122
|
+
return (
|
|
123
|
+
f"{_DOCTRINE}\n"
|
|
124
|
+
f"EDUCATOR: {educator_name} — domain {domain}\n"
|
|
125
|
+
f"INTENT: {intent}\n"
|
|
126
|
+
f"TARGET ARTIFACT KIND: {target_kind}\n"
|
|
127
|
+
f"TARGET SSOT PATH HINT: {target_path_hint}\n\n"
|
|
128
|
+
f"DOMAIN INSTRUCTIONS — what THIS educator must produce:\n"
|
|
129
|
+
f"{domain_instructions}\n\n"
|
|
130
|
+
f"CONTEXT:\n{ctx_brief}\n\n"
|
|
131
|
+
f"Emit ONLY a JSON proposal: "
|
|
132
|
+
f"{{\"kind\": \"{target_kind}\", \"content\": \"<the full artifact>\", "
|
|
133
|
+
f"\"score\": 0-100, \"summary\": \"<one-line self-critique>\", "
|
|
134
|
+
f"\"fix_plan\": [{{\"id\",\"issue\",\"fix\"}}]}}. "
|
|
135
|
+
f"score >= 85 means the artifact is ready for staging."
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def parse_proposal(
|
|
140
|
+
educator_name: str,
|
|
141
|
+
artifact_id: str,
|
|
142
|
+
target_path: str,
|
|
143
|
+
target_kind: str,
|
|
144
|
+
raw: dict[str, Any],
|
|
145
|
+
) -> EducatorProposal:
|
|
146
|
+
"""Build an `EducatorProposal` from a raw provider response dict."""
|
|
147
|
+
return EducatorProposal(
|
|
148
|
+
educator=educator_name,
|
|
149
|
+
artifact=Artifact(
|
|
150
|
+
id=artifact_id,
|
|
151
|
+
kind=raw.get("kind", target_kind),
|
|
152
|
+
content=raw.get("content", ""),
|
|
153
|
+
target_path=target_path,
|
|
154
|
+
),
|
|
155
|
+
score=int(raw.get("score", 0)),
|
|
156
|
+
summary=raw.get("summary", ""),
|
|
157
|
+
fix_plan=list(raw.get("fix_plan", [])),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def run_education(
|
|
162
|
+
educator_name: str,
|
|
163
|
+
domain: str,
|
|
164
|
+
intent: str,
|
|
165
|
+
target_kind: str,
|
|
166
|
+
target_path: str,
|
|
167
|
+
domain_instructions: str,
|
|
168
|
+
context: dict[str, Any],
|
|
169
|
+
provider: AgentProvider,
|
|
170
|
+
artifact_id: str | None = None,
|
|
171
|
+
) -> EducatorProposal:
|
|
172
|
+
"""The shared run loop: build prompt, call provider, parse proposal.
|
|
173
|
+
|
|
174
|
+
Every concrete educator reduces to one call to this. The provider role is
|
|
175
|
+
``educator-<name>`` so the router can wire a different LLM to each educator
|
|
176
|
+
(a cheap model for templates, Claude for prompts, etc.).
|
|
177
|
+
"""
|
|
178
|
+
prompt = build_education_prompt(
|
|
179
|
+
educator_name=educator_name,
|
|
180
|
+
domain=domain,
|
|
181
|
+
intent=intent,
|
|
182
|
+
target_kind=target_kind,
|
|
183
|
+
target_path_hint=target_path,
|
|
184
|
+
domain_instructions=domain_instructions,
|
|
185
|
+
context={**context, "intent": intent, "kind": target_kind},
|
|
186
|
+
)
|
|
187
|
+
result = provider.run(AgentRequest(
|
|
188
|
+
role=f"educator-{educator_name}",
|
|
189
|
+
prompt=prompt,
|
|
190
|
+
context={**context, "intent": intent, "kind": target_kind},
|
|
191
|
+
))
|
|
192
|
+
raw = result.artifacts.get("proposal")
|
|
193
|
+
if raw is None:
|
|
194
|
+
try:
|
|
195
|
+
raw = json.loads(result.text)
|
|
196
|
+
except (json.JSONDecodeError, TypeError):
|
|
197
|
+
raw = {
|
|
198
|
+
"kind": target_kind,
|
|
199
|
+
"content": result.text or "",
|
|
200
|
+
"score": 0,
|
|
201
|
+
"summary": "educator produced no parseable proposal",
|
|
202
|
+
"fix_plan": [],
|
|
203
|
+
}
|
|
204
|
+
aid = artifact_id or f"{educator_name}-{abs(hash(intent)) % 10_000_000:07d}"
|
|
205
|
+
return parse_proposal(educator_name, aid, target_path, target_kind, raw)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# --------------------------------------------------------------------------
|
|
209
|
+
# Registry — discovery of every concrete educator.
|
|
210
|
+
# --------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class EducatorRegistry:
|
|
214
|
+
"""Holds every concrete educator. `get(name)` and `all()` are the API."""
|
|
215
|
+
|
|
216
|
+
def __init__(self, educators: dict[str, Educator]) -> None:
|
|
217
|
+
self._educators = dict(educators)
|
|
218
|
+
|
|
219
|
+
def register(self, educator: Educator) -> None:
|
|
220
|
+
self._educators[educator.name] = educator
|
|
221
|
+
|
|
222
|
+
def get(self, name: str) -> Educator | None:
|
|
223
|
+
return self._educators.get(name)
|
|
224
|
+
|
|
225
|
+
def all(self) -> list[Educator]:
|
|
226
|
+
return list(self._educators.values())
|
|
227
|
+
|
|
228
|
+
def names(self) -> list[str]:
|
|
229
|
+
return sorted(self._educators.keys())
|
|
230
|
+
|
|
231
|
+
@classmethod
|
|
232
|
+
def default(cls) -> "EducatorRegistry":
|
|
233
|
+
"""The 8-educator default registry — imports the concrete classes."""
|
|
234
|
+
# local imports avoid a base ↔ concrete-modules import cycle
|
|
235
|
+
from omega_engine.educators.artifact import ArtifactEducator
|
|
236
|
+
from omega_engine.educators.automation import AutomationEducator
|
|
237
|
+
from omega_engine.educators.claudecode import ClaudecodeEducator
|
|
238
|
+
from omega_engine.educators.connection import ConnectionEducator
|
|
239
|
+
from omega_engine.educators.coworker import CoworkerEducator
|
|
240
|
+
from omega_engine.educators.loop import LoopEducator
|
|
241
|
+
from omega_engine.educators.prompt import PromptEducator
|
|
242
|
+
from omega_engine.educators.skill import SkillEducator
|
|
243
|
+
|
|
244
|
+
return cls({
|
|
245
|
+
e.name: e for e in (
|
|
246
|
+
PromptEducator(),
|
|
247
|
+
ArtifactEducator(),
|
|
248
|
+
SkillEducator(),
|
|
249
|
+
CoworkerEducator(),
|
|
250
|
+
ConnectionEducator(),
|
|
251
|
+
AutomationEducator(),
|
|
252
|
+
ClaudecodeEducator(),
|
|
253
|
+
LoopEducator(),
|
|
254
|
+
)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# --------------------------------------------------------------------------
|
|
259
|
+
# Staging — proposals go to staging, NEVER to the SSOT.
|
|
260
|
+
# --------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@dataclass
|
|
264
|
+
class StagingRecord:
|
|
265
|
+
"""The on-disk handle for a proposal in staging."""
|
|
266
|
+
|
|
267
|
+
proposal_path: Path # the .json metadata
|
|
268
|
+
artifact_path: Path # the actual generated content
|
|
269
|
+
target_path: str # POSIX path inside the SSOT it would promote to
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class StagingPipeline:
|
|
273
|
+
"""Writes proposals to ``Agentik_Extra/staging/promotion/``.
|
|
274
|
+
|
|
275
|
+
An educator never writes to the SSOT directly. Promotion from staging into
|
|
276
|
+
the SSOT is a separate step gated by the audit arsenal + (optionally) a
|
|
277
|
+
human approval. The pipeline guarantees:
|
|
278
|
+
|
|
279
|
+
- artifacts land under one directory keyed by educator + id
|
|
280
|
+
- the original target_path is preserved as metadata
|
|
281
|
+
- the staging area is reversible (delete = no trace)
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
def __init__(self, staging_root: Path | str) -> None:
|
|
285
|
+
self._root = Path(staging_root)
|
|
286
|
+
self._root.mkdir(parents=True, exist_ok=True)
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def root(self) -> Path:
|
|
290
|
+
return self._root
|
|
291
|
+
|
|
292
|
+
def stage(self, proposal: EducatorProposal) -> StagingRecord:
|
|
293
|
+
"""Write the proposal to staging. Returns the on-disk record.
|
|
294
|
+
|
|
295
|
+
The promotion gate (separate) reads the staging record, runs the audit
|
|
296
|
+
arsenal on the artifact, and either copies the artifact to its
|
|
297
|
+
``target_path`` inside the SSOT or rejects it with logged findings.
|
|
298
|
+
"""
|
|
299
|
+
bucket = self._root / proposal.educator
|
|
300
|
+
bucket.mkdir(parents=True, exist_ok=True)
|
|
301
|
+
# extension from the target path so e.g. .yaml stays .yaml in staging
|
|
302
|
+
suffix = Path(proposal.artifact.target_path).suffix or ".txt"
|
|
303
|
+
artifact_path = bucket / f"{proposal.artifact.id}{suffix}"
|
|
304
|
+
proposal_path = bucket / f"{proposal.artifact.id}.json"
|
|
305
|
+
artifact_path.write_text(proposal.artifact.content)
|
|
306
|
+
proposal_path.write_text(json.dumps(proposal.to_dict(), indent=2))
|
|
307
|
+
return StagingRecord(
|
|
308
|
+
proposal_path=proposal_path,
|
|
309
|
+
artifact_path=artifact_path,
|
|
310
|
+
target_path=proposal.artifact.target_path,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def list(self) -> list[Path]:
|
|
314
|
+
"""All staged proposal metadata files (one per pending change)."""
|
|
315
|
+
return sorted(self._root.glob("*/*.json"))
|
|
316
|
+
|
|
317
|
+
def clear(self, educator: str | None = None) -> int:
|
|
318
|
+
"""Delete every staged file (or every file for one educator). Returns count."""
|
|
319
|
+
target = self._root / educator if educator else self._root
|
|
320
|
+
if not target.exists():
|
|
321
|
+
return 0
|
|
322
|
+
removed = 0
|
|
323
|
+
for path in target.rglob("*"):
|
|
324
|
+
if path.is_file():
|
|
325
|
+
path.unlink()
|
|
326
|
+
removed += 1
|
|
327
|
+
return removed
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""`claudecode-educator` — tracks Claude Code changelog patterns + updates SSOT.
|
|
2
|
+
|
|
3
|
+
The signature: Claude Code (the platform) keeps shipping new primitives —
|
|
4
|
+
``/goal``, native compaction, agent tools, prompt caching. Each time, the SSOT
|
|
5
|
+
+ the claude-code adapter must catch up. This educator reads recent-change
|
|
6
|
+
notes and proposes the adapter/SSOT updates that absorb the new primitive.
|
|
7
|
+
|
|
8
|
+
Target SSOT path: ``Agentik_AI/adapters/claude-code/notes.md`` (the canonical
|
|
9
|
+
log of what we know + what we still owe).
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from omega_engine.educators.base import EducatorProposal, run_education
|
|
16
|
+
from omega_engine.provider import AgentProvider
|
|
17
|
+
|
|
18
|
+
_INSTRUCTIONS = """\
|
|
19
|
+
Produce ONE proposal for an update to the claude-code adapter notes. The
|
|
20
|
+
proposal MUST identify exactly ONE Claude Code change and how OmegaOS absorbs
|
|
21
|
+
it. The artifact MUST contain these sections, in order:
|
|
22
|
+
|
|
23
|
+
1. The change — name the new primitive (e.g. "native /goal auto-loop"),
|
|
24
|
+
when it shipped, and link the changelog entry. ONE line each.
|
|
25
|
+
2. The implication for OmegaOS — what does this primitive replace, augment,
|
|
26
|
+
or invalidate in our orchestration? Specifically:
|
|
27
|
+
- which SSOT rule(s) change
|
|
28
|
+
- which adapter(s) change
|
|
29
|
+
- which skill(s) become redundant or need to chain into the new primitive
|
|
30
|
+
3. The proposed adapter change — code-level diff intent (file + region +
|
|
31
|
+
change in one paragraph each). Do NOT write the code, write the contract.
|
|
32
|
+
4. The proposed SSOT change — list every file under Agentik_SSOT/ that the
|
|
33
|
+
promotion gate will edit + the one-line summary of each edit.
|
|
34
|
+
5. The migration plan — three numbered steps for: pilot, generalise,
|
|
35
|
+
deprecate-old-path. Each step has a verify command.
|
|
36
|
+
6. Risk — one paragraph: what could go wrong, how we detect it.
|
|
37
|
+
|
|
38
|
+
The proposal MUST NOT:
|
|
39
|
+
- claim certainty about a primitive without citing the changelog.
|
|
40
|
+
- propose a change without naming the rollback path.
|
|
41
|
+
- bundle multiple primitives — one change per proposal.
|
|
42
|
+
|
|
43
|
+
Format the artifact as Markdown.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ClaudecodeEducator:
|
|
48
|
+
"""Watches the Claude Code changelog + proposes adapter/SSOT updates."""
|
|
49
|
+
|
|
50
|
+
name = "claudecode"
|
|
51
|
+
domain = "claude-code-adapter"
|
|
52
|
+
|
|
53
|
+
def generate(
|
|
54
|
+
self,
|
|
55
|
+
intent: str,
|
|
56
|
+
context: dict[str, Any],
|
|
57
|
+
provider: AgentProvider,
|
|
58
|
+
) -> EducatorProposal:
|
|
59
|
+
change_id = str(context.get("change_id", "latest"))
|
|
60
|
+
target_path = "Agentik_AI/adapters/claude-code/notes.md"
|
|
61
|
+
return run_education(
|
|
62
|
+
educator_name=self.name,
|
|
63
|
+
domain=self.domain,
|
|
64
|
+
intent=intent,
|
|
65
|
+
target_kind="adapter-update",
|
|
66
|
+
target_path=target_path,
|
|
67
|
+
domain_instructions=_INSTRUCTIONS,
|
|
68
|
+
context={**context, "change_id": change_id},
|
|
69
|
+
provider=provider,
|
|
70
|
+
artifact_id=f"cc-{change_id}",
|
|
71
|
+
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""`connection-educator` — generates MCP / API connector configs.
|
|
2
|
+
|
|
3
|
+
The signature: a connector config is the canonical declaration of an external
|
|
4
|
+
capability — an MCP server, an API client, a provider endpoint. The SSOT holds
|
|
5
|
+
the truth; each provider adapter projects it into its own format.
|
|
6
|
+
|
|
7
|
+
Target SSOT path: ``Agentik_SSOT/mcp/configs/<id>.yaml``.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from omega_engine.educators.base import EducatorProposal, run_education
|
|
14
|
+
from omega_engine.provider import AgentProvider
|
|
15
|
+
|
|
16
|
+
_INSTRUCTIONS = """\
|
|
17
|
+
Produce ONE connector config in YAML. The config MUST contain these fields,
|
|
18
|
+
in this order, with no extras (the schema is strict — adapters fail closed):
|
|
19
|
+
|
|
20
|
+
id: <stable identifier, lowercase, kebab-case>
|
|
21
|
+
kind: mcp | api | provider
|
|
22
|
+
description: <one line>
|
|
23
|
+
transport:
|
|
24
|
+
type: stdio | http | sse
|
|
25
|
+
command: <executable, only when transport=stdio>
|
|
26
|
+
url: <endpoint, only when transport in (http, sse)>
|
|
27
|
+
auth:
|
|
28
|
+
type: none | env | header | oauth
|
|
29
|
+
env_var: <NAME, only when type=env>
|
|
30
|
+
header_name: <Name, only when type=header>
|
|
31
|
+
capabilities:
|
|
32
|
+
- <verb-noun phrase describing one tool the connector exposes>
|
|
33
|
+
permissions:
|
|
34
|
+
read: [ <glob | "*"> ]
|
|
35
|
+
write: [ <glob | "*"> ]
|
|
36
|
+
rate_limit:
|
|
37
|
+
rps: <int, default 10>
|
|
38
|
+
burst: <int, default 20>
|
|
39
|
+
health_check:
|
|
40
|
+
command: <shell, returns 0 when healthy>
|
|
41
|
+
|
|
42
|
+
The config MUST NOT:
|
|
43
|
+
- embed secrets — only env_var names. Secrets live in Agentik_Extra/etc/secrets/.
|
|
44
|
+
- leave `permissions` open ("*" is allowed but must be a conscious choice).
|
|
45
|
+
- declare a transport without the matching field (stdio without command, etc.).
|
|
46
|
+
|
|
47
|
+
Format the artifact as valid YAML — no comments, no trailing whitespace.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ConnectionEducator:
|
|
52
|
+
"""Generates MCP / API connector configs for the SSOT."""
|
|
53
|
+
|
|
54
|
+
name = "connection"
|
|
55
|
+
domain = "connectors"
|
|
56
|
+
|
|
57
|
+
def generate(
|
|
58
|
+
self,
|
|
59
|
+
intent: str,
|
|
60
|
+
context: dict[str, Any],
|
|
61
|
+
provider: AgentProvider,
|
|
62
|
+
) -> EducatorProposal:
|
|
63
|
+
connector_id = str(context.get("connector_id", "new-connector"))
|
|
64
|
+
target_path = f"Agentik_SSOT/mcp/configs/{connector_id}.yaml"
|
|
65
|
+
return run_education(
|
|
66
|
+
educator_name=self.name,
|
|
67
|
+
domain=self.domain,
|
|
68
|
+
intent=intent,
|
|
69
|
+
target_kind="connector",
|
|
70
|
+
target_path=target_path,
|
|
71
|
+
domain_instructions=_INSTRUCTIONS,
|
|
72
|
+
context={**context, "connector_id": connector_id},
|
|
73
|
+
provider=provider,
|
|
74
|
+
artifact_id=connector_id,
|
|
75
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""`coworker-educator` — generates worker/agent role definitions.
|
|
2
|
+
|
|
3
|
+
The signature: a role definition is what the engine uses to instantiate a
|
|
4
|
+
worker — its mandate, its tool set, its boundaries, the audits its work is
|
|
5
|
+
gated by. Roles are what makes the orchestration graph readable: "send this to
|
|
6
|
+
a `react-specialist`" only works if `react-specialist` is a defined SSOT role.
|
|
7
|
+
|
|
8
|
+
Target SSOT path: ``Agentik_SSOT/agents/<role>.md``.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from omega_engine.educators.base import EducatorProposal, run_education
|
|
15
|
+
from omega_engine.provider import AgentProvider
|
|
16
|
+
|
|
17
|
+
_INSTRUCTIONS = """\
|
|
18
|
+
Produce ONE worker/agent role definition. The role MUST declare, in order:
|
|
19
|
+
|
|
20
|
+
1. Role name + one-line mandate ("A <role> does X to deliver Y.").
|
|
21
|
+
2. Scope — what kinds of tasks this role accepts AND a hard list of what it
|
|
22
|
+
refuses (with a one-line reason for each refusal).
|
|
23
|
+
3. Tools — the exact engine tools / MCP servers / skills this role uses
|
|
24
|
+
(file edits, browser, build, deploy). One tool per line, with the
|
|
25
|
+
condition under which it is invoked.
|
|
26
|
+
4. Files it may touch — glob patterns. Roles enforce file ownership; the
|
|
27
|
+
engine rejects writes outside this set.
|
|
28
|
+
5. Audits gating its output — list the audit IDs (codeaudit, secaudit, ...)
|
|
29
|
+
that run on its work. Minimum score per audit.
|
|
30
|
+
6. Done criteria — the measurable condition the role uses to claim done.
|
|
31
|
+
MUST be a runnable command or a precise structural check, never a feeling.
|
|
32
|
+
7. Escalation — when the role gives up (budget exceeded, repeated failure)
|
|
33
|
+
and to whom it escalates.
|
|
34
|
+
|
|
35
|
+
The role MUST NOT:
|
|
36
|
+
- overlap silently with another role — state the boundary if it is close.
|
|
37
|
+
- leave the tool list open-ended ("any tool needed" is a refusal-worthy bug).
|
|
38
|
+
- use vague mandates like "help with X".
|
|
39
|
+
|
|
40
|
+
Format the artifact as Markdown.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CoworkerEducator:
|
|
45
|
+
"""Generates worker/agent role definitions for the SSOT roster."""
|
|
46
|
+
|
|
47
|
+
name = "coworker"
|
|
48
|
+
domain = "agent-roles"
|
|
49
|
+
|
|
50
|
+
def generate(
|
|
51
|
+
self,
|
|
52
|
+
intent: str,
|
|
53
|
+
context: dict[str, Any],
|
|
54
|
+
provider: AgentProvider,
|
|
55
|
+
) -> EducatorProposal:
|
|
56
|
+
role = str(context.get("role_name", "worker"))
|
|
57
|
+
target_path = f"Agentik_SSOT/agents/{role}.md"
|
|
58
|
+
return run_education(
|
|
59
|
+
educator_name=self.name,
|
|
60
|
+
domain=self.domain,
|
|
61
|
+
intent=intent,
|
|
62
|
+
target_kind="agent",
|
|
63
|
+
target_path=target_path,
|
|
64
|
+
domain_instructions=_INSTRUCTIONS,
|
|
65
|
+
context={**context, "role_name": role},
|
|
66
|
+
provider=provider,
|
|
67
|
+
artifact_id=role,
|
|
68
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""`loop-educator` — defines and tunes the goal-loop / verification patterns.
|
|
2
|
+
|
|
3
|
+
The signature: a loop spec tells the executor HOW MANY iterations a given task
|
|
4
|
+
type gets, WHICH audits run between iterations, and the EXIT condition. It is
|
|
5
|
+
how the engine decides "keep going" vs "this is hopeless, abort". Tuning the
|
|
6
|
+
loop is the most direct lever on cost and quality.
|
|
7
|
+
|
|
8
|
+
Target SSOT path: ``Agentik_SSOT/loops/<name>.yaml`` (or a patch to
|
|
9
|
+
``Agentik_SSOT/audits/<auditid>.yaml`` when the change is to an audit's
|
|
10
|
+
threshold/weight).
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from omega_engine.educators.base import EducatorProposal, run_education
|
|
17
|
+
from omega_engine.provider import AgentProvider
|
|
18
|
+
|
|
19
|
+
_INSTRUCTIONS = """\
|
|
20
|
+
Produce ONE loop spec in YAML. The spec MUST contain these fields:
|
|
21
|
+
|
|
22
|
+
id: <stable identifier, lowercase, kebab-case>
|
|
23
|
+
applies_to:
|
|
24
|
+
task_kinds: [ executor | verifier | dispatcher | "*" ]
|
|
25
|
+
intent_match: <regex against the mission intent | "*">
|
|
26
|
+
iteration:
|
|
27
|
+
max: <int> # hard cap, never exceeded
|
|
28
|
+
soft_target: <int> # where we expect convergence
|
|
29
|
+
cost_cap_usd: <number | null>
|
|
30
|
+
exit_condition:
|
|
31
|
+
type: score | command | both
|
|
32
|
+
score:
|
|
33
|
+
audit: <audit id from the Quality Arsenal>
|
|
34
|
+
threshold: <int 0-100>
|
|
35
|
+
command:
|
|
36
|
+
cmd: <shell, exit 0 = converged>
|
|
37
|
+
timeout_sec: <int>
|
|
38
|
+
step: # what runs each iteration
|
|
39
|
+
audits: [ <audit id>, ... ]
|
|
40
|
+
fix_action: dispatch | direct_edit | skip
|
|
41
|
+
on_no_progress: # detect plateaus
|
|
42
|
+
same_findings_iterations: <int> # if this many in a row repeat -> abort
|
|
43
|
+
action: abort | switch_strategy
|
|
44
|
+
observability:
|
|
45
|
+
log_each_iteration: true | false
|
|
46
|
+
emit: [ loop.iteration, loop.converged, loop.aborted ]
|
|
47
|
+
|
|
48
|
+
The loop MUST NOT:
|
|
49
|
+
- set `max` higher than 12 unless `cost_cap_usd` is set (runaway prevention).
|
|
50
|
+
- declare exit_condition.type=score without a valid audit id.
|
|
51
|
+
- allow `same_findings_iterations` >= max (that defeats plateau detection).
|
|
52
|
+
- skip `on_no_progress` — every loop must know when to give up.
|
|
53
|
+
|
|
54
|
+
Format the artifact as valid YAML — strict.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LoopEducator:
|
|
59
|
+
"""Defines and tunes goal-loop / verification patterns for the executor."""
|
|
60
|
+
|
|
61
|
+
name = "loop"
|
|
62
|
+
domain = "loops"
|
|
63
|
+
|
|
64
|
+
def generate(
|
|
65
|
+
self,
|
|
66
|
+
intent: str,
|
|
67
|
+
context: dict[str, Any],
|
|
68
|
+
provider: AgentProvider,
|
|
69
|
+
) -> EducatorProposal:
|
|
70
|
+
loop_id = str(context.get("loop_id", "default-loop"))
|
|
71
|
+
target_path = f"Agentik_SSOT/loops/{loop_id}.yaml"
|
|
72
|
+
return run_education(
|
|
73
|
+
educator_name=self.name,
|
|
74
|
+
domain=self.domain,
|
|
75
|
+
intent=intent,
|
|
76
|
+
target_kind="loop",
|
|
77
|
+
target_path=target_path,
|
|
78
|
+
domain_instructions=_INSTRUCTIONS,
|
|
79
|
+
context={**context, "loop_id": loop_id},
|
|
80
|
+
provider=provider,
|
|
81
|
+
artifact_id=loop_id,
|
|
82
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""`prompt-educator` — generates the prompts passed between levels.
|
|
2
|
+
|
|
3
|
+
The signature: produces a prompt template for ONE source → target hand-off
|
|
4
|
+
(AISB → Oracle, Oracle → Manager, Manager → Worker, ...). The template must
|
|
5
|
+
embed the orchestration contract: mission, context, files in scope, done
|
|
6
|
+
criteria, verify command. It is the canonical prompt the engine injects into
|
|
7
|
+
provider calls at that level.
|
|
8
|
+
|
|
9
|
+
Target SSOT path: ``Agentik_SSOT/prompts/<source>-to-<target>.md``.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from omega_engine.educators.base import EducatorProposal, run_education
|
|
16
|
+
from omega_engine.provider import AgentProvider
|
|
17
|
+
|
|
18
|
+
_INSTRUCTIONS = """\
|
|
19
|
+
Produce ONE prompt template the engine will inject at the
|
|
20
|
+
<source-role> -> <target-role> hand-off. The template MUST:
|
|
21
|
+
|
|
22
|
+
1. State the role of the target agent in ONE sentence ("You are <target>.").
|
|
23
|
+
2. Include the mission summary (one paragraph, no padding).
|
|
24
|
+
3. Embed the orchestration contract — these MUST appear, exactly:
|
|
25
|
+
- Mission / Purpose / Context (project, stack, dev URL)
|
|
26
|
+
- Files in Scope (ownership boundaries)
|
|
27
|
+
- Done Criteria (a measurable condition, e.g. "exit 0", "0 console errors")
|
|
28
|
+
- Verify Command (the exact command the target runs before reporting done)
|
|
29
|
+
4. State the legal stop signal (e.g. ".done.json with status=done_clean").
|
|
30
|
+
5. End with the response format the engine will parse.
|
|
31
|
+
|
|
32
|
+
Anti-patterns the artifact MUST NOT contain:
|
|
33
|
+
- "should", "could", "maybe", "TBD"
|
|
34
|
+
- vague verbs ("handle", "ensure" without a verb saying HOW)
|
|
35
|
+
- escape hatches that let the target pause and ask the user
|
|
36
|
+
(we are autonomous — Third Law)
|
|
37
|
+
|
|
38
|
+
Format the artifact as Markdown with placeholders in ALL_CAPS_SNAKE_CASE
|
|
39
|
+
(MISSION_SUMMARY, PROJECT_DIR, FILES_IN_SCOPE, etc.) so the engine can fill them.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PromptEducator:
|
|
44
|
+
"""Generates inter-level prompts for the orchestration graph."""
|
|
45
|
+
|
|
46
|
+
name = "prompt"
|
|
47
|
+
domain = "orchestration-prompts"
|
|
48
|
+
|
|
49
|
+
def generate(
|
|
50
|
+
self,
|
|
51
|
+
intent: str,
|
|
52
|
+
context: dict[str, Any],
|
|
53
|
+
provider: AgentProvider,
|
|
54
|
+
) -> EducatorProposal:
|
|
55
|
+
source = str(context.get("source", "oracle"))
|
|
56
|
+
target = str(context.get("target", "worker"))
|
|
57
|
+
target_path = f"Agentik_SSOT/prompts/{source}-to-{target}.md"
|
|
58
|
+
return run_education(
|
|
59
|
+
educator_name=self.name,
|
|
60
|
+
domain=self.domain,
|
|
61
|
+
intent=intent,
|
|
62
|
+
target_kind="prompt",
|
|
63
|
+
target_path=target_path,
|
|
64
|
+
domain_instructions=_INSTRUCTIONS,
|
|
65
|
+
context={**context, "source": source, "target": target},
|
|
66
|
+
provider=provider,
|
|
67
|
+
artifact_id=f"{source}-to-{target}",
|
|
68
|
+
)
|