hypervibe 0.1.0

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.
Files changed (8) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +7 -0
  3. data/PLAN.md +1484 -0
  4. data/VERSION +1 -0
  5. data/bin/vibe +3 -0
  6. data/hypervibe.gemspec +27 -0
  7. data/lib/hypervibe.rb +0 -0
  8. metadata +103 -0
data/PLAN.md ADDED
@@ -0,0 +1,1484 @@
1
+ # Hypervibe: Ruby Framework for AI & Vibe-Coders
2
+
3
+ ## Overview
4
+
5
+ Hypervibe is a Ruby framework where **AI is the primary developer** and humans provide high-level guidance. Built on the principle that LLMs excel at SQL and JSON Schema but struggle with ORM abstractions, Hypervibe embraces explicit, observable, and streaming-first patterns.
6
+
7
+ ## Core Philosophy
8
+
9
+ - **SQL as source of truth** - LLMs write SQL directly, no ORM abstractions
10
+ - **Tools & Flows** - Declarative orchestration with machine-readable contracts
11
+ - **Streaming first** - Every operation can stream partial results
12
+ - **Observable by default** - Event logs, traces, and replay capabilities
13
+ - **Schema everywhere** - JSON Schema validation on all boundaries
14
+ - **AI-native testing** - Golden tests, dry-runs, and prompt versioning
15
+
16
+ ## Installation & Setup
17
+
18
+ ```bash
19
+ # Install the gem
20
+ gem install hypervibe
21
+
22
+ # Create a new project
23
+ vibe new my_app
24
+ cd my_app
25
+
26
+ # Start development server with trace viewer
27
+ vibe server
28
+
29
+ # Generate components
30
+ vibe generate tool send_notification
31
+ vibe generate flow user_onboarding
32
+ vibe generate query users
33
+ ```
34
+
35
+ ## Core Architecture
36
+
37
+ ### 1. Data Layer: sqlc-style Repositories
38
+
39
+ SQL files define all queries. Hypervibe generates type-safe Ruby methods automatically.
40
+
41
+ #### SQL Query Files
42
+
43
+ ```sql
44
+ -- queries/users.sql
45
+
46
+ -- name: GetUser :one
47
+ SELECT * FROM users WHERE id = $1;
48
+
49
+ -- name: FindByEmail :one
50
+ SELECT id, email, name, created_at
51
+ FROM users
52
+ WHERE email = $1
53
+ LIMIT 1;
54
+
55
+ -- name: ListActiveUsers :many
56
+ -- cache: 5.minutes
57
+ SELECT id, name, email
58
+ FROM users
59
+ WHERE deleted_at IS NULL
60
+ ORDER BY created_at DESC
61
+ LIMIT $1;
62
+
63
+ -- name: CreateUser :one
64
+ INSERT INTO users (email, name, password_hash)
65
+ VALUES ($1, $2, $3)
66
+ RETURNING *;
67
+
68
+ -- name: UpdateLastLogin :exec
69
+ UPDATE users
70
+ SET last_login_at = NOW()
71
+ WHERE id = $1;
72
+
73
+ -- name: CountUserPosts :one
74
+ SELECT COUNT(*) as post_count
75
+ FROM posts
76
+ WHERE user_id = $1 AND published = true;
77
+
78
+ -- name: GetUserWithStats :one
79
+ WITH post_stats AS (
80
+ SELECT
81
+ user_id,
82
+ COUNT(*) as post_count,
83
+ MAX(created_at) as last_post_at
84
+ FROM posts
85
+ WHERE user_id = $1
86
+ GROUP BY user_id
87
+ )
88
+ SELECT
89
+ u.*,
90
+ COALESCE(ps.post_count, 0) as post_count,
91
+ ps.last_post_at
92
+ FROM users u
93
+ LEFT JOIN post_stats ps ON ps.user_id = u.id
94
+ WHERE u.id = $1;
95
+ ```
96
+
97
+ #### Auto-Generated Repository Module
98
+
99
+ ```ruby
100
+ # Auto-generated from queries/users.sql
101
+ Repo[:users] do
102
+ query :get_user,
103
+ sql: "SELECT * FROM users WHERE id = $1",
104
+ args: [{id: :uuid}],
105
+ returns: User
106
+
107
+ query :find_by_email,
108
+ sql: "SELECT id, email, name, created_at FROM users WHERE email = $1 LIMIT 1",
109
+ args: [{email: :string}],
110
+ returns: {id: :uuid, email: :string, name: :string, created_at: :timestamp}
111
+
112
+ query :list_active_users,
113
+ sql: "SELECT id, name, email FROM users WHERE deleted_at IS NULL ORDER BY created_at DESC LIMIT $1",
114
+ args: [{limit: :int}],
115
+ returns: [{id: :uuid, name: :string, email: :string}],
116
+ cache: 5.minutes
117
+
118
+ cmd :create_user,
119
+ sql: "INSERT INTO users (email, name, password_hash) VALUES ($1, $2, $3) RETURNING *",
120
+ args: [{email: :string}, {name: :string}, {password_hash: :string}],
121
+ returns: User
122
+
123
+ cmd :update_last_login,
124
+ sql: "UPDATE users SET last_login_at = NOW() WHERE id = $1",
125
+ args: [{id: :uuid}]
126
+
127
+ query :count_user_posts,
128
+ sql: "SELECT COUNT(*) as post_count FROM posts WHERE user_id = $1 AND published = true",
129
+ args: [{user_id: :uuid}],
130
+ returns: {post_count: :integer}
131
+ end
132
+ ```
133
+
134
+ #### Usage in Code
135
+
136
+ ```ruby
137
+ # Simple queries
138
+ user = Repo[:users].get_user(id: params[:id])
139
+ user = Repo[:users].find_by_email(email: "alice@example.com")
140
+
141
+ # Returns array of hashes
142
+ active_users = Repo[:users].list_active_users(limit: 10)
143
+
144
+ # Commands
145
+ new_user = Repo[:users].create_user(
146
+ email: "bob@example.com",
147
+ name: "Bob",
148
+ password_hash: BCrypt::Password.create("secret")
149
+ )
150
+
151
+ # Every query result includes metadata
152
+ result = Repo[:users].get_user(id: 123)
153
+ result._sql # => "SELECT * FROM users WHERE id = $1"
154
+ result._timing # => 23.5 (ms)
155
+ result._explain # => Query plan
156
+ ```
157
+
158
+ ### 2. Vector & Document Stores
159
+
160
+ Native support for modern AI data patterns:
161
+
162
+ ```sql
163
+ -- queries/embeddings.sql
164
+
165
+ -- name: SearchSimilarDocs :many
166
+ -- adapter: pgvector
167
+ SELECT
168
+ id,
169
+ content,
170
+ metadata,
171
+ 1 - (embedding <=> $1) as similarity
172
+ FROM documents
173
+ WHERE 1 - (embedding <=> $1) > $2
174
+ ORDER BY embedding <=> $1
175
+ LIMIT $3;
176
+
177
+ -- name: StoreDocument :one
178
+ -- adapter: jsonb
179
+ INSERT INTO documents (content, metadata, embedding)
180
+ VALUES ($1, $2, $3)
181
+ RETURNING id;
182
+
183
+ -- name: UpdateDocumentMetadata :exec
184
+ -- adapter: jsonb
185
+ UPDATE documents
186
+ SET metadata = metadata || $2
187
+ WHERE id = $1;
188
+ ```
189
+
190
+ ```ruby
191
+ # Vector search
192
+ similar_docs = Repo[:embeddings].search_similar_docs(
193
+ embedding: AI.embed("user query"),
194
+ threshold: 0.7,
195
+ limit: 10
196
+ )
197
+
198
+ # Document storage with JSONB
199
+ doc_id = Repo[:embeddings].store_document(
200
+ content: "Full text content...",
201
+ metadata: {source: "upload", user_id: 123},
202
+ embedding: AI.embed("Full text content...")
203
+ )
204
+ ```
205
+
206
+ ### 3. Tools: Single Definition, Multiple Interfaces
207
+
208
+ Tools are atomic units of side-effects with JSON Schema contracts:
209
+
210
+ ```ruby
211
+ class Tools::SendEmail
212
+ include Hypervibe::Tool
213
+
214
+ tool "send_email",
215
+ desc: "Send a transactional email",
216
+ examples: [
217
+ {
218
+ input: {
219
+ to: "user@example.com",
220
+ subject: "Welcome!",
221
+ body_html: "<p>Hello</p>"
222
+ },
223
+ output: {
224
+ message_id: "msg_123",
225
+ status: "sent"
226
+ }
227
+ }
228
+ ],
229
+ input: {
230
+ to: {type: "string", format: "email", required: true},
231
+ subject: {type: "string", maxLength: 200, required: true},
232
+ body_html: {type: "string", required: true},
233
+ reply_to: {type: "string", format: "email"},
234
+ attachments: {
235
+ type: "array",
236
+ items: {
237
+ type: "object",
238
+ properties: {
239
+ filename: {type: "string"},
240
+ content: {type: "string", format: "base64"}
241
+ }
242
+ }
243
+ }
244
+ },
245
+ output: {
246
+ message_id: {type: "string"},
247
+ status: {type: "string", enum: ["sent", "queued"]},
248
+ delivered_at: {type: "string", format: "date-time"}
249
+ },
250
+ errors: {
251
+ invalid_email: "The provided email address is not valid",
252
+ rate_limited: "Too many emails sent recently",
253
+ attachment_too_large: "Attachment exceeds 10MB limit"
254
+ },
255
+ capabilities: ["email:send"]
256
+
257
+ def call(to:, subject:, body_html:, reply_to: nil, attachments: [])
258
+ validate_rate_limit!(to)
259
+ validate_attachments!(attachments)
260
+
261
+ id = Mailer.deliver(
262
+ to: to,
263
+ subject: subject,
264
+ html: body_html,
265
+ reply_to: reply_to,
266
+ attachments: process_attachments(attachments)
267
+ )
268
+
269
+ emit :email_sent, {
270
+ to: to,
271
+ message_id: id,
272
+ timestamp: Time.now
273
+ }
274
+
275
+ {
276
+ message_id: id,
277
+ status: "sent",
278
+ delivered_at: Time.now.iso8601
279
+ }
280
+ rescue RateLimitError
281
+ error! :rate_limited
282
+ rescue AttachmentError => e
283
+ error! :attachment_too_large, details: e.message
284
+ end
285
+
286
+ private
287
+
288
+ def validate_attachments!(attachments)
289
+ attachments.each do |att|
290
+ size = Base64.decode64(att[:content]).bytesize
291
+ raise AttachmentError if size > 10.megabytes
292
+ end
293
+ end
294
+ end
295
+ ```
296
+
297
+ This single tool definition automatically generates:
298
+
299
+ - HTTP endpoint: `POST /tools/send_email`
300
+ - CLI command: `vibe tool send_email --to user@example.com --subject "Test"`
301
+ - LLM tool spec (OpenAI/Anthropic format)
302
+ - OpenAPI documentation
303
+ - Contract tests from examples
304
+ - GraphQL mutation (optional)
305
+
306
+ ### 4. Flows: Declarative Orchestration
307
+
308
+ Flows compose tools, AI calls, and queries into resumable workflows:
309
+
310
+ ```ruby
311
+ flow "onboard_user",
312
+ budget_cents: 5_00,
313
+ timeout: 30.seconds,
314
+ stream: true,
315
+ capabilities: [
316
+ "repo:users:write",
317
+ "repo:profiles:write",
318
+ "tool:send_email",
319
+ "tool:schedule_job"
320
+ ] do
321
+
322
+ # Step 1: Validate and create user
323
+ step :user do
324
+ existing = Repo[:users].find_by_email(email: params[:email])
325
+ error!(:user_exists) if existing
326
+
327
+ Repo[:users].create_user(
328
+ email: params[:email],
329
+ name: params[:name],
330
+ password_hash: hash_password(params[:password])
331
+ )
332
+ end
333
+
334
+ # Step 2: Generate personalized content with AI
335
+ ai :welcome_content,
336
+ model: "gpt-4o-mini",
337
+ temperature: 0.7,
338
+ cache: 1.hour,
339
+ max_tokens: 500,
340
+ schema: {
341
+ type: "object",
342
+ properties: {
343
+ subject: {type: "string", maxLength: 100},
344
+ body_html: {type: "string"},
345
+ onboarding_tips: {
346
+ type: "array",
347
+ items: {type: "string"},
348
+ minItems: 3,
349
+ maxItems: 5
350
+ },
351
+ suggested_connections: {
352
+ type: "array",
353
+ items: {
354
+ type: "object",
355
+ properties: {
356
+ user_id: {type: "integer"},
357
+ reason: {type: "string"}
358
+ }
359
+ }
360
+ }
361
+ },
362
+ required: ["subject", "body_html", "onboarding_tips"]
363
+ } do
364
+ system """
365
+ You are a friendly onboarding assistant. Be concise and helpful.
366
+ The app is a professional networking platform.
367
+ """
368
+
369
+ user """
370
+ Create a welcome email for a new user:
371
+ Name: {{ steps.user.name }}
372
+ Email: {{ steps.user.email }}
373
+ Company domain: {{ steps.user.email.split('@').last }}
374
+ Signed up: {{ steps.user.created_at }}
375
+
376
+ Include personalized onboarding tips based on their email domain.
377
+ Suggest potential connections if you recognize the company.
378
+ """
379
+ end
380
+
381
+ # Step 3: Create user profile
382
+ step :profile do
383
+ Repo[:profiles].create(
384
+ user_id: steps.user.id,
385
+ onboarding_tips: steps.welcome_content["onboarding_tips"],
386
+ suggested_connections: steps.welcome_content["suggested_connections"],
387
+ stage: "welcome_sent"
388
+ )
389
+ end
390
+
391
+ # Step 4: Send welcome email
392
+ tool :email, Tools::SendEmail,
393
+ to: params[:email],
394
+ subject: steps.welcome_content["subject"],
395
+ body_html: steps.welcome_content["body_html"]
396
+
397
+ # Step 5: Schedule follow-up sequence
398
+ parallel do
399
+ tool :follow_up_1, Tools::ScheduleJob,
400
+ job_type: "engagement_email",
401
+ run_at: 1.day.from_now,
402
+ params: {user_id: steps.user.id, email_type: "tips"}
403
+
404
+ tool :follow_up_2, Tools::ScheduleJob,
405
+ job_type: "engagement_email",
406
+ run_at: 3.days.from_now,
407
+ params: {user_id: steps.user.id, email_type: "connections"}
408
+
409
+ tool :follow_up_3, Tools::ScheduleJob,
410
+ job_type: "engagement_email",
411
+ run_at: 7.days.from_now,
412
+ params: {user_id: steps.user.id, email_type: "check_in"}
413
+ end
414
+
415
+ # Completion
416
+ emit :onboarding_complete, {
417
+ user_id: steps.user.id,
418
+ email_sent: steps.email.message_id,
419
+ follow_ups_scheduled: [
420
+ steps.follow_up_1.job_id,
421
+ steps.follow_up_2.job_id,
422
+ steps.follow_up_3.job_id
423
+ ]
424
+ }
425
+ end
426
+ ```
427
+
428
+ ### 5. Event Log & Replay System
429
+
430
+ Every flow execution creates an immutable event log:
431
+
432
+ ```ruby
433
+ # Event log structure
434
+ [
435
+ {
436
+ id: "evt_001",
437
+ type: "flow_started",
438
+ flow: "onboard_user",
439
+ run_id: "run_abc123",
440
+ params: {email: "alice@example.com"},
441
+ timestamp: "2024-01-15T10:00:00Z",
442
+ correlation_id: "req_xyz"
443
+ },
444
+ {
445
+ id: "evt_002",
446
+ type: "step_started",
447
+ step: "user",
448
+ run_id: "run_abc123",
449
+ timestamp: "2024-01-15T10:00:00.100Z"
450
+ },
451
+ {
452
+ id: "evt_003",
453
+ type: "sql_executed",
454
+ query: "SELECT id, email FROM users WHERE email = $1",
455
+ args: ["alice@example.com"],
456
+ duration_ms: 23,
457
+ rows_returned: 0,
458
+ run_id: "run_abc123",
459
+ timestamp: "2024-01-15T10:00:00.123Z"
460
+ },
461
+ {
462
+ id: "evt_004",
463
+ type: "sql_executed",
464
+ query: "INSERT INTO users...",
465
+ duration_ms: 45,
466
+ rows_affected: 1,
467
+ run_id: "run_abc123",
468
+ timestamp: "2024-01-15T10:00:00.168Z"
469
+ },
470
+ {
471
+ id: "evt_005",
472
+ type: "step_completed",
473
+ step: "user",
474
+ result: {id: 123, email: "alice@example.com"},
475
+ run_id: "run_abc123",
476
+ timestamp: "2024-01-15T10:00:00.213Z"
477
+ },
478
+ {
479
+ id: "evt_006",
480
+ type: "ai_request",
481
+ model: "gpt-4o-mini",
482
+ prompt_tokens: 234,
483
+ temperature: 0.7,
484
+ run_id: "run_abc123",
485
+ timestamp: "2024-01-15T10:00:00.250Z"
486
+ },
487
+ {
488
+ id: "evt_007",
489
+ type: "ai_response",
490
+ completion_tokens: 156,
491
+ total_tokens: 390,
492
+ cost_cents: 0.0234,
493
+ result: {subject: "Welcome!", body_html: "..."},
494
+ run_id: "run_abc123",
495
+ timestamp: "2024-01-15T10:00:01.750Z"
496
+ },
497
+ {
498
+ id: "evt_008",
499
+ type: "tool_called",
500
+ tool: "send_email",
501
+ input: {to: "alice@example.com", subject: "Welcome!"},
502
+ run_id: "run_abc123",
503
+ timestamp: "2024-01-15T10:00:01.800Z"
504
+ },
505
+ {
506
+ id: "evt_009",
507
+ type: "tool_completed",
508
+ tool: "send_email",
509
+ output: {message_id: "msg_789", status: "sent"},
510
+ duration_ms: 234,
511
+ run_id: "run_abc123",
512
+ timestamp: "2024-01-15T10:00:02.034Z"
513
+ },
514
+ {
515
+ id: "evt_010",
516
+ type: "flow_completed",
517
+ flow: "onboard_user",
518
+ run_id: "run_abc123",
519
+ duration_ms: 2034,
520
+ total_cost_cents: 0.0234,
521
+ timestamp: "2024-01-15T10:00:02.034Z"
522
+ }
523
+ ]
524
+ ```
525
+
526
+ #### Replay & Time Travel
527
+
528
+ ```ruby
529
+ # Replay a flow with fixed responses (for testing)
530
+ replay = Flow.replay("onboard_user", run_id: "run_abc123") do
531
+ mock_ai :welcome_content, returns: {
532
+ subject: "Welcome to the platform!",
533
+ body_html: "<p>We're excited to have you...</p>",
534
+ onboarding_tips: ["Complete your profile", "Connect with colleagues", "Join groups"]
535
+ }
536
+ mock_tool :email, returns: {message_id: "msg_test", status: "sent"}
537
+ end
538
+
539
+ # Inspect any historical run
540
+ run = Flow.runs.find("run_abc123")
541
+ run.trace # Full execution trace
542
+ run.cost # Token costs: $0.0234
543
+ run.duration # 2034ms
544
+ run.events # All events
545
+ run.replay(until: :email) # Partial replay up to email step
546
+
547
+ # Time travel debugging
548
+ Flow.debug("run_abc123") do |debugger|
549
+ debugger.step_forward # Execute next event
550
+ debugger.inspect(:user) # See state at this point
551
+ debugger.rewind_to(:ai_request) # Go back in time
552
+ debugger.modify_and_continue( # What-if analysis
553
+ ai_response: {subject: "Different subject"}
554
+ )
555
+ end
556
+ ```
557
+
558
+ ### 6. Prompts as Code
559
+
560
+ Prompts are versioned, tested, and compiled:
561
+
562
+ ```ruby
563
+ # prompts/summarizer.prompt.rb
564
+ prompt "summarize_document",
565
+ model: "gpt-4o",
566
+ temperature: 0.3,
567
+ version: "1.2.0",
568
+ changelog: {
569
+ "1.2.0" => "Added sentiment analysis",
570
+ "1.1.0" => "Improved key point extraction",
571
+ "1.0.0" => "Initial version"
572
+ },
573
+ schema: {
574
+ type: "object",
575
+ properties: {
576
+ summary: {type: "string", minLength: 100, maxLength: 500},
577
+ key_points: {
578
+ type: "array",
579
+ items: {type: "string"},
580
+ minItems: 3,
581
+ maxItems: 7
582
+ },
583
+ sentiment: {type: "string", enum: ["positive", "neutral", "negative"]},
584
+ confidence: {type: "number", minimum: 0, maximum: 1}
585
+ },
586
+ required: ["summary", "key_points", "sentiment", "confidence"]
587
+ } do
588
+
589
+ system """
590
+ You are a document summarizer. Be concise and extract key information.
591
+ Focus on actionable insights and main arguments.
592
+ Always assess the overall sentiment and your confidence level.
593
+ """
594
+
595
+ user """
596
+ Summarize this document:
597
+
598
+ {{ document }}
599
+
600
+ Document metadata:
601
+ - Length: {{ document.length }} characters
602
+ - Source: {{ metadata.source }}
603
+ - Date: {{ metadata.date }}
604
+ """
605
+
606
+ # Golden examples for testing
607
+ example "earnings_report" do
608
+ input document: "Q3 2024 Earnings Report: Revenue increased 23% YoY to $4.5B...",
609
+ metadata: {source: "SEC Filing", date: "2024-10-15"}
610
+
611
+ output {
612
+ summary: "Q3 earnings exceeded expectations with 23% YoY revenue growth...",
613
+ key_points: [
614
+ "Revenue up 23% to $4.5B",
615
+ "New product line contributed 30% of growth",
616
+ "Guidance raised for Q4"
617
+ ],
618
+ sentiment: "positive",
619
+ confidence: 0.95
620
+ }
621
+ end
622
+
623
+ example "incident_report" do
624
+ input document: "Service Outage Report: At 14:30 UTC, our primary database...",
625
+ metadata: {source: "Internal", date: "2024-10-20"}
626
+
627
+ output {
628
+ summary: "Database outage affected 15% of users for 45 minutes...",
629
+ key_points: [
630
+ "45-minute outage on October 20",
631
+ "15% of users affected",
632
+ "Root cause: connection pool exhaustion"
633
+ ],
634
+ sentiment: "negative",
635
+ confidence: 0.90
636
+ }
637
+ end
638
+
639
+ # Validation rules
640
+ validate do |output|
641
+ # Summary should mention key numbers from input
642
+ if input[:document].include?("23%") && !output[:summary].include?("23")
643
+ error "Summary should include key metrics"
644
+ end
645
+
646
+ # Confidence should be lower for ambiguous content
647
+ if output[:sentiment] == "neutral" && output[:confidence] > 0.8
648
+ warning "High confidence unusual for neutral sentiment"
649
+ end
650
+ end
651
+ end
652
+ ```
653
+
654
+ Usage:
655
+
656
+ ```ruby
657
+ # Use the prompt
658
+ result = Prompts.summarize_document(
659
+ document: File.read("report.pdf"),
660
+ metadata: {source: "uploaded", date: Date.today}
661
+ )
662
+
663
+ # Access versioned prompts
664
+ result_v1 = Prompts.summarize_document.v("1.0.0").call(document: "...")
665
+
666
+ # Test prompts
667
+ Prompts.test("summarize_document") do
668
+ run_golden_examples # Runs all defined examples
669
+ run_validation_suite # Checks edge cases
670
+ run_regression_tests # Ensures backwards compatibility
671
+ end
672
+ ```
673
+
674
+ ### 7. Streaming & Real-time Updates
675
+
676
+ All flows stream by default via Server-Sent Events (SSE):
677
+
678
+ ```ruby
679
+ # HTTP endpoint automatically streams
680
+ GET /flows/onboard_user/run?email=user@example.com
681
+
682
+ # Response stream:
683
+ event: flow_started
684
+ data: {"flow": "onboard_user", "run_id": "run_abc123"}
685
+
686
+ event: step_completed
687
+ data: {"step": "user", "result": {"id": 123, "email": "user@example.com"}}
688
+
689
+ event: ai_token
690
+ data: {"content": "Welcome"}
691
+
692
+ event: ai_token
693
+ data: {"content": " to"}
694
+
695
+ event: ai_token
696
+ data: {"content": " our platform!"}
697
+
698
+ event: step_completed
699
+ data: {"step": "welcome_content", "tokens_used": 156, "cost_cents": 0.0234}
700
+
701
+ event: progress
702
+ data: {"percent": 75, "message": "Sending email..."}
703
+
704
+ event: tool_completed
705
+ data: {"tool": "send_email", "result": {"message_id": "msg_123"}}
706
+
707
+ event: flow_completed
708
+ data: {"run_id": "run_abc123", "duration_ms": 2341, "cost_cents": 0.0234}
709
+ ```
710
+
711
+ Ruby client with streaming:
712
+
713
+ ```ruby
714
+ Flow.run("onboard_user", email: "test@example.com") do |event|
715
+ case event.type
716
+ when :ai_token
717
+ print event.data[:content] # Stream AI response char by char
718
+ when :step_completed
719
+ puts "\n✓ #{event.step} completed"
720
+ when :progress
721
+ update_progress_bar(event.data[:percent])
722
+ when :error
723
+ handle_error(event.data)
724
+ end
725
+ end
726
+ ```
727
+
728
+ JavaScript client:
729
+
730
+ ```javascript
731
+ const events = new EventSource(
732
+ "/flows/onboard_user/run?email=test@example.com",
733
+ );
734
+
735
+ events.addEventListener("ai_token", (e) => {
736
+ const data = JSON.parse(e.data);
737
+ document.getElementById("output").innerHTML += data.content;
738
+ });
739
+
740
+ events.addEventListener("flow_completed", (e) => {
741
+ const data = JSON.parse(e.data);
742
+ console.log(
743
+ `Completed in ${data.duration_ms}ms, cost: $${data.cost_cents / 100}`,
744
+ );
745
+ events.close();
746
+ });
747
+ ```
748
+
749
+ ### 8. Development Tools
750
+
751
+ #### Interactive Console
752
+
753
+ ```ruby
754
+ $ vibe console
755
+
756
+ > experiment do
757
+ # Test queries with immediate feedback
758
+ user = Repo[:users].find_by_email("test@example.com")
759
+ see_sql # Shows: SELECT id, email, name FROM users WHERE email = $1
760
+ see_explain # Shows query plan
761
+
762
+ # Test AI generations
763
+ draft = AI.generate("Write a haiku about #{user.name}")
764
+ show_tokens # Token count: 45 prompt, 17 completion
765
+ show_cost # Cost: $0.0003
766
+
767
+ # Compare variations
768
+ test_with temperature: 0.3
769
+ test_with temperature: 0.9
770
+ compare_results # Shows diff between outputs
771
+
772
+ # Modify and retry
773
+ undo_last
774
+ retry_with model: "gpt-4o"
775
+ end
776
+
777
+ > # Direct repository access
778
+ > Repo[:users].get_user(id: 123)._timing
779
+ => 12.3 # milliseconds
780
+
781
+ > # Test tools in isolation
782
+ > Tools::SendEmail.dry_run(to: "test@example.com", subject: "Test")
783
+ => {message_id: "dry_run_msg_123", status: "sent", dry_run: true}
784
+ ```
785
+
786
+ #### Web-based Trace Viewer
787
+
788
+ ```ruby
789
+ # Built-in web UI at http://localhost:3000/__traces__
790
+ # Features:
791
+ # - Flow execution DAG visualization
792
+ # - Step-by-step replay
793
+ # - SQL queries with EXPLAIN ANALYZE
794
+ # - AI prompts/responses with token counts
795
+ # - Tool inputs/outputs
796
+ # - Waterfall timing diagram
797
+ # - Cost breakdown by step
798
+ # - Event log browser
799
+ # - Performance profiling
800
+ ```
801
+
802
+ #### Golden Tests
803
+
804
+ ```ruby
805
+ # test/flows/onboard_user_test.rb
806
+ describe Flow["onboard_user"] do
807
+ test "successful onboarding" do
808
+ # Use recorded AI responses for deterministic tests
809
+ with_golden_fixtures do
810
+ result = run_flow(
811
+ email: "newuser@example.com",
812
+ name: "Alice",
813
+ password: "secure123"
814
+ )
815
+
816
+ # Assert on each step
817
+ assert_step :user do |user|
818
+ assert_equal "Alice", user.name
819
+ assert_equal "newuser@example.com", user.email
820
+ end
821
+
822
+ assert_ai :welcome_content do |prompt, response|
823
+ assert_includes prompt, "Alice"
824
+ assert response["onboarding_tips"].length >= 3
825
+ end
826
+
827
+ assert_tool :email do |input, output|
828
+ assert_equal "newuser@example.com", input[:to]
829
+ assert output[:message_id].present?
830
+ end
831
+
832
+ assert_event :onboarding_complete
833
+ assert_total_cost_under 0.10 # $0.10
834
+ assert_duration_under 3000 # 3 seconds
835
+ end
836
+ end
837
+
838
+ test "handles existing user" do
839
+ create_user(email: "existing@example.com")
840
+
841
+ assert_flow_error :user_exists do
842
+ run_flow(email: "existing@example.com")
843
+ end
844
+ end
845
+ end
846
+ ```
847
+
848
+ #### Contract Testing
849
+
850
+ ```ruby
851
+ # Automatically generated from tool definitions
852
+ describe Tools::SendEmail do
853
+ test_contract do
854
+ # Tests each example defined in the tool
855
+ example "welcome_email" do
856
+ assert_input_valid
857
+ assert_output_matches_schema
858
+ assert_idempotent
859
+ end
860
+
861
+ # Property-based testing
862
+ property "handles all valid emails" do
863
+ email = generate(:email)
864
+ result = call(to: email, subject: "Test", body_html: "<p>Test</p>")
865
+ assert result[:message_id].present?
866
+ end
867
+ end
868
+ end
869
+ ```
870
+
871
+ ### 9. Security & Governance
872
+
873
+ #### Capability-Based Security
874
+
875
+ ```ruby
876
+ flow "process_payment",
877
+ capabilities: [
878
+ "repo:orders:read",
879
+ "repo:payments:write",
880
+ "tool:charge_card:max_amount:10000",
881
+ "tool:send_email:domain:receipts@myapp.com",
882
+ "ai:gpt-4o-mini:max_tokens:500"
883
+ ] do
884
+
885
+ # Runtime enforces capability boundaries
886
+ step :order do
887
+ Repo[:orders].find(id: params[:order_id]) # ✓ Allowed (read)
888
+ # Repo[:orders].update(...) would fail - no write capability
889
+ end
890
+
891
+ tool :charge, Tools::ChargeCard,
892
+ amount: steps.order.amount # Runtime validates against max_amount
893
+
894
+ # This would fail - domain not in capabilities
895
+ # tool :email, Tools::SendEmail, to: "admin@evil.com"
896
+ end
897
+
898
+ # Capabilities can be delegated
899
+ sub_flow "send_receipt",
900
+ inherit_capabilities: ["tool:send_email:domain:receipts@myapp.com"] do
901
+ # Can only send to receipts@myapp.com
902
+ end
903
+ ```
904
+
905
+ #### Policy Engine
906
+
907
+ ```yaml
908
+ # config/policies.yml
909
+ policies:
910
+ flows:
911
+ - pattern: "process_payment"
912
+ rules:
913
+ max_amount_cents: 100000
914
+ require_human_approval: "amount_cents > 50000"
915
+ rate_limit: "100/hour"
916
+ require_2fa: true
917
+
918
+ - pattern: "delete_*"
919
+ rules:
920
+ require_human_approval: true
921
+ audit_log: enhanced
922
+
923
+ tools:
924
+ - name: "send_email"
925
+ rules:
926
+ forbidden_domains: ["competitor.com", "spam.net"]
927
+ rate_limit: "10/minute per recipient"
928
+ require_spf_check: true
929
+
930
+ - name: "charge_card"
931
+ rules:
932
+ test_mode: "Rails.env.development?"
933
+ fraud_check: "amount > 1000"
934
+
935
+ ai:
936
+ - model: "gpt-4o"
937
+ rules:
938
+ max_tokens: 2000
939
+ require_approval: "tokens > 1000"
940
+ log_prompts: true
941
+
942
+ - model: "gpt-4o-mini"
943
+ rules:
944
+ max_tokens: 500
945
+ temperature_max: 0.8
946
+ ```
947
+
948
+ #### Audit Logging
949
+
950
+ ```ruby
951
+ # Every action is logged with full context
952
+ AuditLog.recent
953
+ # =>
954
+ # [
955
+ # {
956
+ # action: "flow.executed",
957
+ # flow: "process_payment",
958
+ # user_id: 123,
959
+ # run_id: "run_xyz",
960
+ # capabilities_used: ["repo:payments:write", "tool:charge_card"],
961
+ # cost_cents: 0.0234,
962
+ # ip: "192.168.1.1",
963
+ # timestamp: "2024-01-15T10:00:00Z"
964
+ # }
965
+ # ]
966
+ ```
967
+
968
+ ### 10. Deployment & Production
969
+
970
+ #### Configuration
971
+
972
+ ```ruby
973
+ # config/hypervibe.rb
974
+ Hypervibe.configure do |config|
975
+ # Database pools
976
+ config.database_url = ENV["DATABASE_URL"]
977
+ config.read_replica_urls = [
978
+ ENV["READ_REPLICA_1"],
979
+ ENV["READ_REPLICA_2"]
980
+ ]
981
+
982
+ # Redis for caching & queues
983
+ config.redis_url = ENV["REDIS_URL"]
984
+
985
+ # AI Models
986
+ config.ai_providers = {
987
+ openai: {api_key: ENV["OPENAI_API_KEY"]},
988
+ anthropic: {api_key: ENV["ANTHROPIC_API_KEY"]},
989
+ local: {url: "http://localhost:11434"} # Ollama
990
+ }
991
+
992
+ # Observability
993
+ config.telemetry = {
994
+ provider: :datadog,
995
+ api_key: ENV["DD_API_KEY"],
996
+ service_name: "hypervibe-app"
997
+ }
998
+
999
+ # Storage
1000
+ config.event_store = :postgres # or :kafka, :eventstore
1001
+ config.file_storage = :s3 # or :disk, :gcs
1002
+ end
1003
+ ```
1004
+
1005
+ #### Deployment Commands
1006
+
1007
+ ```bash
1008
+ # Database setup
1009
+ vibe db:create
1010
+ vibe db:migrate
1011
+ vibe db:seed
1012
+
1013
+ # Generate TypeScript types from schemas
1014
+ vibe generate:types
1015
+
1016
+ # Run tests
1017
+ vibe test
1018
+ vibe test:golden # Run golden prompt tests
1019
+ vibe test:contracts # Test tool contracts
1020
+
1021
+ # Production deployment
1022
+ vibe deploy --environment production
1023
+
1024
+ # Scale workers
1025
+ vibe scale flow_workers=10
1026
+ vibe scale tool_workers=5
1027
+
1028
+ # Monitor
1029
+ vibe logs --tail
1030
+ vibe metrics
1031
+ vibe traces --flow onboard_user
1032
+ ```
1033
+
1034
+ ### 11. Migration from Rails/Sinatra
1035
+
1036
+ Hypervibe can be gradually adopted in existing apps:
1037
+
1038
+ ```ruby
1039
+ # In Rails app - mount Hypervibe
1040
+ # config/routes.rb
1041
+ Rails.application.routes.draw do
1042
+ mount Hypervibe::Web, at: "/flows"
1043
+
1044
+ # Existing routes still work
1045
+ resources :users
1046
+ resources :posts
1047
+ end
1048
+
1049
+ # Gradually migrate controllers to flows
1050
+ class UsersController < ApplicationController
1051
+ def create
1052
+ # Old code still works
1053
+ @user = User.create!(user_params)
1054
+
1055
+ # But trigger flows for new functionality
1056
+ Flow.run_async("onboard_user",
1057
+ email: @user.email,
1058
+ name: @user.name
1059
+ )
1060
+
1061
+ redirect_to @user
1062
+ end
1063
+ end
1064
+
1065
+ # Share database connections
1066
+ Hypervibe.configure do |config|
1067
+ config.database = ActiveRecord::Base.connection_pool
1068
+ end
1069
+
1070
+ # Reuse existing models if needed (read-only)
1071
+ class User < ActiveRecord::Base
1072
+ # Existing AR model
1073
+ end
1074
+
1075
+ # But write through repositories
1076
+ Repo[:users].create_user(...) # Uses SQL directly
1077
+ ```
1078
+
1079
+ ### 12. Project Structure
1080
+
1081
+ ```
1082
+ my_app/
1083
+ ├── app/
1084
+ │ ├── queries/ # SQL files (source of truth)
1085
+ │ │ ├── users.sql
1086
+ │ │ ├── posts.sql
1087
+ │ │ ├── embeddings.sql
1088
+ │ │ └── analytics.sql
1089
+ │ ├── tools/ # Reusable tools with contracts
1090
+ │ │ ├── send_email.rb
1091
+ │ │ ├── charge_card.rb
1092
+ │ │ ├── generate_pdf.rb
1093
+ │ │ └── slack_notifier.rb
1094
+ │ ├── flows/ # Business workflows
1095
+ │ │ ├── onboard_user.rb
1096
+ │ │ ├── process_order.rb
1097
+ │ │ ├── weekly_digest.rb
1098
+ │ │ └── data_pipeline.rb
1099
+ │ ├── prompts/ # Versioned prompt templates
1100
+ │ │ ├── summarizer.prompt.rb
1101
+ │ │ ├── email_writer.prompt.rb
1102
+ │ │ └── code_reviewer.prompt.rb
1103
+ │ └── projections/ # Event projections for read models
1104
+ │ ├── user_stats.rb
1105
+ │ └── revenue_dashboard.rb
1106
+
1107
+ ├── config/
1108
+ │ ├── hypervibe.rb # Main configuration
1109
+ │ ├── policies.yml # Security policies
1110
+ │ └── database.yml # Database configuration
1111
+
1112
+ ├── generated/ # Auto-generated (git-ignored)
1113
+ │ ├── repos/ # Type-safe query modules
1114
+ │ ├── openapi.json # API documentation
1115
+ │ ├── tool_specs.json # LLM tool definitions
1116
+ │ └── types.ts # TypeScript definitions
1117
+
1118
+ ├── test/
1119
+ │ ├── flows/ # Flow tests with golden examples
1120
+ │ ├── tools/ # Tool contract tests
1121
+ │ ├── prompts/ # Prompt regression tests
1122
+ │ └── fixtures/ # Recorded AI responses
1123
+
1124
+ ├── web/ # Optional web UI
1125
+ │ ├── traces/ # Trace viewer
1126
+ │ └── dashboard/ # Metrics dashboard
1127
+
1128
+ └── Vibefile # Project configuration
1129
+ ```
1130
+
1131
+ ### 13. Example: Complete Feature Implementation
1132
+
1133
+ Here's how you'd implement a complete feature in Hypervibe:
1134
+
1135
+ ```sql
1136
+ -- queries/articles.sql
1137
+
1138
+ -- name: CreateArticle :one
1139
+ INSERT INTO articles (author_id, title, content, status)
1140
+ VALUES ($1, $2, $3, 'draft')
1141
+ RETURNING *;
1142
+
1143
+ -- name: PublishArticle :one
1144
+ UPDATE articles
1145
+ SET status = 'published', published_at = NOW()
1146
+ WHERE id = $1
1147
+ RETURNING *;
1148
+
1149
+ -- name: GetArticleWithAuthor :one
1150
+ SELECT
1151
+ a.*,
1152
+ u.name as author_name,
1153
+ u.email as author_email
1154
+ FROM articles a
1155
+ JOIN users u ON u.id = a.author_id
1156
+ WHERE a.id = $1;
1157
+ ```
1158
+
1159
+ ```ruby
1160
+ # tools/moderate_content.rb
1161
+ class Tools::ModerateContent
1162
+ include Hypervibe::Tool
1163
+
1164
+ tool "moderate_content",
1165
+ desc: "Check content for policy violations",
1166
+ input: {
1167
+ content: {type: "string", required: true},
1168
+ content_type: {type: "string", enum: ["article", "comment"]}
1169
+ },
1170
+ output: {
1171
+ safe: {type: "boolean"},
1172
+ issues: {type: "array", items: {type: "string"}},
1173
+ confidence: {type: "number"}
1174
+ }
1175
+
1176
+ def call(content:, content_type:)
1177
+ result = AI.moderate(content)
1178
+
1179
+ {
1180
+ safe: result[:safe],
1181
+ issues: result[:issues],
1182
+ confidence: result[:confidence]
1183
+ }
1184
+ end
1185
+ end
1186
+ ```
1187
+
1188
+ ```ruby
1189
+ # flows/publish_article.rb
1190
+ flow "publish_article",
1191
+ stream: true,
1192
+ timeout: 30.seconds do
1193
+
1194
+ step :article do
1195
+ Repo[:articles].get_article_with_author(id: params[:article_id])
1196
+ end
1197
+
1198
+ guard "author must match" do
1199
+ steps.article.author_id == params[:user_id]
1200
+ end
1201
+
1202
+ tool :moderation, Tools::ModerateContent,
1203
+ content: steps.article.content,
1204
+ content_type: "article"
1205
+
1206
+ guard "content must be safe" do
1207
+ steps.moderation.safe
1208
+ end
1209
+
1210
+ ai :improvements,
1211
+ model: "gpt-4o-mini",
1212
+ optional: true, # Don't fail if AI is down
1213
+ schema: {
1214
+ type: "object",
1215
+ properties: {
1216
+ seo_title: {type: "string", maxLength: 60},
1217
+ meta_description: {type: "string", maxLength: 160},
1218
+ tags: {type: "array", items: {type: "string"}}
1219
+ }
1220
+ } do
1221
+ system "You are an SEO expert."
1222
+ user "Generate SEO metadata for: {{ steps.article.title }}"
1223
+ end
1224
+
1225
+ step :publish do
1226
+ article = Repo[:articles].publish_article(id: params[:article_id])
1227
+
1228
+ if steps.improvements
1229
+ Repo[:articles].update_metadata(
1230
+ id: article.id,
1231
+ seo_title: steps.improvements["seo_title"],
1232
+ meta_description: steps.improvements["meta_description"],
1233
+ tags: steps.improvements["tags"]
1234
+ )
1235
+ end
1236
+
1237
+ article
1238
+ end
1239
+
1240
+ parallel do
1241
+ tool :notify_followers, Tools::NotifyFollowers,
1242
+ author_id: steps.article.author_id,
1243
+ article_id: steps.article.id
1244
+
1245
+ tool :index_search, Tools::IndexForSearch,
1246
+ type: "article",
1247
+ id: steps.article.id,
1248
+ content: steps.article.content
1249
+
1250
+ tool :social_share, Tools::ScheduleSocialPosts,
1251
+ article_id: steps.article.id,
1252
+ platforms: ["twitter", "linkedin"]
1253
+ end
1254
+
1255
+ emit :article_published, {
1256
+ article_id: steps.article.id,
1257
+ author_id: steps.article.author_id,
1258
+ published_at: steps.publish.published_at
1259
+ }
1260
+ end
1261
+ ```
1262
+
1263
+ ### 14. Advanced Features
1264
+
1265
+ #### Sub-flows and Composition
1266
+
1267
+ ```ruby
1268
+ flow "process_batch",
1269
+ concurrency: 10 do
1270
+
1271
+ step :items do
1272
+ Repo[:queue].get_pending_items(limit: 100)
1273
+ end
1274
+
1275
+ # Process items in parallel with sub-flows
1276
+ map :processed, over: steps.items do |item|
1277
+ sub_flow "process_item",
1278
+ item_id: item.id,
1279
+ inherit_capabilities: true
1280
+ end
1281
+
1282
+ # Aggregate results
1283
+ reduce :summary do
1284
+ {
1285
+ total: steps.processed.count,
1286
+ successful: steps.processed.count(&:success?),
1287
+ failed: steps.processed.count(&:failed?),
1288
+ total_cost: steps.processed.sum(&:cost)
1289
+ }
1290
+ end
1291
+
1292
+ emit :batch_complete, steps.summary
1293
+ end
1294
+ ```
1295
+
1296
+ #### Human-in-the-Loop
1297
+
1298
+ ```ruby
1299
+ flow "content_review" do
1300
+ ai :draft,
1301
+ model: "gpt-4o" do
1302
+ system "Write an article about AI safety"
1303
+ end
1304
+
1305
+ # Pause for human review
1306
+ checkpoint :human_review,
1307
+ timeout: 24.hours,
1308
+ notify: ["editor@example.com"] do
1309
+
1310
+ present steps.draft
1311
+
1312
+ actions [
1313
+ {label: "Approve", value: "approve"},
1314
+ {label: "Request Changes", value: "revise"},
1315
+ {label: "Reject", value: "reject"}
1316
+ ]
1317
+ end
1318
+
1319
+ case steps.human_review.action
1320
+ when "approve"
1321
+ tool :publish, Tools::PublishArticle,
1322
+ content: steps.draft
1323
+ when "revise"
1324
+ ai :revision do
1325
+ system "Revise based on feedback"
1326
+ user "Feedback: {{ steps.human_review.feedback }}"
1327
+ end
1328
+ # Loop back to human review
1329
+ goto :human_review
1330
+ when "reject"
1331
+ emit :rejected
1332
+ end
1333
+ end
1334
+ ```
1335
+
1336
+ #### Event Projections
1337
+
1338
+ ```ruby
1339
+ # projections/user_activity.rb
1340
+ projection "user_activity" do
1341
+ # Subscribe to events
1342
+ on "user_created" do |event|
1343
+ Repo[:analytics].increment_counter(
1344
+ metric: "users.total",
1345
+ date: event.timestamp.to_date
1346
+ )
1347
+ end
1348
+
1349
+ on "article_published" do |event|
1350
+ Repo[:analytics].track_activity(
1351
+ user_id: event.author_id,
1352
+ action: "published_article",
1353
+ timestamp: event.timestamp
1354
+ )
1355
+ end
1356
+
1357
+ # Materialize views
1358
+ every 5.minutes do
1359
+ Repo[:analytics].refresh_materialized_view("user_stats")
1360
+ end
1361
+ end
1362
+ ```
1363
+
1364
+ ## Getting Started
1365
+
1366
+ ### Quick Start
1367
+
1368
+ ```bash
1369
+ # Install Hypervibe
1370
+ gem install hypervibe
1371
+
1372
+ # Create a new project
1373
+ vibe new my_app
1374
+ cd my_app
1375
+
1376
+ # Set up the database
1377
+ vibe db:setup
1378
+
1379
+ # Generate your first flow
1380
+ vibe generate flow hello_world
1381
+
1382
+ # Start the development server
1383
+ vibe server
1384
+
1385
+ # In another terminal, run the flow
1386
+ vibe run hello_world name="World"
1387
+ ```
1388
+
1389
+ ### Your First Flow
1390
+
1391
+ ```ruby
1392
+ # app/flows/hello_world.rb
1393
+ flow "hello_world" do
1394
+ ai :greeting,
1395
+ model: "gpt-4o-mini",
1396
+ schema: {
1397
+ type: "object",
1398
+ properties: {
1399
+ message: {type: "string"},
1400
+ emoji: {type: "string"}
1401
+ }
1402
+ } do
1403
+ system "You are a friendly greeter"
1404
+ user "Say hello to {{ params.name }}"
1405
+ end
1406
+
1407
+ emit :greeted, {
1408
+ name: params.name,
1409
+ message: steps.greeting["message"],
1410
+ emoji: steps.greeting["emoji"]
1411
+ }
1412
+ end
1413
+ ```
1414
+
1415
+ ### CLI Commands
1416
+
1417
+ ```bash
1418
+ # Development
1419
+ vibe server # Start dev server with hot reload
1420
+ vibe console # Interactive Ruby console
1421
+ vibe test # Run test suite
1422
+
1423
+ # Generators
1424
+ vibe generate flow <name>
1425
+ vibe generate tool <name>
1426
+ vibe generate query <name>
1427
+
1428
+ # Database
1429
+ vibe db:create
1430
+ vibe db:migrate
1431
+ vibe db:seed
1432
+ vibe db:reset
1433
+
1434
+ # Production
1435
+ vibe deploy
1436
+ vibe scale <process>=<count>
1437
+ vibe logs --tail
1438
+ vibe metrics
1439
+
1440
+ # Tools & Flows
1441
+ vibe run <flow> [params]
1442
+ vibe tool <name> [params]
1443
+ vibe replay <run_id>
1444
+
1445
+ # Maintenance
1446
+ vibe traces:clean --before 30d
1447
+ vibe cache:clear
1448
+ vibe events:compact
1449
+ ```
1450
+
1451
+ ## Philosophy
1452
+
1453
+ Hypervibe embraces several core principles:
1454
+
1455
+ 1. **SQL is a Feature, Not a Bug**: LLMs understand SQL better than ORMs. We generate types from SQL, not the other way around.
1456
+
1457
+ 2. **Observability Over Debugging**: Every action leaves a trace. You can replay any flow execution and see exactly what happened.
1458
+
1459
+ 3. **Streams Over Requests**: AI is slow. Users need feedback. Everything streams by default.
1460
+
1461
+ 4. **Contracts Over Documentation**: JSON Schema defines everything. Tools, flows, and prompts all have contracts that are enforced at runtime.
1462
+
1463
+ 5. **Events Over State**: Event sourcing provides natural versioning, auditing, and time-travel debugging.
1464
+
1465
+ 6. **Composition Over Inheritance**: Small tools and flows compose into larger systems. No base classes or deep hierarchies.
1466
+
1467
+ ## Contributing
1468
+
1469
+ Hypervibe is open source and welcomes contributions. See [CONTRIBUTING.md](https://github.com/hypervibe/hypervibe/blob/main/CONTRIBUTING.md) for details.
1470
+
1471
+ ## License
1472
+
1473
+ MIT License. See [LICENSE](https://github.com/hypervibe/hypervibe/blob/main/LICENSE) for details.
1474
+
1475
+ ## Learn More
1476
+
1477
+ - **Documentation**: [hypervibe.dev](https://hypervibe.dev)
1478
+ - **Examples**: [github.com/hypervibe/examples](https://github.com/hypervibe/examples)
1479
+ - **Discord**: [discord.gg/hypervibe](https://discord.gg/hypervibe)
1480
+ - **Twitter**: [@hypervibeframework](https://twitter.com/hypervibeframework)
1481
+
1482
+ ---
1483
+
1484
+ Built for the age of AI-assisted development, where LLMs write the SQL and humans define the workflows.