@agentikos/omega-os 0.19.42 → 0.19.44
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/__pycache__/llm-clis.cpython-313.pyc +0 -0
- package/bootstrap/lib/common.sh +39 -9
- package/bootstrap/lib/llm-clis.py +6 -0
- package/bootstrap/lib/manifest-helpers.py +110 -0
- package/bootstrap/lib/steps.sh +253 -28
- package/bootstrap/templates/aisb/CLAUDE.md +13 -0
- package/install.sh +8 -2
- package/omega/Agentik_Engine/omega_engine/__init__.py +1 -1
- package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/hermes.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/paperclip_bridge.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/personas.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__/tmux.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/__pycache__/tui.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/omega_engine/cli.py +44 -7
- package/omega/Agentik_Engine/omega_engine/hermes.py +43 -1
- package/omega/Agentik_Engine/omega_engine/paperclip_bridge.py +22 -0
- package/omega/Agentik_Engine/omega_engine/personas.py +11 -3
- package/omega/Agentik_Engine/omega_engine/provider.py +18 -3
- package/omega/Agentik_Engine/omega_engine/tmux.py +41 -21
- package/omega/Agentik_Engine/omega_engine/tui.py +8 -7
- package/omega/Agentik_Engine/pyproject.toml +1 -1
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps_v0_19_43.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_install_steps_v0_19_43.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tmux_palette.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_tmux_palette.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_v19_43_fixes.cpython-313-pytest-8.4.2.pyc +0 -0
- package/omega/Agentik_Engine/tests/__pycache__/test_v19_43_fixes.cpython-313.pyc +0 -0
- package/omega/Agentik_Engine/tests/test_install_steps_v0_19_43.py +242 -0
- package/omega/Agentik_Engine/tests/test_installer_wiring.py +128 -1
- package/omega/Agentik_Engine/tests/test_tmux_palette.py +51 -0
- package/omega/Agentik_Engine/tests/test_v19_43_fixes.py +265 -0
- package/omega/Agentik_SSOT/VERSION +1 -1
- package/omega/Agentik_SSOT/docs/AUDIT-V0.19.43.md +92 -0
- package/omega/Agentik_SSOT/rules/audit-gates.md +2 -2
- package/omega/Agentik_SSOT/rules/constitution.md +18 -0
- package/omega/Agentik_SSOT/rules/three-laws.md +2 -0
- package/package.json +1 -1
|
Binary file
|
package/bootstrap/lib/common.sh
CHANGED
|
@@ -37,8 +37,14 @@ detect_os() {
|
|
|
37
37
|
*) die "unsupported OS: $(uname -s)" ;;
|
|
38
38
|
esac
|
|
39
39
|
if [ "$OMEGA_OS" = "linux" ]; then
|
|
40
|
+
# Order matters: prefer the manager actually managing the distro.
|
|
41
|
+
# apt (Debian/Ubuntu) → dnf (RHEL/Fedora) → pacman (Arch/Manjaro)
|
|
42
|
+
# → apk (Alpine) → zypper (openSUSE/SLES) → unknown.
|
|
40
43
|
if have apt-get; then OMEGA_PKG="apt"
|
|
41
44
|
elif have dnf; then OMEGA_PKG="dnf"
|
|
45
|
+
elif have pacman; then OMEGA_PKG="pacman"
|
|
46
|
+
elif have apk; then OMEGA_PKG="apk"
|
|
47
|
+
elif have zypper; then OMEGA_PKG="zypper"
|
|
42
48
|
else OMEGA_PKG="unknown"; fi
|
|
43
49
|
else
|
|
44
50
|
OMEGA_PKG="brew"
|
|
@@ -89,7 +95,25 @@ record_state_version() {
|
|
|
89
95
|
# card prints normally.
|
|
90
96
|
run_step() {
|
|
91
97
|
local name="$1" fn="$2"
|
|
92
|
-
|
|
98
|
+
# v0.19.44 — code-deploy steps NEVER skip when the bundled version
|
|
99
|
+
# differs from the installed version, even if state file marks done.
|
|
100
|
+
# Without this, a stale `.install-state` entry blocks step_structure
|
|
101
|
+
# from refreshing cli.py — the bug the user hit on v0.19.43.
|
|
102
|
+
local _force_step=0
|
|
103
|
+
case "$name" in
|
|
104
|
+
*structure*|*aisb-suite*|*audit-skills*|*engine*|*personas*)
|
|
105
|
+
local _installed_v=""
|
|
106
|
+
[ -f "$OMEGA_HOME/Agentik_SSOT/VERSION" ] \
|
|
107
|
+
&& _installed_v="$(cat "$OMEGA_HOME/Agentik_SSOT/VERSION" 2>/dev/null || echo '')"
|
|
108
|
+
if [ -n "$_installed_v" ] \
|
|
109
|
+
&& [ "$_installed_v" != "${OMEGA_BUNDLED_VERSION:-}" ]; then
|
|
110
|
+
_force_step=1
|
|
111
|
+
fi
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
if step_done "$name" \
|
|
115
|
+
&& [ "${FORCE:-0}" != "1" ] \
|
|
116
|
+
&& [ "$_force_step" != "1" ]; then
|
|
93
117
|
if [ "${INSTALL_FULL:-0}" = "1" ]; then
|
|
94
118
|
_full_progress "$name" "skip"
|
|
95
119
|
return 0
|
|
@@ -97,6 +121,9 @@ run_step() {
|
|
|
97
121
|
log "${C_DIM}-- skip $name (already done)${C_RST}"
|
|
98
122
|
return 0
|
|
99
123
|
fi
|
|
124
|
+
if [ "$_force_step" = "1" ]; then
|
|
125
|
+
log "${C_YELLOW}!${C_RST} force-rerun $name (installed v${_installed_v} ≠ bundled v${OMEGA_BUNDLED_VERSION:-?})"
|
|
126
|
+
fi
|
|
100
127
|
|
|
101
128
|
if [ "${INSTALL_FULL:-0}" = "1" ]; then
|
|
102
129
|
# Redirect step output to the log; only the progress bar stays on screen.
|
|
@@ -423,14 +450,17 @@ omega_version() {
|
|
|
423
450
|
install_banner() {
|
|
424
451
|
local v; v="$(omega_version)"
|
|
425
452
|
printf '\n'
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
printf '%s
|
|
430
|
-
printf '%s ███ ███
|
|
431
|
-
printf '%s ███ ███ ███ ███ ███ ███
|
|
432
|
-
printf '%s ███ ███ ███ ███ ███
|
|
433
|
-
printf '%s
|
|
453
|
+
# v0.19.44 — clean blocky A consistent with O/M/E/G shapes. The old A
|
|
454
|
+
# used half-diagonal characters (▄███▄▄▄▄██▀ / ▀▀███▀▀▀▀▀ / ▀███████████)
|
|
455
|
+
# that looked like noise — the new A has a clean horizontal crossbar.
|
|
456
|
+
printf '%s ▄██████▄ ▄▄▄▄███▄▄▄▄ ▄████████ ▄██████▄ ▄████████ %s\n' "$C_ORANGE" "$C_RST"
|
|
457
|
+
printf '%s ███ ███ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
458
|
+
printf '%s ███ ███ ███ ███ ███ ███ █▀ ███ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
459
|
+
printf '%s ███ ███ ███ ███ ███ ▄███▄▄▄ ▄███ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
460
|
+
printf '%s ███ ███ ███ ███ ███ ▀▀███▀▀▀ ▀▀███ ████▄ ██████████%s\n' "$C_ORANGE" "$C_RST"
|
|
461
|
+
printf '%s ███ ███ ███ ███ ███ ███ █▄ ███ ███ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
462
|
+
printf '%s ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
463
|
+
printf '%s ▀██████▀ ▀█ ███ █▀ ██████████ ▀██████▀ ███ ███%s\n' "$C_ORANGE" "$C_RST"
|
|
434
464
|
printf '\n'
|
|
435
465
|
printf ' %sOmega OS%s %sv%s%s · %sagentik-os/OmegaOS%s\n' \
|
|
436
466
|
"$C_BOLD" "$C_RST" "$C_DIM" "$v" "$C_RST" "$C_DIM" "$C_RST"
|
|
@@ -219,6 +219,12 @@ def _resolve_install_cmd(spec: CliSpec) -> list[str] | None:
|
|
|
219
219
|
if _have("pip"):
|
|
220
220
|
return ["pip", "install", "--user", "aider-chat"]
|
|
221
221
|
return None
|
|
222
|
+
if spec.id == "ollama":
|
|
223
|
+
# Ollama's official installer is a curl-piped shell script —
|
|
224
|
+
# the only supported install path on Linux/macOS. v0.19.43 fix:
|
|
225
|
+
# previously returned None, so the --full installer would refuse
|
|
226
|
+
# to install ollama at all.
|
|
227
|
+
return ["bash", "-c", "curl -fsSL https://ollama.com/install.sh | sh"]
|
|
222
228
|
return None
|
|
223
229
|
|
|
224
230
|
|
|
@@ -36,6 +36,12 @@ Subcommands
|
|
|
36
36
|
telegram-chat-id <manifest> <omega_home>
|
|
37
37
|
Read ``telegram.group_chat_id`` from the manifest (if set) and
|
|
38
38
|
persist it through the vault. Returns the resolved id on stdout.
|
|
39
|
+
|
|
40
|
+
providers-from-catalog <omega_home>
|
|
41
|
+
--full mode fallback. Discover available providers from
|
|
42
|
+
Agentik_SSOT/llm-providers/providers-catalog.yaml — include any
|
|
43
|
+
whose first env var is set in the environment OR whose secret
|
|
44
|
+
already exists in the vault. Writes a default router.yaml.
|
|
39
45
|
"""
|
|
40
46
|
from __future__ import annotations
|
|
41
47
|
|
|
@@ -100,6 +106,108 @@ def cmd_providers(manifest: str, omega_home: str) -> int:
|
|
|
100
106
|
return 0
|
|
101
107
|
|
|
102
108
|
|
|
109
|
+
def _roles_for_cli(cli: str) -> list[str]:
|
|
110
|
+
"""Map an LLM CLI to default ModelRouter roles.
|
|
111
|
+
|
|
112
|
+
Reasoning:
|
|
113
|
+
* claude_code = Anthropic Claude — the canonical executor/dispatcher.
|
|
114
|
+
* gemini_cli = Google Gemini — strong general executor.
|
|
115
|
+
* codex = OpenAI Codex — executor (paid OpenAI API).
|
|
116
|
+
* opencode = multi-provider community CLI — anything goes.
|
|
117
|
+
* Others fall back to a generic "executor" role.
|
|
118
|
+
"""
|
|
119
|
+
cli = (cli or "").strip()
|
|
120
|
+
if cli == "claude_code":
|
|
121
|
+
return ["executor", "dispatcher"]
|
|
122
|
+
if cli == "opencode":
|
|
123
|
+
return ["executor", "worker"]
|
|
124
|
+
return ["executor"]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cmd_providers_from_catalog(omega_home: str) -> int:
|
|
128
|
+
"""--full mode fallback: auto-generate router.yaml from the catalog.
|
|
129
|
+
|
|
130
|
+
For every provider in
|
|
131
|
+
``Agentik_SSOT/llm-providers/providers-catalog.yaml`` whose first
|
|
132
|
+
secret_ref env var is present (in the live env or in the vault),
|
|
133
|
+
write a corresponding entry to ``Agentik_SSOT/providers/router.yaml``.
|
|
134
|
+
Providers with ``secret_refs: []`` (oauth / local) are always
|
|
135
|
+
eligible because they don't need an api key.
|
|
136
|
+
"""
|
|
137
|
+
home = Path(omega_home)
|
|
138
|
+
catalog_path = home / "Agentik_SSOT" / "llm-providers" / "providers-catalog.yaml"
|
|
139
|
+
if not catalog_path.exists():
|
|
140
|
+
print(f"no providers catalog at {catalog_path} — skipping")
|
|
141
|
+
return 0
|
|
142
|
+
try:
|
|
143
|
+
catalog = yaml.safe_load(catalog_path.read_text()) or {}
|
|
144
|
+
except yaml.YAMLError as exc:
|
|
145
|
+
print(f"catalog YAML error: {exc}")
|
|
146
|
+
return 0
|
|
147
|
+
entries = catalog.get("providers") or []
|
|
148
|
+
if not entries:
|
|
149
|
+
print(f"catalog at {catalog_path} has no `providers:` block")
|
|
150
|
+
return 0
|
|
151
|
+
|
|
152
|
+
# Vault is best-effort — if the engine isn't importable yet we just
|
|
153
|
+
# rely on os.environ.
|
|
154
|
+
_engine_on_path(home)
|
|
155
|
+
vault_read = None
|
|
156
|
+
try:
|
|
157
|
+
from omega_engine.vault import vault_read as _vr # type: ignore
|
|
158
|
+
vault_read = _vr
|
|
159
|
+
except Exception:
|
|
160
|
+
vault_read = None
|
|
161
|
+
|
|
162
|
+
def _has_secret(env_name: str) -> bool:
|
|
163
|
+
if os.environ.get(env_name):
|
|
164
|
+
return True
|
|
165
|
+
if vault_read is None:
|
|
166
|
+
return False
|
|
167
|
+
try:
|
|
168
|
+
v = vault_read(home, env_name)
|
|
169
|
+
return bool(v and v.strip())
|
|
170
|
+
except Exception:
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
router: dict = {"providers": []}
|
|
174
|
+
discovered: list[str] = []
|
|
175
|
+
for entry in entries:
|
|
176
|
+
if not isinstance(entry, dict):
|
|
177
|
+
continue
|
|
178
|
+
pid = (entry.get("id") or "").strip()
|
|
179
|
+
if not pid:
|
|
180
|
+
continue
|
|
181
|
+
cli = (entry.get("cli") or "").strip()
|
|
182
|
+
refs = entry.get("secret_refs") or []
|
|
183
|
+
# Providers with no secret_refs at all (oauth / local — ollama,
|
|
184
|
+
# lm_studio, github_copilot, chatgpt_subscription) are eligible
|
|
185
|
+
# without a key check.
|
|
186
|
+
primary = refs[0] if refs else None
|
|
187
|
+
eligible = (primary is None) or _has_secret(primary)
|
|
188
|
+
if not eligible:
|
|
189
|
+
continue
|
|
190
|
+
router["providers"].append({
|
|
191
|
+
"id": pid,
|
|
192
|
+
"roles": _roles_for_cli(cli),
|
|
193
|
+
"enabled": True,
|
|
194
|
+
"secret_ref": primary or "",
|
|
195
|
+
"cli": cli,
|
|
196
|
+
})
|
|
197
|
+
discovered.append(pid)
|
|
198
|
+
|
|
199
|
+
out_dir = home / "Agentik_SSOT" / "providers"
|
|
200
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
201
|
+
target = out_dir / "router.yaml"
|
|
202
|
+
target.write_text(yaml.safe_dump(router, sort_keys=False, default_flow_style=False))
|
|
203
|
+
if discovered:
|
|
204
|
+
print(f"discovered providers from catalog: {discovered}")
|
|
205
|
+
else:
|
|
206
|
+
print("no providers discovered (no env vars / vault secrets set yet)")
|
|
207
|
+
print(f"wrote {target}")
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
|
|
103
211
|
def cmd_autonomous(manifest: str, templates_dir: str, target_dir: str) -> int:
|
|
104
212
|
data = _load_manifest(manifest)
|
|
105
213
|
agents = data.get("autonomous_agents") or []
|
|
@@ -362,6 +470,8 @@ def main(argv: list[str]) -> int:
|
|
|
362
470
|
rest = argv[2:]
|
|
363
471
|
if cmd == "providers" and len(rest) == 2:
|
|
364
472
|
return cmd_providers(*rest)
|
|
473
|
+
if cmd == "providers-from-catalog" and len(rest) == 1:
|
|
474
|
+
return cmd_providers_from_catalog(*rest)
|
|
365
475
|
if cmd == "autonomous" and len(rest) == 3:
|
|
366
476
|
return cmd_autonomous(*rest)
|
|
367
477
|
if cmd == "rag" and len(rest) == 2:
|
package/bootstrap/lib/steps.sh
CHANGED
|
@@ -14,7 +14,7 @@ step_preflight() {
|
|
|
14
14
|
return 1
|
|
15
15
|
fi
|
|
16
16
|
have git || { err "git is required"; return 1; }
|
|
17
|
-
[ "$OMEGA_PKG" = "unknown" ] && { err "no supported package manager (apt/dnf/brew)"; return 1; }
|
|
17
|
+
[ "$OMEGA_PKG" = "unknown" ] && { err "no supported package manager (apt/dnf/brew/pacman/apk/zypper)"; return 1; }
|
|
18
18
|
mkdir -p "$STATE_DIR/logs"
|
|
19
19
|
return 0
|
|
20
20
|
}
|
|
@@ -26,15 +26,64 @@ step_system_deps() {
|
|
|
26
26
|
# - fzf — primary picker for the new session manager (`omega`)
|
|
27
27
|
# and required by the tmux-claude install script too
|
|
28
28
|
# whiptail lives in `whiptail` (Debian/Ubuntu), `newt` (RHEL/Fedora),
|
|
29
|
-
# `newt` (Homebrew). fzf is `fzf`
|
|
29
|
+
# `libnewt` (Arch), `newt` (Alpine/SUSE), `newt` (Homebrew). fzf is `fzf`
|
|
30
|
+
# on every platform. nodejs+npm are required because 7 of 13 LLM CLIs
|
|
31
|
+
# (claude_code, gemini_cli, codex, opencode, qwen_code, continue_dev,
|
|
32
|
+
# gh_copilot) install via `npm -g`. Without npm at this step the LLM
|
|
33
|
+
# CLI installer (step 15) silently skips every Node-based CLI.
|
|
30
34
|
local pkgs="python3 git tmux sqlite3 jq curl"
|
|
31
35
|
case "$OMEGA_PKG" in
|
|
32
|
-
apt)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
apt) sudo apt-get update -qq \
|
|
37
|
+
&& sudo apt-get install -y -qq $pkgs whiptail fzf python3-venv python3-yaml nodejs npm ;;
|
|
38
|
+
dnf) sudo dnf install -y -q $pkgs newt fzf python3-pyyaml nodejs npm ;;
|
|
39
|
+
brew) brew install $pkgs newt fzf node 2>/dev/null || true ;;
|
|
40
|
+
pacman) sudo pacman -S --noconfirm --needed $pkgs libnewt fzf python-yaml nodejs npm ;;
|
|
41
|
+
apk) sudo apk add --no-cache $pkgs newt fzf py3-yaml nodejs npm ;;
|
|
42
|
+
zypper) sudo zypper --non-interactive install -y $pkgs newt fzf python3-PyYAML nodejs npm ;;
|
|
43
|
+
*) err "install manually: $pkgs (and whiptail/newt + fzf + nodejs/npm for the menu and LLM CLIs)"; return 1 ;;
|
|
36
44
|
esac
|
|
37
45
|
|
|
46
|
+
# npm version check — 7 of 13 LLM CLIs (claude_code, gemini_cli, codex,
|
|
47
|
+
# opencode, qwen_code, continue_dev, gh_copilot) require npm >= 9 for
|
|
48
|
+
# the agentic CLI install to be reliable. Older npm still works for
|
|
49
|
+
# plain installs; we warn but never fail.
|
|
50
|
+
if have npm; then
|
|
51
|
+
local _npm_v _npm_major
|
|
52
|
+
_npm_v="$(npm --version 2>/dev/null || echo 0)"
|
|
53
|
+
_npm_major="$(printf '%s' "$_npm_v" | cut -d. -f1)"
|
|
54
|
+
case "$_npm_major" in
|
|
55
|
+
''|*[!0-9]*) _npm_major=0 ;;
|
|
56
|
+
esac
|
|
57
|
+
if [ "$_npm_major" -lt 9 ]; then
|
|
58
|
+
info "warn: npm $_npm_v detected — LLM CLI install (step 15) recommends npm >= 9"
|
|
59
|
+
info " upgrade: npm install -g npm@latest (or use your OS package manager)"
|
|
60
|
+
fi
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# tmux version check — the bundled pro config uses allow-passthrough,
|
|
64
|
+
# buffer-limit, and the modern hook syntax which require tmux >= 3.3.
|
|
65
|
+
# Older tmux still works (omega itself only needs basic features), but
|
|
66
|
+
# the pro profile emits errors on those config lines at load time.
|
|
67
|
+
if have tmux; then
|
|
68
|
+
local _tmux_v _tmux_major _tmux_minor
|
|
69
|
+
_tmux_v="$(tmux -V 2>/dev/null | awk '{print $2}' | tr -d -c '0-9.')"
|
|
70
|
+
if [ -n "$_tmux_v" ]; then
|
|
71
|
+
_tmux_major="$(printf '%s' "$_tmux_v" | cut -d. -f1)"
|
|
72
|
+
_tmux_minor="$(printf '%s' "$_tmux_v" | cut -d. -f2 | tr -d -c '0-9')"
|
|
73
|
+
case "$_tmux_major" in
|
|
74
|
+
''|*[!0-9]*) _tmux_major=0 ;;
|
|
75
|
+
esac
|
|
76
|
+
case "$_tmux_minor" in
|
|
77
|
+
''|*[!0-9]*) _tmux_minor=0 ;;
|
|
78
|
+
esac
|
|
79
|
+
if [ "$_tmux_major" -lt 3 ] || { [ "$_tmux_major" = "3" ] && [ "$_tmux_minor" -lt 3 ]; }; then
|
|
80
|
+
info "warn: tmux $_tmux_v detected — pro config requires >= 3.3"
|
|
81
|
+
info " some bindings (allow-passthrough, buffer-limit) may error at load"
|
|
82
|
+
info " upgrade via your OS package manager ($OMEGA_PKG) and reinstall tmux"
|
|
83
|
+
fi
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
|
|
38
87
|
# PyYAML — required by every install-side helper that reads the manifest
|
|
39
88
|
# or audit YAMLs (bootstrap/lib/llm-clis.py, manifest-helpers.py, audit
|
|
40
89
|
# generator). apt/dnf already deliver it via the system package above.
|
|
@@ -134,9 +183,12 @@ step_system_deps() {
|
|
|
134
183
|
if ! have age; then
|
|
135
184
|
info "installing age (powers the encrypted secrets vault)"
|
|
136
185
|
case "$OMEGA_PKG" in
|
|
137
|
-
apt)
|
|
138
|
-
dnf)
|
|
139
|
-
brew)
|
|
186
|
+
apt) sudo apt-get install -y -qq age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
187
|
+
dnf) sudo dnf install -y -q age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
188
|
+
brew) brew install age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
189
|
+
pacman) sudo pacman -S --noconfirm --needed age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
190
|
+
apk) sudo apk add --no-cache age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
191
|
+
zypper) sudo zypper --non-interactive install -y age 2>>"$LOG_FILE" || info "age install failed (non-fatal)" ;;
|
|
140
192
|
esac
|
|
141
193
|
fi
|
|
142
194
|
if ! have uv && [ ! -x "$HOME/.local/bin/uv" ]; then
|
|
@@ -204,7 +256,13 @@ step_llm_clis() {
|
|
|
204
256
|
python3 "$helper" install "$MANIFEST" | sed 's/^/ /'
|
|
205
257
|
return 0
|
|
206
258
|
fi
|
|
207
|
-
|
|
259
|
+
# v0.19.43 — --full mode (NONINTERACTIVE=1 + no MANIFEST) used to skip
|
|
260
|
+
# silently, leaving the operator with zero LLM CLIs after `npx ... --full`.
|
|
261
|
+
# Install the recommended set instead. install_cli is idempotent (skips
|
|
262
|
+
# already-installed CLIs), so this is safe on every entry.
|
|
263
|
+
info "headless --full mode: installing recommended LLM CLI set (claude_code + gemini_cli + opencode)"
|
|
264
|
+
python3 "$helper" install claude_code gemini_cli opencode | sed 's/^/ /' || \
|
|
265
|
+
warn "recommended LLM CLI install returned non-zero (non-fatal)"
|
|
208
266
|
return 0
|
|
209
267
|
fi
|
|
210
268
|
|
|
@@ -257,9 +315,30 @@ var/
|
|
|
257
315
|
staging/
|
|
258
316
|
EOF
|
|
259
317
|
# deploy the repo's source blocks into the live tree
|
|
318
|
+
#
|
|
319
|
+
# v0.19.44 — explicit `/bin/cp -Rf` (not bare `cp`) for two reasons:
|
|
320
|
+
# 1. Bypass any `alias cp='cp -i'` on macOS — interactive cp fails
|
|
321
|
+
# SILENTLY when stdin is piped (the --full case via npx). The user
|
|
322
|
+
# hit this on v0.19.43: re-install showed success but cli.py was
|
|
323
|
+
# never refreshed → bare `omega` kept printing the v0.19.40 message.
|
|
324
|
+
# 2. `-f` forces overwrite even when the destination is read-only or
|
|
325
|
+
# a stale immutable bit lingers from a previous install.
|
|
260
326
|
if [ -d "${OMEGA_REPO:-}/omega" ]; then
|
|
261
|
-
|
|
262
|
-
|
|
327
|
+
local prev_v=""
|
|
328
|
+
[ -f "$OMEGA_HOME/Agentik_SSOT/VERSION" ] \
|
|
329
|
+
&& prev_v="$(cat "$OMEGA_HOME/Agentik_SSOT/VERSION" 2>/dev/null || echo '')"
|
|
330
|
+
/bin/cp -Rf "$OMEGA_REPO/omega/." "$OMEGA_HOME/" || {
|
|
331
|
+
err "cp -Rf failed deploying $OMEGA_REPO/omega → $OMEGA_HOME/"
|
|
332
|
+
return 1
|
|
333
|
+
}
|
|
334
|
+
local new_v=""
|
|
335
|
+
[ -f "$OMEGA_HOME/Agentik_SSOT/VERSION" ] \
|
|
336
|
+
&& new_v="$(cat "$OMEGA_HOME/Agentik_SSOT/VERSION" 2>/dev/null || echo '')"
|
|
337
|
+
if [ -n "$prev_v" ] && [ "$prev_v" != "$new_v" ]; then
|
|
338
|
+
ok "code refreshed: ${prev_v} → ${new_v}"
|
|
339
|
+
else
|
|
340
|
+
ok "deployed source blocks from \$OMEGA_REPO/omega (v${new_v:-?})"
|
|
341
|
+
fi
|
|
263
342
|
else
|
|
264
343
|
err "repo source not found at \$OMEGA_REPO/omega"; return 1
|
|
265
344
|
fi
|
|
@@ -351,7 +430,16 @@ step_engine() {
|
|
|
351
430
|
local uv_bin; uv_bin="$(command -v uv || echo "$HOME/.local/bin/uv")"
|
|
352
431
|
[ -x "$uv_bin" ] || { err "uv not found after step 10"; return 1; }
|
|
353
432
|
cd "$OMEGA_HOME/Agentik_Engine" || { err "engine block missing"; return 1; }
|
|
354
|
-
|
|
433
|
+
# Pin engine venv to Python 3.13 — uv will download an Astral-managed
|
|
434
|
+
# build if the host's python3 is broken or unavailable. This sidesteps
|
|
435
|
+
# the macOS Tahoe brew Python 3.14 libexpat ABI mismatch and any other
|
|
436
|
+
# "system python3 silently inherited" failure mode. Fall back to a
|
|
437
|
+
# bare `uv venv` (uses whatever python3 is on PATH) so the install
|
|
438
|
+
# still succeeds on hosts where Python 3.13 cannot be procured.
|
|
439
|
+
if ! "$uv_bin" venv --python 3.13 >/dev/null 2>&1; then
|
|
440
|
+
info "engine venv: uv venv --python 3.13 failed, falling back to system python3"
|
|
441
|
+
"$uv_bin" venv >/dev/null 2>&1 || { err "uv venv failed"; return 1; }
|
|
442
|
+
fi
|
|
355
443
|
"$uv_bin" pip install -e . >/dev/null 2>&1 || { err "engine install failed"; return 1; }
|
|
356
444
|
mkdir -p "$OMEGA_HOME/Agentik_Tools/bin"
|
|
357
445
|
ln -sf "$OMEGA_HOME/Agentik_Engine/.venv/bin/omega" "$OMEGA_HOME/Agentik_Tools/bin/omega"
|
|
@@ -387,9 +475,16 @@ step_tmux_config() {
|
|
|
387
475
|
fi
|
|
388
476
|
local marker="$HOME/.tmux/scripts/session-manager.sh"
|
|
389
477
|
local installer_url="https://raw.githubusercontent.com/agentik-os/tmux-claude/main/install.sh"
|
|
478
|
+
# v0.19.43 — track whether ~/.tmux.conf is a tmux-claude install (either
|
|
479
|
+
# already present OR freshly installed by the curl pipe). When it is, we
|
|
480
|
+
# MUST also wire the Omega add-on (Alt+O bind) via
|
|
481
|
+
# install_into_home_tmux_conf — otherwise the user has tmux-claude but
|
|
482
|
+
# no way to reach the Omega menu from tmux.
|
|
483
|
+
local upstream_present=0
|
|
390
484
|
|
|
391
485
|
if [ -f "$marker" ]; then
|
|
392
|
-
info "tmux-claude already installed at $marker — skipping"
|
|
486
|
+
info "tmux-claude already installed at $marker — skipping curl"
|
|
487
|
+
upstream_present=1
|
|
393
488
|
elif have curl; then
|
|
394
489
|
info "installing canonical tmux-claude setup (agentik-os/tmux-claude)…"
|
|
395
490
|
# We pipe through `bash -s -- --no-prompt` so the install doesn't ask
|
|
@@ -398,6 +493,7 @@ step_tmux_config() {
|
|
|
398
493
|
if curl -fsSL "$installer_url" 2>>"$LOG_FILE" \
|
|
399
494
|
| bash -s -- --no-prompt >>"$LOG_FILE" 2>&1; then
|
|
400
495
|
ok "tmux-claude installed (~/.tmux/scripts/, ~/.tmux.conf)"
|
|
496
|
+
upstream_present=1
|
|
401
497
|
else
|
|
402
498
|
err "tmux-claude install failed — falling back to bundled pro profile"
|
|
403
499
|
_tmux_fallback_pro_config
|
|
@@ -407,6 +503,28 @@ step_tmux_config() {
|
|
|
407
503
|
_tmux_fallback_pro_config
|
|
408
504
|
fi
|
|
409
505
|
|
|
506
|
+
# v0.19.43 — wire the Omega add-on AFTER an upstream tmux-claude install
|
|
507
|
+
# succeeds (or was already present). Without this step the upstream
|
|
508
|
+
# ~/.tmux.conf has NO `source-file` line for the OmegaOS add-on, so the
|
|
509
|
+
# Alt+O / Ctrl-b o binds never get sourced. install_into_home_tmux_conf
|
|
510
|
+
# detects the tmux-claude markers and falls into the
|
|
511
|
+
# preserved-tmux-claude branch — drops omega-tmux-add.conf and appends
|
|
512
|
+
# the source-file line at the end of ~/.tmux.conf.
|
|
513
|
+
# The fallback path already wires the add-on via _tmux_fallback_pro_config
|
|
514
|
+
# → install_into_home_tmux_conf, so we only need to do it here for the
|
|
515
|
+
# happy path.
|
|
516
|
+
if [ "$upstream_present" = "1" ]; then
|
|
517
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE" || warn "Omega tmux add-on wire failed (non-fatal)"
|
|
518
|
+
import os
|
|
519
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
520
|
+
from omega_engine.tmux import install_into_home_tmux_conf
|
|
521
|
+
result = install_into_home_tmux_conf(profile="pro")
|
|
522
|
+
print(f" Omega tmux wired: mode={result['mode']}")
|
|
523
|
+
print(f" written: {result['written']}")
|
|
524
|
+
print(f" bundled copy: {result['bundled_copy']}")
|
|
525
|
+
PY
|
|
526
|
+
fi
|
|
527
|
+
|
|
410
528
|
# Always also drop the bundled config under $OMEGA_HOME so `omega tmux
|
|
411
529
|
# install --profile pro` later remains a working manual recovery path.
|
|
412
530
|
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
@@ -585,6 +703,15 @@ for entry in missing:
|
|
|
585
703
|
elif pkg == "dnf":
|
|
586
704
|
rc, out = _run(["sudo", "dnf", "install", "-y", "-q", install[pkg]])
|
|
587
705
|
attempt = f"dnf install {install[pkg]}"
|
|
706
|
+
elif pkg == "pacman":
|
|
707
|
+
rc, out = _run(["sudo", "pacman", "-S", "--noconfirm", "--needed", install[pkg]])
|
|
708
|
+
attempt = f"pacman -S {install[pkg]}"
|
|
709
|
+
elif pkg == "apk":
|
|
710
|
+
rc, out = _run(["sudo", "apk", "add", "--no-cache", install[pkg]])
|
|
711
|
+
attempt = f"apk add {install[pkg]}"
|
|
712
|
+
elif pkg == "zypper":
|
|
713
|
+
rc, out = _run(["sudo", "zypper", "--non-interactive", "install", "-y", install[pkg]])
|
|
714
|
+
attempt = f"zypper install {install[pkg]}"
|
|
588
715
|
elif "npm_global" in install and shutil.which("npm"):
|
|
589
716
|
rc, out = _run(["npm", "install", "-g", "--silent", install["npm_global"]])
|
|
590
717
|
attempt = f"npm install -g {install['npm_global']}"
|
|
@@ -1107,6 +1234,32 @@ _claude_plugins_prompt_checklist() {
|
|
|
1107
1234
|
fi
|
|
1108
1235
|
}
|
|
1109
1236
|
|
|
1237
|
+
# --- 47 -----------------------------------------------------------------------
|
|
1238
|
+
#
|
|
1239
|
+
# step_paperclip — register OmegaOS as the "omegaos" company with Paperclip.
|
|
1240
|
+
#
|
|
1241
|
+
# v0.19.43 — auto-runs at install time so the user doesn't have to type
|
|
1242
|
+
# `omega paperclip register` manually. Idempotent: if the 14 agents are
|
|
1243
|
+
# already registered, re-runs are a no-op content-equality check.
|
|
1244
|
+
#
|
|
1245
|
+
# This step does NOT install the Paperclip dashboard binary itself — that
|
|
1246
|
+
# remains opt-in via `omega tool install paperclipai`. It only writes the
|
|
1247
|
+
# company.json + per-agent JSON files at ~/.paperclip/companies/omegaos/
|
|
1248
|
+
# so Paperclip can SEE OmegaOS as soon as the operator starts the daemon.
|
|
1249
|
+
step_paperclip() {
|
|
1250
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
1251
|
+
import os
|
|
1252
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1253
|
+
from omega_engine import paperclip_bridge as PB
|
|
1254
|
+
result = PB.register()
|
|
1255
|
+
print(f" Paperclip company registered: omegaos")
|
|
1256
|
+
print(f" agents written: {result.get('agents_written', 0)}")
|
|
1257
|
+
print(f" workspaces written: {result.get('workspaces_written', 0)}")
|
|
1258
|
+
print(f" paperclip_home: {result.get('paperclip_home', '?')}")
|
|
1259
|
+
PY
|
|
1260
|
+
return $?
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1110
1263
|
# --- 50 -----------------------------------------------------------------------
|
|
1111
1264
|
step_telegram() {
|
|
1112
1265
|
# Two distinct bots in the corrected v0.19.14 model:
|
|
@@ -1268,7 +1421,14 @@ step_accounts() {
|
|
|
1268
1421
|
# we skip and the operator wires providers later via env or `omega account`.
|
|
1269
1422
|
step_providers() {
|
|
1270
1423
|
if [ -z "${MANIFEST:-}" ] || [ ! -f "$MANIFEST" ]; then
|
|
1271
|
-
|
|
1424
|
+
# v0.19.43 — used to skip silently, leaving the runtime ModelRouter
|
|
1425
|
+
# with no router.yaml. Now auto-generate one from the live providers
|
|
1426
|
+
# catalog: any provider whose primary env var is set OR whose vault
|
|
1427
|
+
# secret exists is included. Oauth/local providers are always
|
|
1428
|
+
# included (no key needed).
|
|
1429
|
+
info "no manifest providers — auto-discovering from catalog"
|
|
1430
|
+
python3 "$OMEGA_REPO/bootstrap/lib/manifest-helpers.py" providers-from-catalog "$OMEGA_HOME" \
|
|
1431
|
+
| sed 's/^/ /'
|
|
1272
1432
|
return 0
|
|
1273
1433
|
fi
|
|
1274
1434
|
python3 "$OMEGA_REPO/bootstrap/lib/manifest-helpers.py" providers "$MANIFEST" "$OMEGA_HOME" \
|
|
@@ -1337,17 +1497,22 @@ step_first_project() {
|
|
|
1337
1497
|
|
|
1338
1498
|
# --- 59 -----------------------------------------------------------------------
|
|
1339
1499
|
#
|
|
1340
|
-
#
|
|
1500
|
+
# step_aisb_session — guarantee one always-on AISB master chat window.
|
|
1341
1501
|
#
|
|
1342
|
-
#
|
|
1343
|
-
#
|
|
1344
|
-
#
|
|
1345
|
-
#
|
|
1346
|
-
#
|
|
1502
|
+
# v0.19.43 — RENAMED from step_hermes_session (which was a misnomer: it
|
|
1503
|
+
# spawned the AISB master chat, not Hermès). v0.19.43 also moved the
|
|
1504
|
+
# chat from a standalone tmux session to a WINDOW inside the Omega
|
|
1505
|
+
# master session (Omega:aisb). spawn_aisb_chat now returns "Omega:aisb"
|
|
1506
|
+
# and spawns the Omega master if needed.
|
|
1347
1507
|
#
|
|
1348
|
-
#
|
|
1508
|
+
# This is the operator's terminal-side conversation entry point —
|
|
1509
|
+
# critical when Telegram isn't wired (minimal profile, or chat_id not
|
|
1510
|
+
# yet set), and still useful when it IS wired (an always-attached local
|
|
1511
|
+
# fallback that does not need internet).
|
|
1512
|
+
#
|
|
1513
|
+
# Idempotent: if the aisb window already exists, we just print attach
|
|
1349
1514
|
# instructions.
|
|
1350
|
-
|
|
1515
|
+
step_aisb_session() {
|
|
1351
1516
|
if ! have tmux; then
|
|
1352
1517
|
err "tmux not installed — step_system_deps should have caught this"
|
|
1353
1518
|
return 1
|
|
@@ -1359,13 +1524,16 @@ step_hermes_session() {
|
|
|
1359
1524
|
import os
|
|
1360
1525
|
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1361
1526
|
from omega_engine import tmux
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1527
|
+
# v0.19.43 — AISB master chat is now a WINDOW under the Omega master
|
|
1528
|
+
# session. omega_window_alive() checks the aisb window specifically;
|
|
1529
|
+
# attach_command() returns the right `tmux attach -t Omega:aisb` form.
|
|
1530
|
+
target = "Omega:aisb"
|
|
1531
|
+
if tmux.omega_window_alive("aisb"):
|
|
1532
|
+
print(f" AISB chat window already running: {target}")
|
|
1365
1533
|
else:
|
|
1366
1534
|
tmux.spawn_aisb_chat("$OMEGA_HOME")
|
|
1367
|
-
print(f" spawned: {
|
|
1368
|
-
print(f" attach: {tmux.attach_command(
|
|
1535
|
+
print(f" spawned: {target} (always-on AISB master conversation)")
|
|
1536
|
+
print(f" attach: {tmux.attach_command(target)}")
|
|
1369
1537
|
print(f" detach: Ctrl-b d (session keeps running)")
|
|
1370
1538
|
PY
|
|
1371
1539
|
return $?
|
|
@@ -1373,6 +1541,63 @@ PY
|
|
|
1373
1541
|
|
|
1374
1542
|
# --- 60 -----------------------------------------------------------------------
|
|
1375
1543
|
#
|
|
1544
|
+
# step_hermes_session — spawn the always-on Hermès chat window, IF the
|
|
1545
|
+
# vault key is present.
|
|
1546
|
+
#
|
|
1547
|
+
# v0.19.43 — separate step from step_aisb_session (which was previously
|
|
1548
|
+
# misnamed step_hermes_session but spawned AISB). Hermès has its own
|
|
1549
|
+
# credential isolation contract (ANTHROPIC_API_KEY_HERMES from the
|
|
1550
|
+
# vault — see omega_engine/hermes.py for the resolution chain). If the
|
|
1551
|
+
# vault key is missing we SKIP this step instead of falling back to Max
|
|
1552
|
+
# OAuth — operators who want Hermès running 24/7 must wire the key
|
|
1553
|
+
# explicitly. (Interactive `omega hermes` still falls through to Max
|
|
1554
|
+
# OAuth as a last resort so users can experiment without a paid key.)
|
|
1555
|
+
step_hermes_session() {
|
|
1556
|
+
if ! have tmux; then
|
|
1557
|
+
err "tmux not installed — step_system_deps should have caught this"
|
|
1558
|
+
return 1
|
|
1559
|
+
fi
|
|
1560
|
+
local omega="$OMEGA_HOME/Agentik_Tools/bin/omega"
|
|
1561
|
+
[ -x "$omega" ] || { err "omega CLI not found at $omega — step_engine incomplete"; return 1; }
|
|
1562
|
+
|
|
1563
|
+
local key_present=0
|
|
1564
|
+
if PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>/dev/null
|
|
1565
|
+
from pathlib import Path
|
|
1566
|
+
import os, sys
|
|
1567
|
+
home = Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
|
|
1568
|
+
try:
|
|
1569
|
+
from omega_engine.vault import vault_read
|
|
1570
|
+
k = vault_read(home, "ANTHROPIC_API_KEY_HERMES")
|
|
1571
|
+
sys.exit(0 if (k and k.strip()) else 1)
|
|
1572
|
+
except Exception:
|
|
1573
|
+
sys.exit(1)
|
|
1574
|
+
PY
|
|
1575
|
+
then
|
|
1576
|
+
key_present=1
|
|
1577
|
+
fi
|
|
1578
|
+
|
|
1579
|
+
if [ "$key_present" = "1" ]; then
|
|
1580
|
+
PYTHONPATH="$OMEGA_HOME/Agentik_Engine" python3 - <<PY 2>>"$LOG_FILE"
|
|
1581
|
+
import os
|
|
1582
|
+
os.environ["OMEGA_HOME"] = "$OMEGA_HOME"
|
|
1583
|
+
from omega_engine import tmux
|
|
1584
|
+
target = "Omega:hermes"
|
|
1585
|
+
if tmux.omega_window_alive("hermes"):
|
|
1586
|
+
print(f" Hermès chat window already running: {target}")
|
|
1587
|
+
else:
|
|
1588
|
+
tmux.spawn_hermes_chat("$OMEGA_HOME")
|
|
1589
|
+
print(f" spawned: {target} (always-on Hermès conversation)")
|
|
1590
|
+
print(f" attach: {tmux.attach_command(target)}")
|
|
1591
|
+
PY
|
|
1592
|
+
else
|
|
1593
|
+
info " Hermès vault key (ANTHROPIC_API_KEY_HERMES) absent — skipping persistent session"
|
|
1594
|
+
info " wire it with: omega vault write ANTHROPIC_API_KEY_HERMES sk-ant-..."
|
|
1595
|
+
fi
|
|
1596
|
+
return 0
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
# --- 65 -----------------------------------------------------------------------
|
|
1600
|
+
#
|
|
1376
1601
|
# step_services — install the 24/7 service layer.
|
|
1377
1602
|
#
|
|
1378
1603
|
# Linux: write 3 systemd user units, `daemon-reload`, then `enable --now`.
|
|
@@ -38,6 +38,15 @@ v7.0 adds R-XX ownership and updated tooling without renaming any agent.
|
|
|
38
38
|
|
|
39
39
|
## Architecture
|
|
40
40
|
|
|
41
|
+
> **L0 Paperclip governance.** OmegaOS is registered as the "omegaos"
|
|
42
|
+
> company at `~/.paperclip/companies/omegaos/` with 14 agents (Hermès +
|
|
43
|
+
> 13 AISB). Each agent has a fixed reporting line (Hermès → top; Niobe
|
|
44
|
+
> → Hermès; Oracle/Construct/Morpheus/Architect → Oracle's chain).
|
|
45
|
+
> Agents should call `paperclip_bridge.send_heartbeat()` at meaningful
|
|
46
|
+
> lifecycle events (spawn / mission complete / blocked) so the
|
|
47
|
+
> Paperclip dashboard surfaces live status to the operator. This is
|
|
48
|
+
> additive — no AISB agent depends on Paperclip being running.
|
|
49
|
+
|
|
41
50
|
```
|
|
42
51
|
USER (Telegram)
|
|
43
52
|
|
|
|
@@ -274,6 +283,10 @@ Handoff templates: `protocols/handoff-templates.md`
|
|
|
274
283
|
Shared protocol: `protocols/shared-protocol.md`
|
|
275
284
|
LMC (Lead-Manager-Checker) protocol: `protocols/lmc-protocol.md` for SERAPH-grade audits.
|
|
276
285
|
|
|
286
|
+
**Fresh context handoff** — every brief dispatched downstream MUST be self-contained:
|
|
287
|
+
Mission / Purpose / Context / Done Criteria / Verify Command. The receiving agent
|
|
288
|
+
never sees this conversation; if it isn't written into the brief, it does not exist.
|
|
289
|
+
|
|
277
290
|
---
|
|
278
291
|
|
|
279
292
|
## AISB Nerve (v2.0, Omega-aware)
|