legion-gaia 0.9.57 → 0.9.58

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 304d68143516d528bf4b5c72d3cc1d42395e46942e162c40566d9b8051a047af
4
- data.tar.gz: 25fcee870f9b736fa469739d13850e07e1996ef56c5f88ec99bc5701c2cf358a
3
+ metadata.gz: b1f027ab3c8daed0ec4d1721c3c88e3efc15e475f1cb24f7999ba057074c9554
4
+ data.tar.gz: 1fdc0ccfe37b653d78eec31c0b1dce6b4294235c573af402d2b8205712c2fe0a
5
5
  SHA512:
6
- metadata.gz: b783cc1c8b0ef180dae9a9eee46ca40a71dcc5de87b5ba746d225aa050a4ad7f29ed733cdf80caba41567927437cf0b541962e2b8c29d33f5bd5fab51d599aa1
7
- data.tar.gz: c60c7881c78115c0854f5b77cdec2e8d79f75daae060d2b10baca28087b44bd511fe88eb82d9ee7a0a3fc8a47932643d60b839df883970dd2e7e7f60b649b679
6
+ metadata.gz: cd0989a7ede3408c63a68b7f16a41bb6dc99c964d78811c1620d6caf50885a5c2ebed14ab7d6a90cdc7805ab99abd602469cecda522bb83a427d6e2667b6efae
7
+ data.tar.gz: 516b2c3d3defd7a2bc20e51693ffc053a82b2add2b4e709139e86b2d033a4b163dcef61d89548e0ac4edb0a2169c7a33dce5275b79c905262e1c3318366f0f31
data/.rubocop.yml CHANGED
@@ -27,7 +27,7 @@ Metrics/PerceivedComplexity:
27
27
  Max: 15
28
28
 
29
29
  Metrics/ClassLength:
30
- Max: 200
30
+ Max: 215
31
31
 
32
32
  Metrics/ModuleLength:
33
33
  Max: 200
data/AGENTS.md ADDED
@@ -0,0 +1,55 @@
1
+ # legion-gaia — Agent Notes
2
+
3
+ `legion-gaia` is the **cognitive coordination layer** of the LegionIO framework: a continuously
4
+ ticking agent runtime. It drains channel input (CLI, Microsoft Teams, Slack, HTTP) into a sensory
5
+ buffer, runs each heartbeat through a weighted pipeline of agentic cognitive phases via `lex-tick`,
6
+ and routes responses back out through schedule/presence/behavioral notification gates. See `CLAUDE.md`
7
+ for the file map and invariants; `README.md` for the user-facing tour.
8
+
9
+ ## Fast Start
10
+
11
+ ```bash
12
+ bundle install
13
+ bundle exec rspec # 0 failures required before commit
14
+ bundle exec rubocop # 0 offenses required
15
+ ```
16
+
17
+ Run **both** in full and fix everything before committing.
18
+
19
+ ## Primary Entry Points
20
+
21
+ - `lib/legion/gaia.rb` — facade (`boot`, `ingest`, `heartbeat`, `respond`, `status`, `shutdown`)
22
+ - `lib/legion/gaia/phase_wiring.rb` — `PHASE_MAP` (37 phases: 16 active + 21 dream) + `PHASE_ARGS`
23
+ - `lib/legion/gaia/registry.rb` — extension discovery, runner wiring, phase-handler management
24
+ - `lib/legion/gaia/actors/heartbeat.rb` — the periodic drain → tick actor
25
+ - `lib/legion/gaia/notification_gate.rb` + `notification_gate/` — schedule / presence / behavioral gating
26
+ - `lib/legion/gaia/channels/` — `CliAdapter`, `TeamsAdapter`, `SlackAdapter` (+ auth/webhook/signing)
27
+ - `lib/legion/gaia/router/` — hub-and-spoke `RouterBridge` / `AgentBridge` / `WorkerRouting`
28
+ - `lib/legion/gaia/routes.rb` — self-registering `/api/gaia/*` Sinatra routes
29
+ - `lib/legion/gaia/settings.rb` — `Settings.default`, the config schema
30
+
31
+ ## Guardrails / Gotchas (these prevent real bugs)
32
+
33
+ - **`lex-tick` is mandatory** — GAIA cannot run a tick without it; the heartbeat degrades gracefully
34
+ (warns once, retries) when the tick runner is unresolvable.
35
+ - **37 phases, not all always active** — phases whose runner extension isn't loaded are skipped at
36
+ wiring time. Every phase result must carry `status` (`completed`/`skipped`/`failed`) and
37
+ `elapsed_ms`; the `/api/gaia/ticks` stream depends on it.
38
+ - **Channel adapters are thin and stateless** — translate format only, no business logic, no state,
39
+ recreatable without loss. Every channel authenticates identity before input reaches GAIA
40
+ (Teams JWT/Bot Framework, Slack HMAC-SHA256).
41
+ - **Notification gate order is schedule → presence → behavioral**; critical/urgent priority bypasses
42
+ all layers. Delayed frames sit in a bounded `DelayQueue` re-evaluated each heartbeat.
43
+ - **Router mode** (`boot(mode: :router)`) boots channels only — no SensoryBuffer/cognitive
44
+ extensions. Worker allowlists are enforced for live registration and DB-backed resolution.
45
+ - **Shutdown is quiescing** — new heartbeats blocked, in-flight work drained, phase handlers return
46
+ `{ status: :skipped, reason: :gaia_shutting_down }`; never let teardown write into closed services.
47
+ - **`Legion::JSON` only** (symbol keys); inside `Legion::`, `::JSON`/`::Process` must be explicit.
48
+ Every `rescue` re-raises or `handle_exception`s; use `log.*`, never `puts`.
49
+ - **No personal/company identifiers in VCS**; never force-push.
50
+ - Settings merge is **deep** (`Legion::Settings[:gaia]` over `Settings.default`) — mutate nested keys.
51
+
52
+ ## Validation
53
+
54
+ Run targeted specs for the area you touched (`spec/legion/gaia/...`), then full `rspec` + `rubocop`
55
+ before handoff. The suite runs in-process without external infrastructure.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.58] - 2026-07-15
4
+ ### Added
5
+ - Earned bond formation: strength-based partner detection, reinforcement lifecycle, coldstart wire
6
+
3
7
  ## [0.9.57] - 2026-05-15
4
8
 
5
9
  ### Fixed
data/CLAUDE.md CHANGED
@@ -1,190 +1,87 @@
1
- # legion-gaia: Cognitive Coordination Layer for LegionIO
1
+ # legion-gaia
2
2
 
3
- **Repository Level 3 Documentation**
4
- - **Parent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
5
- - **GitHub**: https://github.com/LegionIO/legion-gaia
6
- - **Version**: 0.9.46
3
+ Cognitive coordination layer for LegionIO — a continuously ticking agent runtime. Drains channel
4
+ input into a sensory buffer, runs it through a weighted pipeline of agentic cognitive phases via
5
+ `lex-tick`, and routes responses back out through schedule/presence/behavioral notification gates.
6
+ Provides channel abstraction for multi-interface communication (CLI, Microsoft Teams, Slack).
7
7
 
8
- ## Purpose
8
+ **GitHub**: https://github.com/LegionIO/legion-gaia
9
9
 
10
- Cognitive coordination layer for LegionIO. GAIA absorbs and replaces `lex-cortex`, elevating the cognitive wiring from an extension to a core library. It drives the tick cycle, discovers and wires agentic extensions, and provides channel abstraction for multi-interface communication (CLI, Teams, Slack).
10
+ ## Build & Test
11
11
 
12
- ## Key Files
13
-
14
- ```
15
- lib/legion/gaia.rb # Entry point: boot, shutdown, heartbeat, ingest, respond, status
16
- lib/legion/gaia/version.rb # VERSION constant
17
- lib/legion/gaia/settings.rb # Default config hash (channels, router, session, output)
18
- lib/legion/gaia/registry.rb # Extension discovery, runner wiring, phase handler management
19
- lib/legion/gaia/phase_wiring.rb # PHASE_MAP (25 phases: 16 active + 9 dream), PHASE_ARGS, resolve/build helpers
20
- lib/legion/gaia/runner_host.rb # Wraps runner modules with isolated instance state via extend
21
- lib/legion/gaia/sensory_buffer.rb # Thread-safe signal queue (max 1000, normalized)
22
- lib/legion/gaia/actors/heartbeat.rb # Every-1s actor, drains buffer and drives tick
23
- lib/legion/gaia/input_frame.rb # Data.define — immutable inbound message from any channel
24
- lib/legion/gaia/output_frame.rb # Data.define — immutable outbound response to any channel
25
- lib/legion/gaia/channel_adapter.rb # Base class for channel adapters (translate in/out, deliver)
26
- lib/legion/gaia/channel_registry.rb # Registry of active channel adapters, thread-safe
27
- lib/legion/gaia/channel_aware_renderer.rb # Adapts output complexity to channel capabilities + transition suggestions
28
- lib/legion/gaia/output_router.rb # Routes OutputFrames through renderer to correct adapter
29
- lib/legion/gaia/session_store.rb # Session continuity tracking, keyed by human identity
30
- lib/legion/gaia/channels/cli_adapter.rb # First concrete adapter — wraps CLI input/output
31
- lib/legion/gaia/channels/teams_adapter.rb # Teams adapter — Bot Framework activities to Frames
32
- lib/legion/gaia/channels/teams/bot_framework_auth.rb # JWT validation for Bot Framework tokens
33
- lib/legion/gaia/channels/teams/conversation_store.rb # Thread-safe conversation reference storage
34
- lib/legion/gaia/channels/teams/webhook_handler.rb # HTTP webhook handler for Bot Framework activities
35
- lib/legion/gaia/channels/slack_adapter.rb # Slack adapter — Events API to Frames
36
- lib/legion/gaia/channels/slack/signing_verifier.rb # HMAC-SHA256 request verification for Slack Events API
37
- lib/legion/gaia/router.rb # Router module entry point, conditional transport loading
38
- lib/legion/gaia/router/worker_routing.rb # Identity-to-worker routing table with allowlist
39
- lib/legion/gaia/router/router_bridge.rb # Central router: inbound routing + outbound delivery
40
- lib/legion/gaia/router/agent_bridge.rb # Agent-side: subscribe inbound, publish outbound
41
- lib/legion/gaia/router/transport/exchanges/gaia.rb # Topic exchange for GAIA outbound frames
42
- lib/legion/gaia/router/transport/queues/inbound.rb # Per-worker inbound queue (subclass of Transport::Queues::Agent)
43
- lib/legion/gaia/router/transport/queues/outbound.rb # Shared outbound queue (agent->router)
44
- lib/legion/gaia/router/transport/messages/input_frame_message.rb # InputFrame -> RabbitMQ
45
- lib/legion/gaia/router/transport/messages/output_frame_message.rb # OutputFrame -> RabbitMQ
46
- lib/legion/gaia/notification_gate.rb # Three-layer gate between OutputRouter and delivery
47
- lib/legion/gaia/notification_gate/schedule_evaluator.rb # Config-driven quiet hours (day/time/timezone windows)
48
- lib/legion/gaia/notification_gate/presence_evaluator.rb # Teams presence status -> priority threshold mapping
49
- lib/legion/gaia/notification_gate/behavioral_evaluator.rb # Learned signal scoring (arousal, idle time)
50
- lib/legion/gaia/notification_gate/delay_queue.rb # Thread-safe delayed message queue (max size, TTL)
51
- lib/legion/gaia/proactive.rb # Proactive message delivery: send_message, broadcast to channels
52
- lib/legion/gaia/offline_handler.rb # Offline agent handling: queue messages, notify sender, presence tracking
12
+ ```bash
13
+ bundle install
14
+ bundle exec rspec # 0 failures required before commit
15
+ bundle exec rubocop # 0 offenses required
53
16
  ```
54
17
 
55
- ## Architecture
56
-
57
- ### Phase 1: Cortex Absorption
58
- - `Legion::Gaia.boot` creates SensoryBuffer, Registry, and ChannelRegistry, runs discovery
59
- - `Registry#discover` walks `PHASE_MAP`, resolves runner classes via `Legion::Extensions`, wraps in `RunnerHost`
60
- - `Legion::Gaia.heartbeat` drains buffer, calls `tick_host.execute_tick(signals:, phase_handlers:)`
61
- - Heartbeat actor calls `heartbeat` every 1s (configurable via settings)
62
- - Graceful degradation: if lex-tick runner is not discoverable at runtime, heartbeat returns `{ error: :no_tick_extension }` and retries next tick (lex-tick is a gemspec dependency but runner wiring is dynamic)
63
-
64
- ### Phase 2: Channel Abstraction
65
- - `InputFrame` and `OutputFrame` are immutable `Data.define` value objects the universal message format
66
- - `ChannelAdapter` base class defines the contract: `translate_inbound`, `translate_outbound`, `deliver`
67
- - `ChannelRegistry` manages active adapters, thread-safe register/unregister/deliver
68
- - `ChannelAwareRenderer` pre-adapts content complexity (truncation, channel switch suggestions)
69
- - `OutputRouter` chains renderer -> registry -> adapter for delivery
70
- - `SessionStore` tracks session continuity across channels, keyed by human identity with TTL
71
- - `CliAdapter` is the first concrete adapter translates raw strings to InputFrames, buffers output
72
- - `Legion::Gaia.ingest(input_frame)` pushes to sensory buffer and creates/touches session
73
- - `Legion::Gaia.respond(content:, channel_id:)` routes output through renderer and adapter
74
-
75
- ### Phase 3: Teams Channel Adapter
76
- - `TeamsAdapter` translates Bot Framework activities to InputFrames and OutputFrames to Teams messages
77
- - `BotFrameworkAuth` validates JWT tokens from Bot Framework and Emulator issuers (claims, expiry, audience)
78
- - `ConversationStore` holds `service_url` + `conversation_id` references needed for reply delivery (thread-safe)
79
- - `WebhookHandler` routes inbound activities by type: message, conversationUpdate, invoke, other
80
- - Bot @mention stripping ensures clean text reaches the cognitive pipeline
81
- - Mobile/desktop device detection from `channelData.clientInfo.platform`
82
- - Delivery uses `lex-microsoft_teams` Bot runner (`send_text`/`send_card`) when available
83
- - Teams adapter auto-registers during `boot_channels` when `channels.teams.enabled` is true
18
+ ## Where Things Live (most-touched)
19
+
20
+ | Path | Purpose |
21
+ |------|---------|
22
+ | `lib/legion/gaia.rb` | Facade: `boot`, `ingest`, `heartbeat`, `respond`, `status`, `shutdown`; heartbeat quiescence, partner-absence and proactive logic |
23
+ | `lib/legion/gaia/phase_wiring.rb` | `PHASE_MAP` (37 phases: 16 active + 21 dream), `PHASE_ARGS` lambdas, runner resolution, phase-result annotation |
24
+ | `lib/legion/gaia/registry.rb` | Extension discovery, runner wiring, phase-handler management (singleton via `Registry.instance`) |
25
+ | `lib/legion/gaia/runner_host.rb` | Extends a runner module onto an instance so modules get persistent `@ivar` state |
26
+ | `lib/legion/gaia/sensory_buffer.rb` | Thread-safe bounded signal queue (`MAX_BUFFER_SIZE`) |
27
+ | `lib/legion/gaia/actors/heartbeat.rb` | Periodic actor: drain buffer → tick |
28
+ | `lib/legion/gaia/input_frame.rb` / `output_frame.rb` | `Data.define` immutable channel frames |
29
+ | `lib/legion/gaia/channel_adapter.rb` | Base class: `translate_inbound` / `translate_outbound` / `deliver`; `adapter_classes` registry |
30
+ | `lib/legion/gaia/channel_registry.rb` | Active adapters; thread-safe register/unregister/deliver |
31
+ | `lib/legion/gaia/channel_aware_renderer.rb` | Adapts content complexity to channel limits + transition suggestions |
32
+ | `lib/legion/gaia/output_router.rb` | Chains renderer notification gate → registry adapter |
33
+ | `lib/legion/gaia/notification_gate.rb` + `notification_gate/` | Schedule / presence / behavioral evaluators + bounded `DelayQueue` |
34
+ | `lib/legion/gaia/session_store.rb` | Session continuity keyed by human identity, TTL-based |
35
+ | `lib/legion/gaia/router/` | Hub-and-spoke for multi-worker deployments: `WorkerRouting`, `RouterBridge`, `AgentBridge` |
36
+ | `lib/legion/gaia/channels/` | `CliAdapter`, `TeamsAdapter` (+ `teams/` auth/webhook), `SlackAdapter` (+ `slack/` signing) |
37
+ | `lib/legion/gaia/routes.rb` | Self-registering Sinatra routes under `/api/gaia/*` and `/api/channels/teams/webhook` |
38
+ | `lib/legion/gaia/settings.rb` | `Settings.default` the config schema |
39
+ | `lib/legion/gaia/version.rb` | `VERSION` constant (source of truth for the published gem) |
40
+
41
+ ## Data Flow
84
42
 
85
- ### Phase 4: Central Router (Hub-and-Spoke)
86
- - Dual boot modes: `Legion::Gaia.boot(mode: :router)` for stateless router, default `:agent` for full GAIA
87
- - Router mode: boots channels only — no SensoryBuffer, Registry, or cognitive extensions
88
- - `RouterBridge` handles inbound routing (identity -> worker_id -> RabbitMQ queue) and outbound delivery
89
- - `AgentBridge` subscribes to per-worker inbound queue, pushes InputFrames into local GAIA SensoryBuffer
90
- - `AgentBridge` publishes OutputFrames to outbound queue when `respond` is called
91
- - `WorkerRouting` maps Entra OID / identity to worker_id with allowlist enforcement
92
- - Transport layer follows standard legion-transport patterns (Exchange, Queue, Message base classes)
93
- - Inbound uses the `agent` exchange (from `legion-transport`): routing key `agent.<worker_id>`, queue `agent.<worker_id>` (via `Transport::Queues::Agent`). Outbound uses the `gaia` exchange (many-to-one fan-in to router).
94
- - Transport classes only loaded when `legion-transport` is available (conditional require)
95
- - Router never sees cognitive state — only InputFrame/OutputFrame envelopes
96
-
97
- ### Phase 5: Slack Adapter + Cross-Channel Polish
98
- - `SlackAdapter` translates Slack Events API payloads to InputFrames and OutputFrames to Slack messages
99
- - `SigningVerifier` validates inbound requests via HMAC-SHA256 (signing secret + timestamp + body)
100
- - Bot `<@UBOT>` mention stripping for clean text input
101
- - Thread-aware outbound delivery (preserves `thread_ts` for reply threading)
102
- - Slack adapter auto-registers during `boot_channels` when `channels.slack.enabled` is true
103
- - `ChannelAwareRenderer` adds transition suggestions when content is truncated (e.g., "Full response available on cli")
104
- - Richness hierarchy: voice -> slack -> cli (richer channels suggested when content exceeds limits)
105
-
106
- ### Phase 6: Notification Gate
107
- - `NotificationGate` sits between OutputRouter and channel delivery, evaluating each frame
108
- - Three evaluation layers in order: schedule (quiet hours) -> presence (Teams status) -> behavioral (learned signals)
109
- - `ScheduleEvaluator` parses config-driven schedule arrays with day/time/timezone windows, handles overnight wraps
110
- - `PresenceEvaluator` maps Teams availability states to minimum priority thresholds (Available->ambient, Busy/Away->urgent, DoNotDisturb/Offline->critical)
111
- - `BehavioralEvaluator` uses arousal (0.0-1.0) and idle_seconds signals to compute notification score
112
- - Priority override: critical/urgent messages bypass all layers
113
- - `DelayQueue` is thread-safe with mutex, max_size eviction, TTL-based expiration, flush
114
- - OutputRouter calls `notification_gate.evaluate(frame)` -> `:deliver` or `:delay`
115
- - Delayed frames re-evaluated each heartbeat tick via `process_delayed` (drain expired, flush when quiet ends)
116
-
117
- ### Data Flow
118
43
  ```
119
- Human Input -> ChannelAdapter#translate_inbound -> InputFrame -> Gaia.ingest -> SensoryBuffer
120
- |
121
- Heartbeat tick
122
- |
123
- Cognitive Output -> OutputFrame -> OutputRouter -> ChannelAwareRenderer -> ChannelAdapter#deliver
44
+ Channel input -> ChannelAdapter#translate_inbound -> InputFrame -> Gaia.ingest -> SensoryBuffer
45
+ |
46
+ Heartbeat tick (lex-tick)
47
+ |
48
+ Cognitive output <- OutputFrame <- OutputRouter <- NotificationGate <- ChannelAdapter#deliver
124
49
  ```
125
50
 
126
- ## Patterns
127
-
128
- - `RunnerHost` uses `extend runner_module` on instances to give modules persistent `@ivar` state
129
- - `Registry` tracks `@discovered` boolean to prevent re-discovery when results are empty
130
- - `PhaseWiring::PHASE_ARGS` lambdas build kwargs from a context hash; `association_walk` is the most complex
131
- - Settings fall through: `Legion::Settings[:gaia]` if available, else `Legion::Gaia::Settings.default`
132
- - `InputFrame`/`OutputFrame` use `Data.define` for immutability frozen by default, pattern-matchable
133
- - Channel adapters are deliberately thin: translate format, not content. No business logic, no state
134
- - `SessionStore` uses identity-indexed lookup with TTL-based expiration and channel history tracking
135
-
136
- ## Architectural Constraints
137
-
138
- 1. No channel-specific state adapters store nothing, destroy and recreate without loss
139
- 2. No channel-specific logic adapters translate format, not content
140
- 3. Authentication is non-negotiableevery channel validates identity before input reaches GAIA
141
- 4. Private core protections are channel-independent
142
- 5. Human controls channel availability any channel can be disabled at any time
143
-
144
- ## Dependencies
145
-
146
- ### Declared gem dependencies
147
-
148
- | Gem | Purpose |
149
- |-----|---------|
150
- | `base64` | Required (Ruby 3.4+ removed from default gems) |
151
- | `openssl` | Required for TLS/JWT operations |
152
- | `legion-apollo` (>= 0.2.1) | Apollo knowledge client library (knowledge_retrieval phase) |
153
- | `legion-json` | JSON serialization |
154
- | `legion-logging` | Logging (guarded by `const_defined?`) |
155
- | `legion-settings` | Configuration |
156
- | `lex-tick` | Tick orchestrator — GAIA is inoperable without this |
157
- | `lex-privatecore` | Privacy enforcement safety layer for the cognitive stack |
158
- | `lex-apollo` | Apollo knowledge service (knowledge_retrieval + knowledge_promotion phases) |
159
- | `lex-coldstart` | Cold-start progress tracking (procedural_check phase) |
160
- | `lex-detect` | Task observation (post_tick_reflection phase) |
161
- | `lex-mesh` | Mesh interface and topology (mesh_interface phase) |
162
- | `lex-synapse` | GAIA report and reflection (working_memory_integration, post_tick_reflection phases) |
163
- | `lex-agentic-affect` | Affective processing domain (emotional_evaluation, gut_instinct phases) |
164
- | `lex-agentic-attention` | Attention management domain (sensory_processing phase) |
165
- | `lex-agentic-defense` | Defense and threat response domain |
166
- | `lex-agentic-executive` | Executive function and goal management (action_selection phase) |
167
- | `lex-agentic-homeostasis` | Internal state regulation (homeostasis_regulation phase) |
168
- | `lex-agentic-imagination` | Creative and hypothetical reasoning |
169
- | `lex-agentic-inference` | Probabilistic inference domain (prediction_engine phase) |
170
- | `lex-agentic-integration` | Sensory integration domain |
171
- | `lex-agentic-language` | Language processing domain (dream_narration phase) |
172
- | `lex-agentic-learning` | Learning and adaptation domain |
173
- | `lex-agentic-memory` | Memory management domain (memory_retrieval, memory_consolidation, dream cycle phases) |
174
- | `lex-agentic-self` | Self-model and identity domain (identity_entropy_check phase) |
175
- | `lex-agentic-social` | Social cognition domain (social_cognition, theory_of_mind phases) |
176
-
177
- ### Optional at runtime (not declared in gemspec)
178
-
179
- - `legion-transport` — required for router mode (hub-and-spoke), conditional require
180
- - `lex-microsoft_teams` — required for Teams delivery, guarded
181
- - Other agentic LEXs are discovered via `Legion::Extensions`
182
-
183
- ## Future
184
-
185
- - Voice adapter
186
- - Proactive notification scheduling (agent-initiated messages at optimal delivery times)
187
-
188
- ---
189
-
190
- **Maintained By**: Matthew Iverson (@Esity)
51
+ ## HTTP Routes (`routes.rb`)
52
+
53
+ `GET /api/gaia/status`, `GET /api/gaia/ticks`, `GET /api/gaia/channels`, `GET /api/gaia/buffer`,
54
+ `GET /api/gaia/sessions`, `POST /api/gaia/ingest`, `POST /api/channels/teams/webhook`. Registered via
55
+ `Legion::API.register_library_routes('gaia', Legion::Gaia::Routes)` at boot.
56
+
57
+ ## Gotchas / Invariants (these prevent real bugs)
58
+
59
+ - **`lex-tick` is mandatory** GAIA is inoperable without the tick orchestrator. The heartbeat
60
+ degrades gracefully if the tick runner is unresolvable (warns once, retries next tick).
61
+ - **Phase counts**: `PHASE_MAP` is 37 entries — 16 active-tick, 21 dream-cycle. Phases whose runner
62
+ extension isn't loaded are skipped at wiring time; don't assume every phase is always active.
63
+ - **Every phase result is annotated** with `status` (`completed`/`skipped`/`failed`) and `elapsed_ms`
64
+ (monotonic). The `/api/gaia/ticks` stream depends on these always being present.
65
+ - **Frames are immutable**`InputFrame`/`OutputFrame` are `Data.define`, frozen, pattern-matchable.
66
+ - **Channel adapters are thin and stateless** — translate format only, no business logic, no state;
67
+ they must be recreatable without loss. Authentication is non-negotiable: every channel validates
68
+ identity before input reaches GAIA (Teams JWT/Bot Framework, Slack HMAC-SHA256).
69
+ - **Critical/urgent priority bypasses all notification-gate layers.** Gate order is schedule →
70
+ presence → behavioral.
71
+ - **Router mode** (`boot(mode: :router)`) boots channels only — no SensoryBuffer or cognitive
72
+ extensions. Worker allowlists are enforced for live registrations *and* DB-backed resolution.
73
+ - **Quiescing shutdown** once `shutdown` starts, phase handlers return
74
+ `{ status: :skipped, reason: :gaia_shutting_down }`; new heartbeats are blocked and in-flight work
75
+ drains (bounded by `shutdown.heartbeat_wait_timeout`). This prevents late writes to closed services.
76
+ - **Transport classes load conditionally** only required when `legion-transport` is available.
77
+ - **Settings merge is deep** `Legion::Gaia.settings` deep-merges `Legion::Settings[:gaia]` over
78
+ `Settings.default`; mutate nested keys, don't replace the whole hash.
79
+
80
+ ## Legion-Wide Rules
81
+
82
+ - **`Legion::JSON` only** `Legion::JSON.load` returns **symbol keys**; `.dump` takes exactly one
83
+ positional arg. Inside the `Legion::` namespace, `::JSON` and `::Process` must be explicit.
84
+ - **Never swallow exceptions** — every `rescue` re-raises or calls `handle_exception(e, level:,
85
+ operation:)`. Use `log.*` (via `Legion::Gaia::Logging` / `Legion::Logging::Helper`), never `puts`.
86
+ - **No personal/company identifiers in VCS.** Never force-push.
87
+ - Ruby 3.4+, single quotes, frozen string literals, line length ≤ 120 (see `.rubocop.yml`).