@agentikos/omega-os 0.19.12 → 0.19.14
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/bootstrap/lib/steps.sh +80 -18
- 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__/aisb_chat.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/hermes.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/aisb_chat.py +43 -0
- package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/telegram.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/daemons/telegram.py +27 -14
- package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/stack.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/genesis/stack.py +30 -0
- package/omega/Agentik_Engine/omega_engine/hermes.py +34 -8
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_hermes_and_ua.py +56 -8
- package/omega/Agentik_Engine/tests/test_telegram_history.py +63 -15
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/LAYERS.md +130 -73
- package/omega/Agentik_SSOT/docs/references/README.md +17 -0
- package/omega/Agentik_SSOT/skills/desktop-architecture/SKILL.md +61 -0
- package/package.json +1 -1
package/bootstrap/lib/steps.sh
CHANGED
|
@@ -865,37 +865,55 @@ _claude_plugins_prompt_checklist() {
|
|
|
865
865
|
|
|
866
866
|
# --- 50 -----------------------------------------------------------------------
|
|
867
867
|
step_telegram() {
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
868
|
+
# Two distinct bots in the corrected v0.19.14 model:
|
|
869
|
+
# * AISB bot (token A) — REQUIRED. Runs missions on Max OAuth.
|
|
870
|
+
# * Hermès bot (token H) — OPTIONAL. Meta-companion on Anthropic API.
|
|
871
|
+
# And one optional API key (ANTHROPIC_API_KEY_HERMES) gating Hermès AI.
|
|
872
|
+
# Old `TELEGRAM_TOKEN` is treated as the AISB token (back-compat).
|
|
873
|
+
local aisb_token hermes_token anthropic_key chat_id
|
|
874
|
+
|
|
875
|
+
# 1. AISB bot — required.
|
|
876
|
+
info "AISB bot — required. Talks to OmegaOS on Claude Max OAuth."
|
|
877
|
+
ask aisb_token "AISB Telegram bot token (from @BotFather)" "${TELEGRAM_TOKEN_AISB:-${TELEGRAM_TOKEN:-}}"
|
|
878
|
+
if [ -z "$aisb_token" ]; then
|
|
879
|
+
err "an AISB bot token is required (or install with --profile minimal)"
|
|
872
880
|
return 1
|
|
873
881
|
fi
|
|
874
882
|
if have curl; then
|
|
875
|
-
if ! curl -s "https://api.telegram.org/bot${
|
|
876
|
-
err "Telegram token rejected by the API"
|
|
883
|
+
if ! curl -s "https://api.telegram.org/bot${aisb_token}/getMe" | grep -q '"ok":true'; then
|
|
884
|
+
err "AISB Telegram token rejected by the API"
|
|
877
885
|
return 1
|
|
878
886
|
fi
|
|
879
887
|
fi
|
|
888
|
+
|
|
880
889
|
local sec="$OMEGA_HOME/Agentik_Extra/etc/secrets"
|
|
881
890
|
mkdir -p "$sec"
|
|
882
|
-
|
|
891
|
+
# Write a single .env file consumed by both daemons; vault still holds
|
|
892
|
+
# the canonical encrypted copy.
|
|
893
|
+
{
|
|
894
|
+
echo "# Generated by OmegaOS install — do not edit by hand."
|
|
895
|
+
echo "# AISB bot (OmegaOS-native, Claude Max OAuth)"
|
|
896
|
+
printf 'TELEGRAM_TOKEN_AISB=%s\n' "$aisb_token"
|
|
897
|
+
printf 'TELEGRAM_TOKEN=%s\n' "$aisb_token" # back-compat alias
|
|
898
|
+
} > "$sec/telegram.env"
|
|
883
899
|
chmod 600 "$sec/telegram.env"
|
|
884
|
-
|
|
885
|
-
python3 - "$OMEGA_HOME" "$token" <<'PY' || true
|
|
900
|
+
python3 - "$OMEGA_HOME" "$aisb_token" <<'PY' || true
|
|
886
901
|
import sys
|
|
887
902
|
from pathlib import Path
|
|
888
903
|
home = Path(sys.argv[1])
|
|
889
904
|
sys.path.insert(0, str(home / "Agentik_Engine"))
|
|
890
905
|
try:
|
|
891
906
|
from omega_engine.vault import vault_write
|
|
907
|
+
# Write under BOTH names so old code paths reading TELEGRAM_TOKEN keep
|
|
908
|
+
# working without a separate migration step.
|
|
909
|
+
vault_write(home, "TELEGRAM_TOKEN_AISB", sys.argv[2])
|
|
892
910
|
vault_write(home, "TELEGRAM_TOKEN", sys.argv[2])
|
|
893
911
|
except Exception as exc:
|
|
894
912
|
print(f"(vault write skipped: {exc})")
|
|
895
913
|
PY
|
|
896
|
-
ok "Telegram bot validated and wired"
|
|
914
|
+
ok "AISB Telegram bot validated and wired"
|
|
897
915
|
|
|
898
|
-
#
|
|
916
|
+
# 2. AISB group chat id — same as before (scopes missions to a group).
|
|
899
917
|
chat_id="$(python3 - "$MANIFEST" <<'PY' 2>/dev/null || true
|
|
900
918
|
import sys, yaml
|
|
901
919
|
try:
|
|
@@ -906,14 +924,11 @@ except Exception:
|
|
|
906
924
|
print('')
|
|
907
925
|
PY
|
|
908
926
|
)"
|
|
909
|
-
chat_id="$
|
|
927
|
+
chat_id="$(printf '%s' "$chat_id" | tr -d '\n ')"
|
|
910
928
|
if [ -z "$chat_id" ]; then
|
|
911
|
-
ask chat_id "
|
|
929
|
+
ask chat_id "AISB forum group chat id (e.g. -1001234567890; blank to set later)" ""
|
|
912
930
|
fi
|
|
913
931
|
if [ -n "$chat_id" ]; then
|
|
914
|
-
python3 "$OMEGA_REPO/bootstrap/lib/manifest-helpers.py" telegram-chat-id \
|
|
915
|
-
"$MANIFEST" "$OMEGA_HOME" 2>/dev/null | sed 's/^/ /' || true
|
|
916
|
-
# When chat_id came from the prompt (not the manifest), persist directly.
|
|
917
932
|
python3 - "$OMEGA_HOME" "$chat_id" <<'PY' || true
|
|
918
933
|
import sys
|
|
919
934
|
from pathlib import Path
|
|
@@ -922,12 +937,59 @@ sys.path.insert(0, str(home / "Agentik_Engine"))
|
|
|
922
937
|
try:
|
|
923
938
|
from omega_engine.vault import vault_write
|
|
924
939
|
vault_write(home, "TELEGRAM_GROUP_ID", sys.argv[2])
|
|
925
|
-
print(f"
|
|
940
|
+
print(f"AISB group chat_id stored: {sys.argv[2]}")
|
|
926
941
|
except Exception as exc:
|
|
927
942
|
print(f"(vault write skipped: {exc})")
|
|
928
943
|
PY
|
|
929
944
|
else
|
|
930
|
-
info "no
|
|
945
|
+
info "no AISB group_chat_id captured — set later with \`omega telegram set-group <id>\`"
|
|
946
|
+
fi
|
|
947
|
+
|
|
948
|
+
# 3. Hermès bot — OPTIONAL. Skip cleanly if the operator just hits Enter.
|
|
949
|
+
echo
|
|
950
|
+
info "Hermès bot — OPTIONAL. Meta-companion on Anthropic API (you pay per call)."
|
|
951
|
+
info " Skip both prompts if you don't want Hermès yet — OmegaOS works fully without it."
|
|
952
|
+
ask hermes_token "Hermès Telegram bot token (blank = skip Hermès)" "${TELEGRAM_TOKEN_HERMES:-}"
|
|
953
|
+
if [ -n "$hermes_token" ]; then
|
|
954
|
+
if have curl; then
|
|
955
|
+
if ! curl -s "https://api.telegram.org/bot${hermes_token}/getMe" | grep -q '"ok":true'; then
|
|
956
|
+
err "Hermès Telegram token rejected by the API — continuing without Hermès"
|
|
957
|
+
hermes_token=""
|
|
958
|
+
fi
|
|
959
|
+
fi
|
|
960
|
+
fi
|
|
961
|
+
if [ -n "$hermes_token" ]; then
|
|
962
|
+
ask anthropic_key "Anthropic API key for Hermès (sk-ant-...; blank = set later)" \
|
|
963
|
+
"${ANTHROPIC_API_KEY_HERMES:-${ANTHROPIC_API_KEY:-}}"
|
|
964
|
+
{
|
|
965
|
+
echo "# Hermès bot (Layer 2 meta-companion, Anthropic API)"
|
|
966
|
+
printf 'TELEGRAM_TOKEN_HERMES=%s\n' "$hermes_token"
|
|
967
|
+
} >> "$sec/telegram.env"
|
|
968
|
+
if [ -n "$anthropic_key" ]; then
|
|
969
|
+
printf 'ANTHROPIC_API_KEY_HERMES=%s\n' "$anthropic_key" >> "$sec/telegram.env"
|
|
970
|
+
fi
|
|
971
|
+
chmod 600 "$sec/telegram.env"
|
|
972
|
+
python3 - "$OMEGA_HOME" "$hermes_token" "$anthropic_key" <<'PY' || true
|
|
973
|
+
import sys
|
|
974
|
+
from pathlib import Path
|
|
975
|
+
home = Path(sys.argv[1])
|
|
976
|
+
sys.path.insert(0, str(home / "Agentik_Engine"))
|
|
977
|
+
try:
|
|
978
|
+
from omega_engine.vault import vault_write
|
|
979
|
+
vault_write(home, "TELEGRAM_TOKEN_HERMES", sys.argv[2])
|
|
980
|
+
if sys.argv[3]:
|
|
981
|
+
vault_write(home, "ANTHROPIC_API_KEY_HERMES", sys.argv[3])
|
|
982
|
+
except Exception as exc:
|
|
983
|
+
print(f"(vault write skipped: {exc})")
|
|
984
|
+
PY
|
|
985
|
+
if [ -n "$anthropic_key" ]; then
|
|
986
|
+
ok "Hermès Telegram bot + Anthropic key wired"
|
|
987
|
+
else
|
|
988
|
+
info "Hermès Telegram bot wired (no Anthropic key yet — set with"
|
|
989
|
+
info " omega vault write ANTHROPIC_API_KEY_HERMES <sk-ant-...>)"
|
|
990
|
+
fi
|
|
991
|
+
else
|
|
992
|
+
info "Hermès skipped — wire later with \`omega telegram setup-hermes\`"
|
|
931
993
|
fi
|
|
932
994
|
return 0
|
|
933
995
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -60,6 +60,49 @@ def _clear_history(home: Path) -> int:
|
|
|
60
60
|
conn.close()
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def chat_once(home: Path, text: str, *,
|
|
64
|
+
topic_id: int = None,
|
|
65
|
+
record_history: bool = True) -> str:
|
|
66
|
+
"""Run ONE conversation turn against the AISB envelope and return the
|
|
67
|
+
reply. Stateless from the caller's POV — history is persisted via
|
|
68
|
+
``telegram_history`` keyed on ``topic_id`` (a single global default
|
|
69
|
+
for the tmux REPL; chat_id for Telegram DMs to keep per-user threads).
|
|
70
|
+
|
|
71
|
+
Extracted so the Telegram DM path can talk to the same agent the
|
|
72
|
+
tmux REPL talks to, without duplicating env+envelope+provider plumbing.
|
|
73
|
+
"""
|
|
74
|
+
import time
|
|
75
|
+
from omega_engine.envelope import EnvelopeContext, build_envelope
|
|
76
|
+
from omega_engine.provider import AgentRequest
|
|
77
|
+
from omega_engine.router import ModelRouter
|
|
78
|
+
from omega_engine.telegram_history import (
|
|
79
|
+
build_context_prompt, record_inbound, record_outbound,
|
|
80
|
+
)
|
|
81
|
+
if topic_id is None:
|
|
82
|
+
topic_id = CHAT_TOPIC
|
|
83
|
+
if record_history:
|
|
84
|
+
record_inbound(home, topic_id=topic_id, text=text)
|
|
85
|
+
enriched = build_context_prompt(
|
|
86
|
+
home, topic_id=topic_id, new_intent=text, limit=10,
|
|
87
|
+
)
|
|
88
|
+
ctx = EnvelopeContext(
|
|
89
|
+
role="aisb",
|
|
90
|
+
intent=enriched,
|
|
91
|
+
task_id=f"chat-{int(time.time())}",
|
|
92
|
+
)
|
|
93
|
+
env = build_envelope(home, ctx)
|
|
94
|
+
router = ModelRouter.auto()
|
|
95
|
+
provider = router.resolve("aisb")
|
|
96
|
+
result = provider.run(AgentRequest(
|
|
97
|
+
role="aisb", prompt=env["user"], context={},
|
|
98
|
+
system=env["system"],
|
|
99
|
+
))
|
|
100
|
+
reply = (result.text or "").strip() or "(empty reply)"
|
|
101
|
+
if record_history:
|
|
102
|
+
record_outbound(home, topic_id=topic_id, text=reply)
|
|
103
|
+
return reply
|
|
104
|
+
|
|
105
|
+
|
|
63
106
|
def run_chat_loop() -> int:
|
|
64
107
|
"""Block until /quit. Returns 0 on clean exit."""
|
|
65
108
|
home = _omega_home()
|
|
Binary file
|
|
@@ -153,33 +153,46 @@ def _route_one(
|
|
|
153
153
|
"""
|
|
154
154
|
from omega_engine import telegram_history
|
|
155
155
|
|
|
156
|
-
# DM (no topic) —
|
|
157
|
-
#
|
|
158
|
-
#
|
|
156
|
+
# DM (no topic) — route to the AISB conversational agent (same one
|
|
157
|
+
# the tmux REPL talks to). This used to refuse with "Missions only
|
|
158
|
+
# run from a project topic" which broke the most basic UX (a fresh
|
|
159
|
+
# install has no group topic yet, so the bot was effectively dead).
|
|
160
|
+
#
|
|
161
|
+
# Per-chat conversation history is namespaced by chat_id (encoded
|
|
162
|
+
# as a negative topic_id to avoid collisions with real Telegram
|
|
163
|
+
# forum topics, which are always positive small integers).
|
|
159
164
|
if topic_id is None:
|
|
160
|
-
|
|
161
|
-
# bot's eventual reply (handled elsewhere) are linked.
|
|
165
|
+
dm_topic = -abs(int(chat_id)) if chat_id is not None else 0
|
|
162
166
|
telegram_history.record_inbound(
|
|
163
|
-
home, topic_id=
|
|
167
|
+
home, topic_id=dm_topic, text=text, message_id=message_id,
|
|
164
168
|
)
|
|
165
169
|
logger.info(
|
|
166
|
-
"telegram in: DM (chat=%s) text=%r —
|
|
167
|
-
"mission from the DM; ask in a project topic instead",
|
|
170
|
+
"telegram in: DM (chat=%s) text=%r — routing to AISB chat",
|
|
168
171
|
chat_id, text[:80],
|
|
169
172
|
)
|
|
173
|
+
try:
|
|
174
|
+
from omega_engine.aisb_chat import chat_once
|
|
175
|
+
reply = chat_once(home, text, topic_id=dm_topic,
|
|
176
|
+
record_history=False)
|
|
177
|
+
except Exception as exc: # noqa: BLE001
|
|
178
|
+
logger.warning("telegram DM: chat_once failed",
|
|
179
|
+
exc_info=True)
|
|
180
|
+
reply = (
|
|
181
|
+
f"I hit an error talking to the AISB agent: {exc}\n"
|
|
182
|
+
"Check `omega doctor` for provider/account status."
|
|
183
|
+
)
|
|
184
|
+
telegram_history.record_outbound(
|
|
185
|
+
home, topic_id=dm_topic, text=reply,
|
|
186
|
+
)
|
|
170
187
|
if telegram_bridge is not None and chat_id is not None:
|
|
171
188
|
try:
|
|
172
189
|
telegram_bridge._call("sendMessage", { # noqa: SLF001
|
|
173
190
|
"chat_id": str(chat_id),
|
|
174
|
-
"text":
|
|
175
|
-
"Missions only run from a project topic in the "
|
|
176
|
-
"OmegaOS group — not the DM. Open the topic for "
|
|
177
|
-
"the project and re-send your request there."
|
|
178
|
-
),
|
|
191
|
+
"text": reply[:3900],
|
|
179
192
|
})
|
|
180
193
|
except Exception: # noqa: BLE001
|
|
181
194
|
logger.warning("telegram daemon: DM reply failed", exc_info=True)
|
|
182
|
-
return "dm:
|
|
195
|
+
return "dm:aisb-chat"
|
|
183
196
|
|
|
184
197
|
# Topic message — record + route.
|
|
185
198
|
telegram_history.record_inbound(
|
|
Binary file
|
|
@@ -176,6 +176,35 @@ def _backend_supabase_stack() -> Stack:
|
|
|
176
176
|
)
|
|
177
177
|
|
|
178
178
|
|
|
179
|
+
def _claude_dashboard_stack() -> Stack:
|
|
180
|
+
"""The Claude Code-grade premium dashboard stack.
|
|
181
|
+
|
|
182
|
+
Picks up the architecture contract from
|
|
183
|
+
``Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md``
|
|
184
|
+
during PRD + branding + design-system phases. Worker prompts include
|
|
185
|
+
the `/desktop-architecture` skill so every generated component traces
|
|
186
|
+
back to the same reference doc.
|
|
187
|
+
"""
|
|
188
|
+
return Stack(
|
|
189
|
+
id="claude-dashboard",
|
|
190
|
+
title="Claude-grade premium dashboard (Next.js + Convex + shadcn + Motion + references doc)",
|
|
191
|
+
config=StackConfig(
|
|
192
|
+
type="web",
|
|
193
|
+
frontend="nextjs",
|
|
194
|
+
backend="convex",
|
|
195
|
+
deploy="vercel",
|
|
196
|
+
payments="stripe",
|
|
197
|
+
ui_kit="shadcn",
|
|
198
|
+
auth="clerk",
|
|
199
|
+
extras=["desktop-architecture-reference"],
|
|
200
|
+
),
|
|
201
|
+
why="When the operator wants the Claude / Linear / Vercel / Stripe / "
|
|
202
|
+
"Elevenlabs dashboard look. Genesis phases pull from "
|
|
203
|
+
"Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md "
|
|
204
|
+
"as the single source of design truth.",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
179
208
|
CANONICAL_STACKS: dict[str, Stack] = {
|
|
180
209
|
s.id: s for s in (
|
|
181
210
|
default_stack(),
|
|
@@ -183,6 +212,7 @@ CANONICAL_STACKS: dict[str, Stack] = {
|
|
|
183
212
|
_mobile_cross_stack(),
|
|
184
213
|
_desktop_tauri_stack(),
|
|
185
214
|
_backend_supabase_stack(),
|
|
215
|
+
_claude_dashboard_stack(),
|
|
186
216
|
)
|
|
187
217
|
}
|
|
188
218
|
|
|
@@ -248,19 +248,45 @@ def build_env(
|
|
|
248
248
|
*,
|
|
249
249
|
extra: dict[str, str] | None = None,
|
|
250
250
|
creds_path: str | Path | None = None,
|
|
251
|
+
omega_home: str | Path | None = None,
|
|
251
252
|
) -> dict[str, str]:
|
|
252
253
|
"""Build the env dict for every Hermes invocation.
|
|
253
254
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
v0.19.14 — Hermès now defaults to its OWN Anthropic API key (budget
|
|
256
|
+
isolation from the OmegaOS Claude Max OAuth):
|
|
257
|
+
|
|
258
|
+
1. ``ANTHROPIC_API_KEY_HERMES`` from the encrypted vault → primary.
|
|
259
|
+
2. ``ANTHROPIC_API_KEY`` already in the shell env → fallback.
|
|
260
|
+
3. ``CLAUDE_CODE_OAUTH_TOKEN`` from ``~/.claude/.credentials.json``
|
|
261
|
+
→ LAST RESORT only, with a clear warning that this routes Hermès
|
|
262
|
+
calls through your Max sub.
|
|
263
|
+
|
|
264
|
+
Caller env wins via ``extra``.
|
|
257
265
|
"""
|
|
258
|
-
token = claude_oauth_token(creds_path)
|
|
259
266
|
env = {**os.environ}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
267
|
+
# 1. Vault first.
|
|
268
|
+
key = ""
|
|
269
|
+
try:
|
|
270
|
+
from omega_engine.vault import vault_read
|
|
271
|
+
from pathlib import Path as _P
|
|
272
|
+
home = _P(omega_home) if omega_home else _P(
|
|
273
|
+
os.environ.get("OMEGA_HOME", str(_P.home() / "Omega"))
|
|
274
|
+
)
|
|
275
|
+
key = (vault_read(home, "ANTHROPIC_API_KEY_HERMES") or "").strip()
|
|
276
|
+
except Exception: # noqa: BLE001
|
|
277
|
+
key = ""
|
|
278
|
+
# 2. Shell env fallback.
|
|
279
|
+
if not key:
|
|
280
|
+
key = (os.environ.get("ANTHROPIC_API_KEY") or "").strip()
|
|
281
|
+
# 3. Last-resort OAuth (preserves the old behaviour without making
|
|
282
|
+
# Hermès depend on it).
|
|
283
|
+
if not key:
|
|
284
|
+
try:
|
|
285
|
+
env["CLAUDE_CODE_OAUTH_TOKEN"] = claude_oauth_token(creds_path)
|
|
286
|
+
except Exception: # noqa: BLE001
|
|
287
|
+
pass
|
|
288
|
+
if key:
|
|
289
|
+
env["ANTHROPIC_API_KEY"] = key
|
|
264
290
|
env.setdefault("HERMES_PROVIDER", "anthropic")
|
|
265
291
|
env.setdefault("HERMES_MODEL", "claude-opus-4-7")
|
|
266
292
|
if extra:
|
package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313-pytest-8.4.2.pyc
CHANGED
|
Binary file
|
|
Binary file
|
package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -95,13 +95,43 @@ class TestClaudeOAuthRead(unittest.TestCase):
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
class TestBuildEnv(unittest.TestCase):
|
|
98
|
-
|
|
98
|
+
"""v0.19.14 — Hermès prefers ANTHROPIC_API_KEY_HERMES from the vault,
|
|
99
|
+
falls back to ANTHROPIC_API_KEY env, then last-resort to the Max
|
|
100
|
+
OAuth at ``~/.claude/.credentials.json``."""
|
|
101
|
+
|
|
102
|
+
def test_env_uses_anthropic_key_env_when_set(self):
|
|
103
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
104
|
+
p = _fake_creds(Path(tmp) / "c.json", token="tk-Z")
|
|
105
|
+
old = os.environ.get("ANTHROPIC_API_KEY")
|
|
106
|
+
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-test"
|
|
107
|
+
os.environ.pop("OMEGA_HOME", None)
|
|
108
|
+
try:
|
|
109
|
+
env = H.build_env(creds_path=p)
|
|
110
|
+
self.assertEqual(env.get("ANTHROPIC_API_KEY"), "sk-ant-test",
|
|
111
|
+
"Hermès must prefer ANTHROPIC_API_KEY over OAuth")
|
|
112
|
+
# OAuth NOT exposed when an Anthropic key is available.
|
|
113
|
+
self.assertNotIn("CLAUDE_CODE_OAUTH_TOKEN", env)
|
|
114
|
+
finally:
|
|
115
|
+
if old is None:
|
|
116
|
+
os.environ.pop("ANTHROPIC_API_KEY", None)
|
|
117
|
+
else:
|
|
118
|
+
os.environ["ANTHROPIC_API_KEY"] = old
|
|
119
|
+
|
|
120
|
+
def test_env_falls_back_to_oauth_when_no_anthropic_key(self):
|
|
99
121
|
with tempfile.TemporaryDirectory() as tmp:
|
|
100
122
|
p = _fake_creds(Path(tmp) / "c.json", token="tk-Z")
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
123
|
+
old = os.environ.get("ANTHROPIC_API_KEY")
|
|
124
|
+
os.environ.pop("ANTHROPIC_API_KEY", None)
|
|
125
|
+
os.environ["OMEGA_HOME"] = tmp # no vault key here
|
|
126
|
+
try:
|
|
127
|
+
env = H.build_env(creds_path=p)
|
|
128
|
+
self.assertEqual(env.get("CLAUDE_CODE_OAUTH_TOKEN"), "tk-Z")
|
|
129
|
+
self.assertEqual(env["HERMES_PROVIDER"], "anthropic")
|
|
130
|
+
self.assertEqual(env["HERMES_MODEL"], "claude-opus-4-7")
|
|
131
|
+
finally:
|
|
132
|
+
os.environ.pop("OMEGA_HOME", None)
|
|
133
|
+
if old is not None:
|
|
134
|
+
os.environ["ANTHROPIC_API_KEY"] = old
|
|
105
135
|
|
|
106
136
|
def test_env_extra_overrides_default(self):
|
|
107
137
|
with tempfile.TemporaryDirectory() as tmp:
|
|
@@ -110,9 +140,27 @@ class TestBuildEnv(unittest.TestCase):
|
|
|
110
140
|
extra={"HERMES_MODEL": "claude-sonnet-4-7"})
|
|
111
141
|
self.assertEqual(env["HERMES_MODEL"], "claude-sonnet-4-7")
|
|
112
142
|
|
|
113
|
-
def
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
def test_env_no_creds_no_anthropic_returns_env_without_token(self):
|
|
144
|
+
"""When neither an Anthropic key nor Claude OAuth is available,
|
|
145
|
+
build_env returns a usable env WITHOUT either token. The caller
|
|
146
|
+
(or Hermès itself) decides whether to error or skip; build_env
|
|
147
|
+
no longer raises — that was the v0.18 strict behaviour."""
|
|
148
|
+
old_anth = os.environ.get("ANTHROPIC_API_KEY")
|
|
149
|
+
old_home = os.environ.get("OMEGA_HOME")
|
|
150
|
+
os.environ.pop("ANTHROPIC_API_KEY", None)
|
|
151
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
152
|
+
os.environ["OMEGA_HOME"] = tmp
|
|
153
|
+
try:
|
|
154
|
+
env = H.build_env(creds_path=Path("/no/such/file"))
|
|
155
|
+
self.assertNotIn("ANTHROPIC_API_KEY", env)
|
|
156
|
+
self.assertNotIn("CLAUDE_CODE_OAUTH_TOKEN", env)
|
|
157
|
+
self.assertEqual(env["HERMES_PROVIDER"], "anthropic")
|
|
158
|
+
finally:
|
|
159
|
+
os.environ.pop("OMEGA_HOME", None)
|
|
160
|
+
if old_home is not None:
|
|
161
|
+
os.environ["OMEGA_HOME"] = old_home
|
|
162
|
+
if old_anth is not None:
|
|
163
|
+
os.environ["ANTHROPIC_API_KEY"] = old_anth
|
|
116
164
|
|
|
117
165
|
|
|
118
166
|
# ---------------------------------------------------------------------------
|
|
@@ -142,10 +142,15 @@ class TestTopicStats(unittest.TestCase):
|
|
|
142
142
|
self.assertEqual(by_topic[2]["messages"], 1)
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
class
|
|
146
|
-
"""The daemon
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
class TestDaemonDMRoutesToAISBChat(unittest.TestCase):
|
|
146
|
+
"""The daemon now routes DMs to the AISB conversational agent
|
|
147
|
+
(v0.19.13 change). Previously it refused with "project topic only",
|
|
148
|
+
which made the bot mute on a fresh install with no group yet."""
|
|
149
|
+
|
|
150
|
+
def test_dm_message_routes_to_aisb_chat(self):
|
|
151
|
+
from omega_engine.daemons import telegram as T
|
|
152
|
+
from omega_engine import aisb_chat
|
|
153
|
+
from unittest import mock
|
|
149
154
|
|
|
150
155
|
class _FakeBridge:
|
|
151
156
|
def __init__(self):
|
|
@@ -161,22 +166,65 @@ class TestDaemonDMRefusal(unittest.TestCase):
|
|
|
161
166
|
with tempfile.TemporaryDirectory() as td:
|
|
162
167
|
home = Path(td)
|
|
163
168
|
bridge = _FakeBridge()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
with mock.patch.object(aisb_chat, "chat_once",
|
|
170
|
+
return_value="hello from AISB"):
|
|
171
|
+
tag = T._route_one(
|
|
172
|
+
topic_id=None, text="hi from DM",
|
|
173
|
+
message_id=5, chat_id=12345,
|
|
174
|
+
supervisor=_FakeSupervisor(),
|
|
175
|
+
project_map={},
|
|
176
|
+
home=home,
|
|
177
|
+
telegram_bridge=bridge,
|
|
178
|
+
)
|
|
179
|
+
self.assertEqual(tag, "dm:aisb-chat",
|
|
180
|
+
"DM must now be tagged as routed to AISB, not refused")
|
|
181
|
+
# We sent the AISB reply back via sendMessage.
|
|
174
182
|
self.assertEqual(len(bridge.calls), 1)
|
|
175
183
|
self.assertEqual(bridge.calls[0]["method"], "sendMessage")
|
|
176
184
|
self.assertEqual(
|
|
177
185
|
str(bridge.calls[0]["fields"]["chat_id"]), "12345",
|
|
178
186
|
)
|
|
179
|
-
self.
|
|
187
|
+
self.assertEqual(
|
|
188
|
+
bridge.calls[0]["fields"]["text"], "hello from AISB",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def test_dm_history_is_namespaced_by_chat_id(self):
|
|
192
|
+
"""Two DMs from different chats must NOT cross-contaminate history.
|
|
193
|
+
We use negative topic_ids derived from chat_id (real topics are
|
|
194
|
+
always positive Telegram forum thread IDs)."""
|
|
195
|
+
from omega_engine.daemons import telegram as T
|
|
196
|
+
from omega_engine import aisb_chat
|
|
197
|
+
from unittest import mock
|
|
198
|
+
|
|
199
|
+
class _FakeBridge:
|
|
200
|
+
def __init__(self): self.calls = []
|
|
201
|
+
def _call(self, method, fields, **_kw):
|
|
202
|
+
self.calls.append({"method": method, "fields": fields})
|
|
203
|
+
return {"message_id": 1}
|
|
204
|
+
|
|
205
|
+
class _FakeSupervisor:
|
|
206
|
+
def on_channel_message(self, t, x): return []
|
|
207
|
+
|
|
208
|
+
with tempfile.TemporaryDirectory() as td:
|
|
209
|
+
home = Path(td)
|
|
210
|
+
(home / "Agentik_Runtime").mkdir(parents=True)
|
|
211
|
+
captured: list[int] = []
|
|
212
|
+
def _fake_chat(home_arg, text, *, topic_id, record_history):
|
|
213
|
+
captured.append(topic_id)
|
|
214
|
+
return "ok"
|
|
215
|
+
with mock.patch.object(aisb_chat, "chat_once",
|
|
216
|
+
side_effect=_fake_chat):
|
|
217
|
+
T._route_one(topic_id=None, text="hi", message_id=1,
|
|
218
|
+
chat_id=42, supervisor=_FakeSupervisor(),
|
|
219
|
+
project_map={}, home=home,
|
|
220
|
+
telegram_bridge=_FakeBridge())
|
|
221
|
+
T._route_one(topic_id=None, text="hi", message_id=2,
|
|
222
|
+
chat_id=99, supervisor=_FakeSupervisor(),
|
|
223
|
+
project_map={}, home=home,
|
|
224
|
+
telegram_bridge=_FakeBridge())
|
|
225
|
+
self.assertEqual(captured, [-42, -99],
|
|
226
|
+
"DM history must be namespaced by chat_id "
|
|
227
|
+
"(encoded as negative topic_id)")
|
|
180
228
|
|
|
181
229
|
def test_topic_message_records_history(self):
|
|
182
230
|
from omega_engine.daemons.telegram import _route_one
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.19.
|
|
1
|
+
0.19.14
|
|
@@ -1,90 +1,147 @@
|
|
|
1
1
|
# OmegaOS Layered Architecture
|
|
2
2
|
|
|
3
|
-
> Five layers.
|
|
4
|
-
>
|
|
3
|
+
> Five layers. **Two independent credential domains.** **Two Telegram bots
|
|
4
|
+
> with separate tokens.** Hermès sits above; AISB+Oracle+Workers stay below.
|
|
5
|
+
> Each layer is independently usable.
|
|
6
|
+
|
|
7
|
+
## The corrected model (v0.19.14)
|
|
5
8
|
|
|
6
9
|
```
|
|
7
10
|
┌──────────────────────────────────────────────────────────────────────┐
|
|
8
|
-
│ Layer 1 ─ Human
|
|
9
|
-
│
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
│
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
│
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
│
|
|
22
|
-
│
|
|
23
|
-
│
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
│
|
|
28
|
-
│
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
│
|
|
36
|
-
│
|
|
37
|
-
|
|
38
|
-
|
|
11
|
+
│ Layer 1 ─ Human (you) │
|
|
12
|
+
│ Three doors: │
|
|
13
|
+
│ 1. Telegram → Hermès bot (meta-companion, Anthropic API) │
|
|
14
|
+
│ 2. Telegram → AISB bot (OmegaOS native, Claude Max OAuth) │
|
|
15
|
+
│ 3. CLI / tmux (omega …, AISB-chat session) │
|
|
16
|
+
└────────┬───────────────────────────────────┬─────────────────────────┘
|
|
17
|
+
│ │
|
|
18
|
+
▼ ▼
|
|
19
|
+
┌──────────────────────┐ ┌────────────────────────────────────┐
|
|
20
|
+
│ Layer 2 ─ HERMÈS │ │ Layer 3 ─ AISB │
|
|
21
|
+
│ Meta-companion, │ ───────►│ OmegaOS intake / orchestrator │
|
|
22
|
+
│ scheduler, learner. │ dispatch│ Classifies, picks a topology, │
|
|
23
|
+
│ │ missions│ runs the mission. │
|
|
24
|
+
│ Auth: ANTHROPIC_API_ │ │ │
|
|
25
|
+
│ KEY_HERMES │ │ Auth: Claude Max OAuth │
|
|
26
|
+
│ Bot: TELEGRAM_TOKEN_│ │ (~/.claude/.credentials.json)│
|
|
27
|
+
│ HERMES │ │ Bot: TELEGRAM_TOKEN_AISB │
|
|
28
|
+
│ │ │ │
|
|
29
|
+
│ OPT-IN (skip if you │ │ Required for missions. │
|
|
30
|
+
│ don't want a paid │ │ Telegram bot is optional too — │
|
|
31
|
+
│ Anthropic key) │ │ tmux AISB-chat is the fallback. │
|
|
32
|
+
└──────────────────────┘ └─────────────┬──────────────────────┘
|
|
33
|
+
│
|
|
34
|
+
▼
|
|
35
|
+
┌────────────────────────────────────┐
|
|
36
|
+
│ Layer 4 ─ Oracle (planner) │
|
|
37
|
+
│ Persistent tmux. Reads mission, │
|
|
38
|
+
│ plans N workers with verify_cmd. │
|
|
39
|
+
│ Auth: Claude Max OAuth │
|
|
40
|
+
└─────────────┬──────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
▼
|
|
43
|
+
┌────────────────────────────────────┐
|
|
44
|
+
│ Layer 5 ─ Workers (executors) │
|
|
45
|
+
│ One per subtask. Persistent tmux. │
|
|
46
|
+
│ Writes .done.json. Audit-gated. │
|
|
47
|
+
│ Auth: Claude Max OAuth │
|
|
48
|
+
└────────────────────────────────────┘
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Why TWO bots, TWO auth domains
|
|
52
|
+
|
|
53
|
+
| Concern | Hermès (L2) | AISB+Oracle+Workers (L3-L5) |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| **Telegram token** | `TELEGRAM_TOKEN_HERMES` | `TELEGRAM_TOKEN_AISB` |
|
|
56
|
+
| **LLM credential** | `ANTHROPIC_API_KEY_HERMES` (you pay per call) | Claude Max OAuth from `~/.claude/.credentials.json` (covered by your Max sub) |
|
|
57
|
+
| **What it does** | Meta-reasoning: schedules, suggestions, learning, dispatches missions DOWN to AISB | Executes verified-completion missions inside projects |
|
|
58
|
+
| **Budget risk** | You pay → bounded by your Anthropic spend limit | Claude Max — never charged per call |
|
|
59
|
+
| **Failure mode if absent** | Skip Hermès → OmegaOS still works (CLI + AISB bot) | If absent, no missions → not optional |
|
|
60
|
+
|
|
61
|
+
This split is intentional:
|
|
62
|
+
|
|
63
|
+
1. **Budget isolation.** Hermès can run a tight schedule loop, learn from
|
|
64
|
+
observations, propose missions — without ever touching your Max quota.
|
|
65
|
+
AISB+Workers can crank through 50-step missions on Max OAuth — without
|
|
66
|
+
ever burning your Anthropic API budget.
|
|
67
|
+
2. **Independent identity.** Hermès has its own Telegram username, its
|
|
68
|
+
own bot personality, its own conversation history. AISB stays
|
|
69
|
+
project-focused (one bot per OmegaOS install, topics per project).
|
|
70
|
+
3. **Authority gradient.** Hermès is *above* OmegaOS — it can issue
|
|
71
|
+
commands to AISB but doesn't run inside it. AISB is *the* runtime
|
|
72
|
+
for OmegaOS missions.
|
|
73
|
+
|
|
74
|
+
## Per-project Telegram structure
|
|
75
|
+
|
|
76
|
+
OmegaOS treats Telegram as the operator's command surface:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
AISB Group (Telegram supergroup with topics enabled)
|
|
80
|
+
│
|
|
81
|
+
├── Topic "general" — chat with AISB, status questions
|
|
82
|
+
├── Topic "project: dentistry" — dispatch missions for the Dentistry project
|
|
83
|
+
├── Topic "project: kommu" — dispatch missions for the Kommu project
|
|
84
|
+
├── Topic "project: causio" — dispatch missions for the Causio project
|
|
85
|
+
└── … (one topic per project, mapped in
|
|
86
|
+
Agentik_SSOT/projects/<slug>/registry.yaml)
|
|
39
87
|
```
|
|
40
88
|
|
|
41
|
-
|
|
89
|
+
A message posted in a project topic = a mission for THAT project. AISB
|
|
90
|
+
reads `message_thread_id` (the topic_id), looks up the slug, runs the
|
|
91
|
+
mission in the project's context (cwd = project root, env =
|
|
92
|
+
project-scoped secrets).
|
|
93
|
+
|
|
94
|
+
Hermès operates ABOVE the group. It can:
|
|
95
|
+
|
|
96
|
+
* Receive a DM in **its own** Telegram bot from you.
|
|
97
|
+
* Decide: "this is a mission for project X" → send a message INTO
|
|
98
|
+
the AISB group's topic-X (Hermès posts as a member of the group).
|
|
99
|
+
* Or: "this is a meta-question" → answer directly via Anthropic API.
|
|
100
|
+
* Or: "this is an autonomous trigger" (cron, observation) → dispatch
|
|
101
|
+
a fresh mission into a project topic.
|
|
42
102
|
|
|
43
|
-
|
|
44
|
-
|---|---|---|---|
|
|
45
|
-
| 1 | Intent | Human | n/a |
|
|
46
|
-
| 2 | Autonomous companion | Hermes (Python, ~/.hermes) | Claude Max OAuth |
|
|
47
|
-
| 3 | Mission intake | OmegaOS engine | Claude Max OAuth |
|
|
48
|
-
| 4 | Planning | Persistent tmux + `claude -p` | Claude Max OAuth |
|
|
49
|
-
| 5 | Execution | Persistent tmux + `claude -p` | Claude Max OAuth |
|
|
103
|
+
## Install / secrets layout (corrected)
|
|
50
104
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
token
|
|
54
|
-
|
|
55
|
-
|
|
105
|
+
| Vault key | Holds | Who reads it |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `TELEGRAM_TOKEN_AISB` | AISB bot token (from BotFather, bot A) | `omega telegram bridge` + AISB daemon |
|
|
108
|
+
| `TELEGRAM_TOKEN_HERMES` | Hermès bot token (from BotFather, bot B) | Hermès daemon only |
|
|
109
|
+
| `ANTHROPIC_API_KEY_HERMES` | Hermès's own paid Anthropic key | Hermès daemon only |
|
|
110
|
+
| `TELEGRAM_GROUP_ID` | AISB supergroup chat_id | AISB daemon (to scope missions) |
|
|
111
|
+
| `TELEGRAM_TOKEN` | **back-compat alias** for `TELEGRAM_TOKEN_AISB` | Old install paths |
|
|
112
|
+
| Claude Max OAuth | The OAuth at `~/.claude/.credentials.json` | AISB, Oracle, all Workers |
|
|
113
|
+
|
|
114
|
+
Claude Max OAuth is **never duplicated in the vault** — it lives in
|
|
115
|
+
`~/.claude/.credentials.json` and every layer below Hermès reads it live
|
|
116
|
+
on every call so refresh rotations propagate naturally.
|
|
56
117
|
|
|
57
118
|
## Layer choice cheat-sheet
|
|
58
119
|
|
|
59
120
|
| You want to | Use |
|
|
60
121
|
|---|---|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
69
|
-
## Bridges
|
|
70
|
-
|
|
71
|
-
* `omega hermes` — Layer 2 ↔ rest of stack. Hermes can call OmegaOS via
|
|
72
|
-
the `omega` CLI (any of layers 3-5). OmegaOS can call Hermes via
|
|
73
|
-
`omega hermes ask "..."`.
|
|
74
|
-
* `omega ua` — Understand-Anything sidecar. Builds an interactive
|
|
75
|
-
knowledge graph of any project; `omega ua consume` lands the graph
|
|
76
|
-
into the Engine's GraphRetriever so Oracle/workers can answer
|
|
77
|
-
"where in the code is X?" via Graph RAG.
|
|
78
|
-
* `omega ma` — Anthropic Managed Agents (opt-in, API-key-only). NOT
|
|
79
|
-
part of the OAuth stack; only used when explicitly opted into per
|
|
80
|
-
topology entry.
|
|
122
|
+
| Quick chat with the meta-companion | Hermès bot (DM) — Anthropic API |
|
|
123
|
+
| Run a mission on a project | AISB project topic OR `omega run` from project dir |
|
|
124
|
+
| One-shot CLI question (no orchestration) | `claude -p "..."` directly |
|
|
125
|
+
| Verified-completion multi-worker mission | `omega run` / AISB topic — engages Oracle + Workers |
|
|
126
|
+
| Recurring scheduled mission | `omega cadence schedule …` — wakes through AISB |
|
|
127
|
+
| Cross-platform autonomous loop | Hermès (Anthropic API key, scheduled tasks) |
|
|
128
|
+
| Audit a project | `/codeaudit` etc. from project — Quality Arsenal |
|
|
81
129
|
|
|
82
130
|
## What this is NOT
|
|
83
131
|
|
|
84
|
-
*
|
|
85
|
-
|
|
86
|
-
ability to delegate to each other.
|
|
87
|
-
*
|
|
88
|
-
OS
|
|
89
|
-
|
|
90
|
-
|
|
132
|
+
* Hermès is NOT a wrapper around AISB — they're separate runtimes with
|
|
133
|
+
separate credentials and separate Telegram identities. The bridge gives
|
|
134
|
+
both the ability to delegate to each other.
|
|
135
|
+
* AISB does NOT need Hermès to function. Skip Hermès install → OmegaOS
|
|
136
|
+
is a complete agentic OS with verified completion. Add Hermès when you
|
|
137
|
+
want meta-reasoning + autonomous loops above your projects.
|
|
138
|
+
* The Anthropic API key Hermès uses is NOT shared with anything else.
|
|
139
|
+
AISB+Oracle+Workers stay on Max OAuth, always.
|
|
140
|
+
|
|
141
|
+
## v0.19.x evolution
|
|
142
|
+
|
|
143
|
+
| Version | Change |
|
|
144
|
+
|---|---|
|
|
145
|
+
| v0.18 | Single OAuth model (Hermès on Claude Max) |
|
|
146
|
+
| **v0.19.14** | **Split: Hermès on `ANTHROPIC_API_KEY_HERMES`; AISB on Max OAuth; two Telegram bots** |
|
|
147
|
+
| (planned v0.19.15+) | Dedicated Hermès daemon (its own poll loop), Hermès→AISB dispatch verbs |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# References
|
|
2
|
+
|
|
3
|
+
Operator-curated source-of-truth documents that OmegaOS skills + Genesis
|
|
4
|
+
consume by name. Drop a new version of any file here and it propagates
|
|
5
|
+
to every project at the next `omega sync`.
|
|
6
|
+
|
|
7
|
+
## Active references
|
|
8
|
+
|
|
9
|
+
| File | Consumed by | Topic |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md` | `/desktop-architecture`, Genesis stack `claude-dashboard`, refonte audit | Premium desktop / dashboard UI architecture, the "Claude / Linear / Vercel / Stripe / Elevenlabs" canon |
|
|
12
|
+
|
|
13
|
+
## Format
|
|
14
|
+
|
|
15
|
+
Plain Markdown. No frontmatter needed — these are reference docs, not
|
|
16
|
+
SKILL.md. Headings should be self-describing so skills can extract
|
|
17
|
+
sub-sections by regex if needed.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: desktop-architecture
|
|
3
|
+
description: >
|
|
4
|
+
Reference skill — pull the canonical Claude Code-grade desktop/dashboard
|
|
5
|
+
architecture (`Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`)
|
|
6
|
+
and apply it to a project. Triggers on "desktop architecture", "Claude
|
|
7
|
+
dashboard", "Claude desktop", "premium dashboard", "comme Linear / Vercel
|
|
8
|
+
/ Stripe / Elevenlabs", "dashboard senior", "claude stack". Use whenever
|
|
9
|
+
the user asks for a dashboard refonte or a new project that needs the
|
|
10
|
+
Claude-grade desktop look.
|
|
11
|
+
when_to_use: >
|
|
12
|
+
User mentions "desktop architecture", "Claude dashboard", "Claude desktop
|
|
13
|
+
stack", or asks for a dashboard rebuild "comme Claude / Linear / Vercel /
|
|
14
|
+
Stripe / Elevenlabs". Also triggers automatically when the Genesis stack
|
|
15
|
+
picker selects the `claude-dashboard` preset.
|
|
16
|
+
allowed-tools: Read Grep Glob
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# /desktop-architecture — pull the canonical Claude dashboard reference
|
|
20
|
+
|
|
21
|
+
This skill loads the **Claude Desktop Frontend Architecture** reference
|
|
22
|
+
document from the SSOT and applies its principles to the current task.
|
|
23
|
+
|
|
24
|
+
## What it does
|
|
25
|
+
|
|
26
|
+
1. Reads `$OMEGA_HOME/Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`
|
|
27
|
+
2. Extracts the relevant section (components, layout, motion, palette,
|
|
28
|
+
typography, density, navigation, command palette, etc.)
|
|
29
|
+
3. Applies it as the design contract for the requested task:
|
|
30
|
+
- **Refonte audit** — score the current UI against this contract
|
|
31
|
+
- **Genesis** — when stack = `claude-dashboard`, the PRD, branding and
|
|
32
|
+
design-system phases derive their tokens from this doc
|
|
33
|
+
- **Component builder** — when a worker generates a new dashboard
|
|
34
|
+
screen, it references the layout primitives from this doc first
|
|
35
|
+
|
|
36
|
+
## Triggers (any of these in a user prompt invoke me)
|
|
37
|
+
|
|
38
|
+
- `desktop architecture`
|
|
39
|
+
- `Claude desktop` / `Claude dashboard` / `Claude stack`
|
|
40
|
+
- `premium dashboard` / `dashboard senior`
|
|
41
|
+
- `comme Linear` / `comme Vercel` / `comme Stripe` / `comme Elevenlabs`
|
|
42
|
+
- `refais le dashboard` / `redesign dashboard` (combined with project name)
|
|
43
|
+
|
|
44
|
+
## Where it lives
|
|
45
|
+
|
|
46
|
+
The reference doc itself lives at:
|
|
47
|
+
`$OMEGA_HOME/Agentik_SSOT/docs/references/CLAUDE-DESKTOP-FRONTEND-ARCHITECTURE.md`
|
|
48
|
+
|
|
49
|
+
It's the single source of truth — when Gareth refreshes the document
|
|
50
|
+
(e.g. new components, new motion language), every project re-reads it
|
|
51
|
+
on next `/desktop-architecture` invocation. No fork, no drift.
|
|
52
|
+
|
|
53
|
+
## How to refresh the reference
|
|
54
|
+
|
|
55
|
+
The operator drops a new version into the SSOT path above, then runs:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
omega sync # projects to ~/.claude/skills/<id>/
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Workers spawned after the sync pick up the new content automatically.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentikos/omega-os",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.14",
|
|
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"
|