+ );
+}
+
diff --git a/db/sql/038_node_guardian_seed.sql b/db/sql/038_node_guardian_seed.sql
new file mode 100644
index 00000000..cf37f858
--- /dev/null
+++ b/db/sql/038_node_guardian_seed.sql
@@ -0,0 +1,23 @@
+-- Оновлення типів агентів для Node Guardian та Node Steward
+
+-- NODE 1
+UPDATE agents
+SET kind = 'node_guardian'
+WHERE id = 'monitor-node1';
+
+UPDATE agents
+SET kind = 'node_steward'
+WHERE id = 'node-steward-node1';
+
+-- NODE 2
+UPDATE agents
+SET kind = 'node_guardian'
+WHERE id = 'monitor-node2';
+
+UPDATE agents
+SET kind = 'node_steward'
+WHERE id = 'node-steward-node2';
+
+-- Додати теги (опціонально, якщо колонка tags існує і це масив текстів)
+-- UPDATE agents SET tags = array_append(tags, 'role:guardian') WHERE id = 'monitor-node1' AND NOT ('role:guardian' = ANY(tags));
+
diff --git a/docs/users/nodes/NODE_GUARDIAN_AND_STEWARD.md b/docs/users/nodes/NODE_GUARDIAN_AND_STEWARD.md
new file mode 100644
index 00000000..779d3b7a
--- /dev/null
+++ b/docs/users/nodes/NODE_GUARDIAN_AND_STEWARD.md
@@ -0,0 +1,70 @@
+# Node Guardian & Node Steward
+
+**Дата:** 29 листопада 2025
+**Статус:** Впроваджено (Task 038)
+
+У екосистемі DAARION кожна нода має два ключові "обличчя" — спеціалізованих агентів, які відповідають за її функціонування та представлення у мережі.
+
+---
+
+## 1. Ролі
+
+### 🛡️ Node Guardian (Технічний наглядач)
+**Відповідальність:**
+* Моніторинг інфраструктури (CPU, RAM, Disk, GPU).
+* Стан сервісів (Docker, Systemd).
+* Безпека та алерти.
+* Автоматична реакція на інциденти (в межах дозволеного).
+
+**Тип агента:** `node_guardian` (або `infra_monitor`).
+
+### 🗣️ Node Steward (Хазяїн ноди)
+**Відповідальність:**
+* Публічне представлення ноди як "громадянина".
+* Комунікація з іншими учасниками мережі.
+* Управління конфігурацією та правилами (Governance).
+* "Human Interface" до ноди.
+
+**Тип агента:** `node_steward` (або `infra_ops`).
+
+---
+
+## 2. Як призначити
+
+Агенти автоматично визначаються системою (`city-service`) за наступним алгоритмом:
+
+1. **Пошук за типом (`kind`):**
+ * Система шукає агентів, прив'язаних до цієї ноди (`node_id`), які мають `kind = 'node_guardian'` або `'node_steward'`.
+
+2. **Fallback (сумісність):**
+ * Якщо спеціалізованих типів не знайдено, система шукає `infra_monitor` (як Guardian) та `infra_ops` (як Steward).
+
+3. **Node Cache (Legacy):**
+ * Якщо динамічний пошук не дав результатів, використовується закешоване значення з таблиці `node_registry.nodes` (якщо воно було встановлено вручну).
+
+### SQL для призначення (приклад)
+
+```sql
+-- Призначити Guardian
+UPDATE agents
+SET kind = 'node_guardian'
+WHERE id = 'my-monitor-agent-id';
+
+-- Призначити Steward
+UPDATE agents
+SET kind = 'node_steward'
+WHERE id = 'my-steward-agent-id';
+```
+
+---
+
+## 3. Відображення в UI
+
+### Node Dashboard (`/nodes/[nodeId]`)
+У кабінеті ноди (як повному, так і базовому профілі) відображається картка **"Node Guardian & Steward"**:
+* Показує імена та ролі агентів.
+* Посилання на їх **Публічний профіль** (`/citizens/[slug]`).
+* Посилання на **Кабінет агента** (`/agents/[id]`).
+
+Це дозволяє оператору швидко перейти до налаштувань агента або почати діалог з ним.
+
diff --git a/services/city-service/repo_city.py b/services/city-service/repo_city.py
index 243ede62..dc6c45e6 100644
--- a/services/city-service/repo_city.py
+++ b/services/city-service/repo_city.py
@@ -1665,6 +1665,40 @@ async def get_node_by_id(node_id: str) -> Optional[dict]:
else:
data["steward_agent"] = None
+ # TASK 038: Dynamic discovery of Node Guardian / Steward if cache is empty
+ if not data["guardian_agent"] or not data["steward_agent"]:
+ dynamic_agents = await pool.fetch("""
+ SELECT id, display_name, kind, public_slug
+ FROM agents
+ WHERE node_id = $1
+ AND (kind IN ('node_guardian', 'node_steward') OR kind IN ('infra_monitor', 'infra_ops'))
+ AND COALESCE(is_archived, false) = false
+ """, node_id)
+
+ if not data["guardian_agent"]:
+ # Prefer 'node_guardian', fallback to 'infra_monitor'
+ guardian = next((a for a in dynamic_agents if a['kind'] == 'node_guardian'),
+ next((a for a in dynamic_agents if a['kind'] == 'infra_monitor'), None))
+ if guardian:
+ data["guardian_agent"] = {
+ "id": guardian["id"],
+ "name": guardian["display_name"],
+ "kind": guardian["kind"],
+ "slug": guardian["public_slug"]
+ }
+
+ if not data["steward_agent"]:
+ # Prefer 'node_steward', fallback to 'infra_ops'
+ steward = next((a for a in dynamic_agents if a['kind'] == 'node_steward'),
+ next((a for a in dynamic_agents if a['kind'] == 'infra_ops'), None))
+ if steward:
+ data["steward_agent"] = {
+ "id": steward["id"],
+ "name": steward["display_name"],
+ "kind": steward["kind"],
+ "slug": steward["public_slug"]
+ }
+
# Clean up intermediate fields
for key in ["guardian_name", "guardian_kind", "guardian_slug",
"steward_name", "steward_kind", "steward_slug"]: