Stan modułu w cyklu życia. Jedyne pole z zamkniętym słownikiem.
Bo stan to nie opis — to diagnoza.
"incubation"// kiełkuje, jeszcze w ziemi"active"// rośnie, jest używany"mature"// stabilny, sprawdzony"dormant"// uśpiony, może wrócić"archived"// zamknięty, pamiątka
lineageobject · required
Rodowód modułu. Skąd się wziął, kto go urodził, pod jakim kontraktem.
Najgłębsza pamięć w manifeście.
seed_sessionstring
Nazwa sesji która urodziła moduł — ludzki identyfikator (np. "Złota Helisa ✨"). Pusty string jeśli nieznana.
parent_sidstring · uuid | ""
UUID poprzedniej sesji która dała kontekst tej sesji. Pusty string jeśli sesja inauguracyjna. Buduje graf drzewa decyzji w Operator Chain.
contract_shasha-256
Pieczęć operatora. Ta sama wartość dla wszystkich modułów jednego operatora. Generowana raz, w AIWPass.
contributorsarray · actor+role+chat_id
Kto wniósł wkład. Ludzie i modele AI razem. Każdy kontrybutor nosi własny chat_id. Role swobodne: operator, architect, seed, refiner, builder, contributor.
signatureobject · optional
Opcjonalna pieczęć kryptograficzna — actor + sha256. Generowana przez AIWPass.
filesobject · required
Co jest w module. Pięć pól stałych.
Dla single-file components i backend pozostają puste.
Bootstrap to esencja wiedzy dla modelu AI — zamiast wczytywać HTML, model czyta jeden plik .md.
entrystring · path
Główny plik wejściowy. Zawsze wypełniony.
docsstring · path
Plik dokumentacji. Pusty string jeśli brak.
componentsarray · path+role
Lista plików współtworzących moduł. Pusta tablica dla single-file.
bootstrapstring · path · .md
Plik bootstrapowy dla modelu AI.
Esencja wiedzy o module w Markdown — architektura, konwencje, kluczowe decyzje.
Model wczytuje ten jeden plik zamiast parsować HTML.
Konwencja nazwy: <id>-boot.md w folderze modułu.
Pusty string jeśli moduł nie potrzebuje bootstrapa AI.
runtimeobject · required
Tryb pracy artefaktu. Struktura stała.
Dwa tryby: demo (port 0 — artefakt operuje lokalnie na mockach)
i produkcyjny (port > 0 — artefakt łączy się z silnikiem FastAPI).
Uprawnienia AI leżą w AIWPass — tu tylko deklaracja czy kanał jest otwarty.
data_pathstring
Ścieżka do JSONów modułu. Konwencja: .data/<id>/. Pusty string jeśli moduł nie handluje danymi.
ioarray · read | write
Operacje na danych. Pusta tablica jeśli moduł nie handluje JSONami.
portinteger · 0–65535
Port silnika FastAPI. 0 = tryb demo (brak backendu).
Wartość > 0 = tryb produkcyjny — artefakt łączy się z tym portem.
Alokacja portów per moduł → zakładka Backend.
consumersarray · human | ai
"human" — przeglądarka/operator. "ai" — model AI ma otwarty dostęp (szczegółowe uprawnienia w AIWPass).
operator_statestring
Stan operatora w momencie sesji — focused, tired, flow, chaotic. Do korelacji ze metrykami sesji.
i18nobject · required
Internacjonalizacja. Plik tłumaczeń: <id>-lang.json. Domyślny język zawsze pl. Selektor pojawia się tylko gdy available.length > 1. Wzorzec selektora → AiWSchema · Overlays.
Z czym moduł rozmawia.
Graf wyłaniający się z manifestów — nie drzewo folderów, semantyczna sieć.
Typ relacji jako czasownik 3 os. l.poj. — słownik otwarty.
Każdy moduł opisuje sam siebie — struktura wyłania się z manifestów, nie z hierarchii folderów. To jest samo w formie technicznej.
Metryki zostają w sesjach. Manifest pozostaje deklaratywny — mówi czym moduł jest, nie jak się ma.
Contract SHA w każdym manifeście to cicha deklaracja — "powstałem pod tą umową". Lineage nie kłamie.
Relacje typowane robią różnicę między listą plików a systemem znaczeń. AGI czytająca repo nie parsuje drzewa — buduje graf.
Port w manifeście to nie metadane — to żywy adres. Gdy port > 0, artefakt wie gdzie szukać swojego Rdzenia. Protokół połączenia → zakładki Frontend i Backend.
Bootstrap to most między człowiekiem a modelem. HTML jest dla przeglądarki — Markdown jest dla AI. Jeden plik niesie esencję modułu bez narzutu renderowania. Model czyta kontekst, nie strukturę.
Artefakt jest suwerenny.
Działa zawsze — z backendem i bez.
Backend rozszerza możliwości, ale nie warunkuje istnienia.
Połączenie z Rdzeniem jest cichą umową.
Gdy Rdzeń znika — artefakt bezgłośnie wraca do mocka.
Użytkownik nigdy nie zobaczy błędu połączenia.
Zasady · offline-first
Backend jest opcjonalny. Ten sam plik HTML działa: podwójnym kliknięciem (file://), przez serwer (http://localhost:PORT) i wysłany jako plik. Logika detekcji trybu → jednej linii JS.
Wskaźnik LIVE / MOCK — w hud-l jako element <span id="live-dot">. Zielony "live" gdy połączenie działa, szary "mock" gdy fallback. Nigdy komunikat o błędzie.
Mock data zawsze zdefiniowana. Funkcja getMock() zwraca sensowne dane — animacja trwa nieprzerwanie bez względu na stan backendu.
Silent fail. Każdy fetch i każde WS zdarzenie opakowane w try/catch. Wyjątek trafia do setLive(false), nie do konsoli użytkownika.
Detekcja trybu · API
const APIpierwsza linia JS
Jedna linia wykrywa czy artefakt działa przez serwer.
Null = tryb offline — artefakt używa mocków i localStorage.
Wszystkie fetch/WS wywołania sprawdzają API przed wykonaniem.
const API = location.protocol === 'file:' ? null : `${location.origin}/api`;
const MODULE_ID = 'breath'; // id z manifest.jsonconst PORT = 8006; // port z manifest.json → runtime.port
REST Polling · MVP · bieżący wzorzec
fetchState / fetchLogpolling · 4s / 12s
Obecny wzorzec dla modułów z backendem REST.
State co 4 sekundy, log co 12 sekund — zbalansowany puls bez przeciążania serwera.
Przy przejściu na WebSocket — polling zatrzymujemy.
Klasa zarządzająca połączeniem WebSocket dla konkretnego artefaktu.
Automatyczny reconnect z wykładniczym czasem oczekiwania (1s → 2s → 4s → … max 30s).
Gdy serwer wraca — artefakt cicho się podłącza.
Polling zastępujemy tym gdy moduł gotowy na WebSocket.
Puls systemu. Wysyłany przez silnik co ~1 sekundę do wszystkich podłączonych artefaktów. Zawiera telemetrię hardware — artefakty mogą reagować wizualnie (temperatura CPU → kolor świateł, obciążenie RAM → pulsowanie).
Zmiana stanu wysyłana do konkretnego artefaktu (przez target). Artefakt uruchamia animację przejścia do nowego stanu. Ignoruj jeśli target !== MODULE_ID.
Odpowiedź na ciężkie zadanie zlecone przez artefakt (np. generowanie labiryntu). Rdzeń liczy w tle (BackgroundTask) i odsyła wynik gdy gotowy. Artefakt dopasowuje po task_id.
Polecenie wysyłane przez artefakt do silnika. Tylko przez WebSocket. Dla prostych operacji preferuj REST POST — ACTION rezervowany dla poleceń wymagających szybkiej odpowiedzi lub sesji.
Każdy moduł ma własny silnik — osobny FastAPI na osobnym porcie.
Nie jeden monolit, lecz konstelacja niezależnych Rdzeni.
Silnik jest opcjonalny. Artefakt istnieje bez niego.
Gdy silnik działa — artefakt go subskrybuje.
Port w manifeście to adres subskrypcji.
Protokół obsługuje dwie topologie — dedykowany port per moduł
i wspólny port dla wielu artefaktów.
Wybór należy do architekta. Kod silnika jest identyczny w obu wariantach.
Alokacja portów · engines/ per moduł
Moduł (engines/)
Port
Status
arena
8001
active
caves
8002
active
morph
8003
active
horizon
8004
active
breath
8005
incubation
następny
8006+
—
Struktura katalogu silnika
engines/<id>/
korzeń silnika (uv workspace)
engines/<id>/<id>/
pakiet Python
├── __init__.py
marker pakietu
├── main.py
FastAPI app + endpointy
└── engine.py
logika biznesowa (opcjonalnie)
pyproject.toml
zależności UV
.data/<id>/
bazy danych (poza engines/)
.logs/<id>/
logi (poza engines/)
Dane poza kodem. Silnik odczytuje bazę ze ścieżki ../../.data/<id>/ — nigdy nie trzyma danych w engines/<id>/. Zasada lustrzana: engines/ ↔ apps/ ↔ .data/ ↔ .logs/
CORS otwarty na dev.allow_origins=["*"] na czas developmentu — artefakt może być otwierany z file:// lub różnych portów. Zaostrz w produkcji.
Uruchamianie.cd engines/<id> && uv run uvicorn <id>.main:app --port PORT --reload
Dwie topologie — ten sam kod.Dedykowany port per moduł (domyślna konwencja, porty 8001–8006+) — jeden silnik, jeden artefakt. Wspólny port dla wielu artefaktów — jeden silnik, wiele artefaktów rozróżnianych po artifact_id w URL. WebSocket /ws/{artifact_id} i REST /api/{module_id}/ obsługują oba warianty bez zmian w kodzie.
REST · wzorzec endpointów
GET /api/<id>/statebieżący stan
Podstawowy endpoint każdego modułu z backendem. Zwraca bieżący stan agenta — jedną czynność w locie. Artefakt polluje co 4 sekundy.
Rejestr aktywnych połączeń. Klucz to artifact_id — unikatowy identyfikator artefaktu (z manifest.json).
Broadcast idzie do wszystkich, send_to do konkretnego.
Padające połączenia usuwane cicho z rejestru.
Słownik dict[str, WebSocket] naturalnie obsługuje oba warianty topologii —
w modelu dedykowanym rejestr ma zawsze jeden wpis, w modelu wspólnym portów — dowolną liczbę.
classConnectionManager:
def__init__(self):
self.active: dict[str, WebSocket] = {}
async defconnect(self, artifact_id: str, ws: WebSocket):
await ws.accept()
self.active[artifact_id] = ws
defdisconnect(self, artifact_id: str):
self.active.pop(artifact_id, None)
async defbroadcast(self, data: dict):
dead = []
for aid, ws in self.active.items():
try: await ws.send_json(data)
except: dead.append(aid)
for aid in dead: self.disconnect(aid)
async defsend_to(self, artifact_id: str, data: dict):
if ws := self.active.get(artifact_id):
try: await ws.send_json(data)
except: self.disconnect(artifact_id)
AiWBroadcastpuls systemu · /ws/broadcast
Pętla telemetrii uruchamiana przy starcie silnika. Wysyła BROADCAST_SIGNAL co sekundę do wszystkich podłączonych artefaktów. Artefakty mogą używać danych CPU/MEM do efektów wizualnych.
WebSocket dla konkretnego artefaktu — identyfikowany po artifact_id w URL.
Artefakt może wysyłać ACTION, silnik odpowiada STATE_UPDATE lub TASK_READY.
Rejestruje połączenie w ConnectionManager pod kluczem artifact_id.
Topologia dedykowana: jeden artefakt na własnym porcie, rejestr zawsze jednoelementowy.
Topologia wspólna: wiele artefaktów łączy się pod różnymi artifact_id do jednego silnika —
send_to i broadcast działają identycznie w obu wariantach.
@app.websocket("/ws/{artifact_id}")
async defws_protocol(ws: WebSocket, artifact_id: str):
await manager.connect(artifact_id, ws)
try:
while True:
data = await ws.receive_json()
if data.get("type") == "ACTION":
await handle_action(artifact_id, data, manager)
except WebSocketDisconnect:
manager.disconnect(artifact_id)
Szablon Backend · main.py · kopiuj · obsługuje obie topologie
# ── AIWHISPERERS · ENGINE TEMPLATE ──────────────────────────────────────────# Podmień MODULE_ID i PORT. Zaimplementuj logikę w engine.py.# Topologia A — dedykowany port: jeden moduł, jeden silnik (domyślna konwencja 8001–8006+).# Topologia B — wspólny port: wiele modułów łączy się do jednego silnika po artifact_id w URL.# Kod silnika jest identyczny w obu — różni się tylko konfiguracja uruchomienia.from fastapi import FastAPI, WebSocket, WebSocketDisconnect, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
import asyncio, psutil, time
MODULE_ID = "breath"
PORT = 8006# ── ConnectionManager ────────────────────────────────────────────────────────classConnectionManager:
def__init__(self): self.active: dict[str, WebSocket] = {}
async defconnect(self, aid: str, ws: WebSocket):
await ws.accept(); self.active[aid] = ws
defdisconnect(self, aid: str): self.active.pop(aid, None)
async defbroadcast(self, data: dict):
dead = []
for aid, ws in self.active.items():
try: await ws.send_json(data)
except: dead.append(aid)
for aid in dead: self.disconnect(aid)
async defsend_to(self, aid: str, data: dict):
if ws := self.active.get(aid):
try: await ws.send_json(data)
except: self.disconnect(aid)
manager = ConnectionManager()
# ── Telemetry broadcast loop ──────────────────────────────────────────────────async deftelemetry_loop():
while True:
await manager.broadcast({
"type": "BROADCAST_SIGNAL",
"telemetry": { "cpu": psutil.cpu_percent(), "mem": psutil.virtual_memory().percent }
})
await asyncio.sleep(1)
@asynccontextmanagerasync deflifespan(app: FastAPI):
asyncio.create_task(telemetry_loop())
yield# ── FastAPI app ───────────────────────────────────────────────────────────────
app = FastAPI(lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
)
# ── REST · state ──────────────────────────────────────────────────────────────# module_id w URL — topologia A: zawsze MODULE_ID; topologia B: routing per moduł.@app.get("/api/{module_id}/state")
async defget_state(module_id: str):
return {
"activity_key": "mysli",
"started_at": int(time.time() * 1000),
"duration_ms": 9000,
"metrics": {}
}
# ── REST · log ────────────────────────────────────────────────────────────────@app.get("/api/{module_id}/log")
async defget_log(module_id: str, limit: int = 40):
return [] # zaimplementuj odczyt z .data/<id>/# ── WebSocket · AiWBroadcast (opcjonalny) ─────────────────────────────────────@app.websocket("/ws/broadcast")
async defws_broadcast(ws: WebSocket):
await manager.connect("broadcast", ws)
try:
while True: await asyncio.sleep(60) # keepaliveexcept WebSocketDisconnect: manager.disconnect("broadcast")
# ── WebSocket · AiWProtocol (kanał artefaktu) ─────────────────────────────────# artifact_id z URL — topologia A: zawsze MODULE_ID; topologia B: dowolny id klienta.@app.websocket("/ws/{artifact_id}")
async defws_protocol(ws: WebSocket, artifact_id: str):
await manager.connect(artifact_id, ws)
try:
while True:
data = await ws.receive_json()
if data.get("type") == "ACTION":
await handle_action(artifact_id, data, manager)
except WebSocketDisconnect: manager.disconnect(artifact_id)
async defhandle_action(artifact_id: str, data: dict, mgr: ConnectionManager):
# zaimplementuj obsługę akcji; mgr.send_to(artifact_id, ...) lub mgr.broadcast(...)pass# ── Uruchamianie ──────────────────────────────────────────────────────────────# Topologia A — dedykowany port per moduł (domyślna konwencja):# cd engines/breath && uv run uvicorn breath.main:app --port 8005 --reload# Topologia B — wspólny port dla wielu modułów:# cd engines/hub && uv run uvicorn hub.main:app --port 8000 --reload# (artefakty różnych modułów łączą się po /ws/{artifact_id} i /api/{module_id}/)
_protocol · backend · v1.0 · AiWhisperers · 2026
about · refleksja modelu · sesja protokołu
O tym schemacie
sesja: Wyrównanie Protokołu · model: Claude Sonnet 4.6 · 2026-05-02
Denis przyszedł z konkretnym problemem — AiWSchema.html był za duży,
a zakładka Manifest nie miała gdzie rozrosnąć się o dokumentację połączeń.
Zdecydowaliśmy: wydzielić Manifest + Protokół do osobnego artefaktu.
Kluczowe napięcie do rozwiązania: protocol.md mówił o "jednym Rdzeniu na jednym porcie",
a rzeczywistość CLAUDE.md pokazywała osobny engine per moduł (8001–8006).
Nie sprzeczność — ewolucja architektury. Dokumentujemy co jest,
nie co mogłoby być w teorii.
Poprawiłem też błąd w przykładach manifestu — packages/horizon/ zastąpiłem
poprawnym engines/horizon/, zgodnie z CLAUDE.md. Lineage powinien mówić prawdę.
pieczęcie · proweniencja
D
Denis · AI Whispers
iFactory 5.0 · ROOT · 2026
Operator · Architekt Podziału
Decyzja o wydzieleniu protokołu z Schematu. Idea zakładek Frontend i Backend.
Kontekst z trzech dokumentów: protocol.md, breath-api-spec.md, CLAUDE.md.
✦
Claude · Sonnet 4.6
Anthropic · Wyrównanie Protokołu · 2026
Budowniczy · Destylator Protokołu
AiWProtocol v1.0 — kompletny manifest, wzorzec AiWConnector,
ConnectionManager, szablony REST i WebSocket.
Wyrównanie architektury: port-per-artifact zamiast one-core.