vibe-ready 0.2.0

Composable runtime, logging, scheduling, and storage foundations for vibe-coding Rust projects.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
# vibe-ready

Composable runtime, logging, scheduling, and storage foundations for vibe-coding Rust projects.

`vibe-ready` is a small application foundation crate for developers who want to build quickly with AI coding tools. It gives an AI agent a stable set of primitives for project setup: a runtime engine, task execution, scheduled jobs, structured logs, persistent key-value storage, cancellation, status tracking, and a consistent error model.

The goal is simple: describe the product you want, tell your AI to use `vibe-ready`, and let it assemble the common project infrastructure from this crate instead of reinventing it.

## What You Get

- Engine lifecycle: create, run, inspect, and destroy a `VibeEngine`.
- Runtime execution: run futures synchronously with `invoke`, post background work with `post`, or use the lower-level `VibeEngineExecutor`.
- Callback pool: dispatch user callbacks away from async runtime threads with `VibeCallbackExecutor`.
- Scheduler: priority tasks, delayed tasks, periodic tasks, cancellation tokens, task handles, and task inspection.
- Key-value store: typed values, buckets, TTL, batch operations, transactions, change listeners, and expired-row cleanup.
- Configuration model: app identity, platform, runtime sizing, logging behavior, storage behavior, and backup strategy.
- Logging: structured log records, log listeners, stdout output, optional persistent log storage, standard log fields, and exported log macros.
- Storage backends: Diesel SQLite persistence by default, or no-op backends for tests and lightweight builds.
- Error model: stable error codes, error categories, messages, sources, and context breadcrumbs.
- Platform helpers: current time, async sleep, and task spawning helpers.
- AI-friendly public API: documented re-exports and a `prelude` for fast project bootstrapping.

## Installation

Add the crate to your Rust project:

```toml
[dependencies]
vibe-ready = "0.1.1"
```

For local development from this repository:

```toml
[dependencies]
vibe-ready = { path = "../vibe-ready" }
```

Default features enable SQLite-backed log and work storage:

```toml
[dependencies]
vibe-ready = { version = "0.1.1", features = ["log-diesel", "store-diesel-sqlite"] }
```

For tests or projects that do not need persistence:

```toml
[dependencies]
vibe-ready = { version = "0.1.1", default-features = false, features = ["log-noop", "store-noop"] }
```

## Quick Start

```rust
use std::time::Duration;
use vibe_ready::{VibeEngine, VibeEngineConfig, VibePlatformType, VibeResult};

fn main() -> VibeResult<()> {
    let config = VibeEngineConfig::builder()
        .platform(VibePlatformType::MacOS)
        .app_name("demo-app")
        .namespace("examples")
        .build();

    let engine = VibeEngine::create(config)?;

    engine.store().set_str("status", "ready")?;
    let status = engine.store().get_str("status")?;
    assert_eq!(status.as_deref(), Some("ready"));

    engine.post(async {
        println!("background task started");
    });

    engine.destroy_with_timeout(Duration::from_secs(2))?;
    Ok(())
}
```

## AI Agent Usage

This README is intentionally written so an AI coding agent can use `vibe-ready` as a project foundation without reading the entire source tree first.

### One-Line Prompt

Use this when asking an AI to build a Rust app:

```text
Build this Rust project using vibe-ready as the foundation: create a VibeEngine, configure app identity and storage, use VibeKvStore for local state, use the scheduler for background jobs, use structured logging, and return VibeResult from fallible app flows.
```

### Detailed AI Prompt

```text
You are building a Rust project with the vibe-ready crate.

Use vibe_ready::prelude::*.
Create configuration with VibeEngineConfig::builder().
Set app_name, namespace, platform, store_root_path when needed, and choose no-op backends for tests.
Create the runtime with VibeEngine::create(config) or VibeEngine::create_with_runtime_handle(config, handle).
Use engine.invoke for async work that must return a value synchronously.
Use engine.post for fire-and-forget async work.
Use engine.post_with_priority, schedule_after, and schedule_every for background jobs.
Use VibeCancellationToken in scheduled tasks and check token.is_cancelled() or await token.cancelled().
Use engine.tasks().list() and count() for diagnostics.
Use engine.store() for app state. Use set/get typed values, buckets, TTL, transactions, batch operations, and on_change listeners instead of creating ad hoc storage.
Use engine.insert_log, engine.set_log_listener, and log_i!/log_e! macros for structured logs.
Return VibeResult<T> from public fallible functions and attach context with VibeEngineError::with_context when useful.
Always call engine.destroy_with_timeout before shutdown in examples and tests.
```

### What AI Should Build With Each Capability

| Need | Use |
| --- | --- |
| App runtime foundation | `VibeEngine`, `VibeEngineConfig` |
| Shared project imports | `vibe_ready::prelude::*` |
| Local app state | `VibeKvStore` |
| Namespaced state | `VibeKvBucket` |
| Temporary state | `set_with_ttl`, `purge_expired` |
| Atomic state changes | `transaction`, `VibeKvTx` |
| React to state changes | `on_change`, `VibeKvChange` |
| Fire-and-forget background work | `VibeEngine::post` |
| Blocking wait for async result | `VibeEngine::invoke` |
| Priority background jobs | `post_with_priority`, `VibeTaskPriority` |
| Delayed or periodic jobs | `schedule_after`, `schedule_every` |
| Cooperative cancellation | `VibeCancellationToken`, `VibeTaskHandle::cancel` |
| Task diagnostics | `VibeTaskPanel`, `VibeTaskInfo` |
| Structured logs | `VibeLogInfo`, `VibeLogLevel`, `log_i!`, `log_e!` |
| Stable app errors | `VibeEngineError`, `VibeError`, `VibeErrorCode`, `VibeErrorKind`, `VibeResult`, `err!` |
| Platform time/spawn helpers | `vibe_ready::platform::{now, sleep, spawn}` |
| Advanced storage access | `VibeDbClient`, `VibeTableKeyVal`, `VibeDbErrorInfo` |
| JSON/display utility macros | `array_to_json_string!`, `obj_array_to_json_string!`, `basic_type_map_to_json_string!`, `impl_display_json!` |

## Core Concepts

### Engine

`VibeEngine` is the main entry point. It owns or connects to a Tokio runtime, initializes logging and work storage, exposes a task executor, and gives the application access to a key-value store.

```rust
use vibe_ready::{VibeEngine, VibeEngineConfig, VibePlatformType, VibeResult};

fn create_engine() -> VibeResult<VibeEngine> {
    let config = VibeEngineConfig::builder()
        .platform(VibePlatformType::MacOS)
        .app_name("my-product")
        .namespace("dev")
        .runtime_worker_threads(4)
        .callback_threads(2)
        .queue_capacity(1024, 256)
        .build();

    VibeEngine::create(config)
}
```

Use an external Tokio runtime when the host application already owns one:

```rust
use vibe_ready::{VibeEngine, VibeEngineConfig, VibeResult};

fn create_with_host_runtime(runtime: &tokio::runtime::Runtime) -> VibeResult<VibeEngine> {
    VibeEngine::create_with_runtime_handle(
        VibeEngineConfig::builder().app_name("hosted-app").build(),
        runtime.handle().clone(),
    )
}
```

### Configuration

`VibeEngineConfig::builder()` starts with defaults suitable for local development. Configure only what your app needs.

```rust
use vibe_ready::{
    VibeEngineConfig, VibeLogBackend, VibeLogLevel, VibePlatformType, VibeStoreBackend,
};

let config = VibeEngineConfig::builder()
    .platform(VibePlatformType::MacOS)
    .store_root_path("./.vibe-ready")
    .app_name("notes-app")
    .namespace("local")
    .log_backend(VibeLogBackend::DieselSqlite)
    .log_level(VibeLogLevel::Info)
    .log_write_to_store(true)
    .log_output_stdout(true)
    .log_retention_days(7)
    .log_max_rows(120_000)
    .store_backend(VibeStoreBackend::DieselSqlite)
    .encrypt(false)
    .runtime_worker_threads(4)
    .callback_threads(3)
    .queue_capacity(1024, 256)
    .priority_queue_capacity(1024)
    .build();

config.validate().expect("valid configuration");
```

Important configuration fields:

- `app_name`: the application identity used in storage paths and log user ids.
- `namespace`: a logical environment, tenant, or product namespace.
- `store_root_path`: root path for SDK-managed data.
- `log`: log backend, level, stdout behavior, persistence, and retention.
- `store`: work-store backend, encryption request, and backup strategy.
- `runtime`: Tokio worker threads, callback threads, task queue sizes, and scheduler lane capacity.

Configuration types and options:

- `VibeAppConfig`: explicit `app_name` and `namespace` values.
- `VibeLogConfig`: log backend, level, persistence, stdout output, retention days, and max rows.
- `VibeStoreConfig`: store backend, encryption request, and backup strategy.
- `VibeRuntimeConfig`: runtime worker threads, callback threads, async/sync queue capacities, and priority queue capacity.
- `VibeLogBackend`: `Noop` or `DieselSqlite`.
- `VibeStoreBackend`: `Noop` or `DieselSqlite`.
- `VibeBackupStrategy`: `Disabled` or `Manual`.
- `VibePlatformType`: platform identity. Variants: `Android`, `IOS`, `HarmonyOS`, `Windows`, `MacOS`, `Linux`, `Electron`, `Web`, `HarmonyOSPC`, `MiniWeb`, `PC`, `IPad`, `APad`, `HPad`, `Unknown`.

The builder is the recommended entry point, but a constructed `VibeEngineConfig` also exposes read-only getters that an AI agent can use for diagnostics: `store_path()`, `is_encrypt()`, `platform()`, `app_name()`, `namespace()`, `log_config()`, `store_config()`, `runtime_config()`, and `app_store_path()`.

### Runtime Execution

Use `invoke` when the caller needs a result:

```rust
use vibe_ready::{VibeEngine, VibeEngineConfig, VibeResult};

fn compute() -> VibeResult<i32> {
    let engine = VibeEngine::create(VibeEngineConfig::builder().app_name("compute").build())?;
    let answer = engine.invoke(async { 40 + 2 })?;
    engine.destroy_with_timeout(std::time::Duration::from_secs(1))?;
    Ok(answer)
}
```

Use `post` when the caller does not need a result:

```rust
engine.post(async move {
    println!("fire-and-forget work");
});
```

Use `executor()` for advanced integrations:

```rust
// In a function that returns VibeResult<()>:
let executor = engine.executor();
executor.post(async {})?;
let callbacks = executor.callback();
callbacks.execute(|| println!("callback on callback pool"));
```

`VibeCallbackExecutor` also exposes `once`, `once2`, and `once3` helpers that wrap a closure so it runs on the callback pool when invoked with one, two, or three arguments. `VibeEngine` re-exports the one-argument and two-argument shortcuts as `cb_pool_once` and `cb_pool_once2` for AI-generated bridging code that needs to hand a callback to native or FFI layers.

### Scheduler

The scheduler handles priority, delayed, and periodic work.

```rust
use std::time::Duration;
use vibe_ready::{VibeTaskPriority, VibeResult};

// In a function that receives engine: &VibeEngine and returns VibeResult<()>:
let handle = engine.post_with_priority("refresh-cache", VibeTaskPriority::High, async move {
    println!("high-priority task");
})?;

assert_eq!(handle.name(), "refresh-cache");

let delayed = engine.schedule_after("warmup", Duration::from_secs(5), |token| async move {
    if !token.is_cancelled() {
        println!("warmup after delay");
    }
})?;

let periodic = engine.schedule_every("heartbeat", Duration::from_secs(30), |token| async move {
    if token.is_cancelled() {
        return;
    }
    println!("heartbeat");
})?;

periodic.cancel();
let task_count = engine.tasks().count()?;
let snapshots = engine.tasks().list()?;

drop((handle, delayed, task_count, snapshots));
```

Scheduler types:

- `VibeTaskPriority`: `High`, `Normal`, `Low`.
- `VibeTaskKind`: `Once`, `Delayed`, `Periodic`.
- `VibeTaskState`: `Pending`, `Running`, `Completed`, `Cancelled`, `Failed`.
- `VibeTaskHandle` methods: `id()`, `name()`, `kind()`, `priority()`, `state()`, `token()`, `info()`, `cancel()`, `is_finished()`, and `join().await`.
- `VibeTaskPanel` methods: `list() -> Result<Vec<VibeTaskInfo>>`, `count() -> Result<usize>`.
- `VibeCancellationToken` methods: `cancel()`, `is_cancelled()`, and `cancelled().await`.

### Key-Value Store

`VibeKvStore` is the high-level app state API. It supports typed values, named buckets, TTL, batch operations, transactions, and listeners.

```rust
use std::time::Duration;
use vibe_ready::{VibeEngine, VibeEngineConfig, VibeKvValue, VibeResult};

fn use_store() -> VibeResult<()> {
    let engine = VibeEngine::create(VibeEngineConfig::builder().app_name("store-demo").build())?;
    let store = engine.store();

    store.set_str("name", "vibe")?;
    store.set_bool("enabled", true)?;
    store.set_i32("count", 3)?;
    store.set("score", 99_i64)?;
    store.set("ratio", 0.75_f64)?;
    store.set("payload", vec![1_u8, 2, 3])?;
    store.set("json", serde_json::json!({ "ready": true }))?;

    assert_eq!(store.get_str("name")?, Some("vibe".to_string()));
    assert_eq!(store.get("count")?, Some(VibeKvValue::I32(3)));

    store.set_with_ttl("session", "temporary", Duration::from_secs(60))?;

    engine.destroy_with_timeout(Duration::from_secs(1))?;
    Ok(())
}
```

Use buckets for logical separation:

```rust
// In a function that returns VibeResult<()>:
let settings = engine.store().bucket("settings");
settings.set("theme", "dark")?;
assert_eq!(settings.name(), "settings");
```

Use batch operations when writing or reading multiple keys:

```rust
// In a function that returns VibeResult<()>:
let store = engine.store();
store.set_many(vec![("a", 1_i32), ("b", 2_i32)])?;
let values = store.get_many(vec!["a", "b"])?;
store.remove_many(vec!["a", "b"])?;
drop(values);
```

Use inspection and maintenance helpers when an AI agent needs to introspect or clean state:

```rust
// In a function that returns VibeResult<()>:
let store = engine.store();
let exists = store.contains("name")?;
let keys = store.list_keys()?;
let removed_expired_rows = store.purge_expired()?;
drop((exists, keys, removed_expired_rows));
```

Use transactions for atomic state changes:

```rust
// In a function that returns VibeResult<()>:
let result = engine.store().transaction(|tx| {
    tx.set("current_user", "alice")?
        .set_with_ttl("session", "token", std::time::Duration::from_secs(3600))?
        .remove("stale_user")?;
    Ok("committed")
})?;

assert_eq!(result, "committed");
```

Use listeners to react to state changes:

```rust
// In a function that returns VibeResult<()>:
let store = engine.store();
let listener_id = store.on_change("user*", |change| {
    println!("{} changed in bucket {}", change.key, change.bucket);
});

store.set_str("user.name", "Alice")?;
assert!(store.off_change(listener_id));
```

Pattern matching supports:

- exact keys, for example `"user.name"`;
- all keys with `"*"`;
- one trailing wildcard, for example `"user*"`.

### Logging

Use engine logging for explicit log entries:

```rust
use vibe_ready::VibeLogLevel;

engine.insert_log(true, VibeLogLevel::Info, "startup".into(), "ready".into());
engine.set_log_listener(Some(Box::new(|info| {
    println!("log: {:?} {} {}", info.level, info.tag, info.content);
})));
```

Use exported macros for structured logs:

```rust
vibe_ready::log_i!("startup", "status", "ready");
vibe_ready::log_s!("store", "key|result", "status", "ok");
vibe_ready::log_e!("network", "reason", "timeout");
```

Available log helpers:

- `log_i!`: info log.
- `log_i_!`: info log with an extension segment.
- `log_t!`: info trace-style log.
- `log_t_!`: info trace-style log with an extension segment.
- `log_r!`: debug read-style log.
- `log_r_!`: debug read-style log with an extension segment.
- `log_s!`: debug state-style log.
- `log_s_!`: debug state-style log with an extension segment.
- `log_e!`: error log.
- `log_e_!`: error log with an extension segment.

Standard log field constants are also exported for consistent structured payloads:

- `CODE_STR`: field name for error or status codes.
- `DESC`: field name for human-readable descriptions.
- `RET_STR`: field name for return values.

### Errors

Most fallible APIs return `VibeResult<T>`, an alias for `Result<T, VibeEngineError>`.

```rust
use vibe_ready::{VibeEngineError, VibeErrorCode, VibeResult};

fn fail_with_context() -> VibeResult<()> {
    Err(VibeEngineError::from_error_code(VibeErrorCode::RuntimeError)
        .with_context("failed while starting background workers"))
}
```

Useful error APIs:

- `from_error_code(VibeErrorCode)`: construct an error from a stable error code.
- `from_success()`: construct a success sentinel value.
- `is_success()`: check whether an error represents success.
- `from_u16(u16)` / `from_u32(u32)`: construct an error from a raw numeric code.
- `code()`: stable numeric code.
- `kind()`: high-level `VibeErrorKind` category.
- `message()`: human-readable message.
- `source_message()`: optional lower-level source.
- `context()`: context breadcrumb list.
- `with_source(...)`: attach source text.
- `with_context(...)`: attach context text.

Use `err!` when you want to log an error with a backtrace and return the same error expression:

```rust
use vibe_ready::{err, VibeEngineError, VibeErrorCode};

let error = err!(VibeEngineError::from_error_code(VibeErrorCode::RuntimeError));
assert_eq!(error.code(), VibeErrorCode::RuntimeError.code());
```

### Utility Macros

`vibe-ready` also exports small utility macros used by generated projects and logging helpers:

```rust
let values = vec![1, 2, 3];
let json = vibe_ready::array_to_json_string!(values);
assert_eq!(json, "[1,2,3]");
```

- `array_to_json_string!`: serializes an array-like value to JSON.
- `obj_array_to_json_string!`: renders displayable objects as a JSON-array-like string.
- `basic_type_map_to_json_string!`: serializes a string-keyed map of basic values to JSON.
- `impl_display_json!`: implements `Display` for serializable types by rendering JSON.

### Platform Helpers

```rust
let timestamp_ms = vibe_ready::platform::now();

vibe_ready::platform::spawn(async move {
    vibe_ready::platform::sleep(std::time::Duration::from_millis(10)).await;
    println!("spawned at {}", timestamp_ms);
});
```

### Capabilities

Use `VibeCapabilities` to inspect compile-time support:

```rust
let capabilities = vibe_ready::VibeCapabilities::current();
println!("log store: {}", capabilities.log_store);
println!("work store: {}", capabilities.work_store);
```

Fields:

- `log_store`: log persistence support is compiled in.
- `work_store`: work/key-value persistence support is compiled in.
- `network`: reserved network API support flag.
- `encryption`: reserved encryption support flag.
- `wasm`: current target is WebAssembly.
- `tracing`: reserved tracing integration flag.
- `metrics`: reserved metrics integration flag.

### Status Manager

`VibeStatusManager` tracks `VibeConnectionStatus` and notifies a listener when the status changes. Most applications do not need it directly, but integrations can use it for connection-like workflows.

```rust
use vibe_ready::{VibeConnectionStatus, VibeStatusManager, VibeResult};

async fn status_flow() -> VibeResult<()> {
    let manager = VibeStatusManager::new();
    manager
        .set_connection_status_listener(Some(Box::new(|status| {
            println!("status changed: {status}");
        })))
        .await;
    manager
        .set_connection_status(VibeConnectionStatus::Connecting)
        .await?;
    manager
        .set_connection_status(VibeConnectionStatus::Connected)
        .await?;
    Ok(())
}
```

### Advanced Database APIs

Prefer `VibeKvStore` for application state. Use `VibeDbClient` only when an integration needs lower-level row access or custom database operations.

```rust
use vibe_ready::{VibeDbClient, VibeKvValue, VibeStoreBackend};

async fn low_level_store() -> vibe_ready::VibeResult<()> {
    let client = VibeDbClient::with_backend(VibeStoreBackend::Noop);
    client
        .try_open("./.vibe-ready/work".into(), "dev:advanced".to_string(), false)
        .await?;
    client.set("key".to_string(), VibeKvValue::from("value")).await?;
    client.close().await?;
    Ok(())
}
```

Advanced row types:

- `VibeKvValue`: typed value enum for string, bool, i32, i64, f64, bytes, and JSON.
- `VibeTableKeyVal`: row representation for low-level storage APIs.
- `VibeDbErrorInfo`: database backend error details.
- `DbError`: database error category.

## Feature Flags

| Feature | Default | Purpose |
| --- | --- | --- |
| `log-diesel` | Yes | Enables Diesel SQLite log persistence. |
| `store-diesel-sqlite` | Yes | Enables Diesel SQLite work/key-value persistence. |
| `log-noop` | No | Compatibility feature for no-op log behavior. |
| `store-noop` | No | Compatibility feature for no-op store behavior. |

No-op backends are always available at runtime through `VibeLogBackend::Noop` and `VibeStoreBackend::Noop`. They are useful for tests, examples, and generated prototypes.

## Common Recipes for AI-Generated Projects

### CLI Tool With Persistent State

Tell your AI:

```text
Use vibe-ready to create a CLI app. Store user settings in engine.store().bucket("settings"), use VibeResult for fallible commands, and call destroy_with_timeout before process exit.
```

Implementation shape:

```rust
use vibe_ready::prelude::*;

fn run() -> VibeResult<()> {
    let engine = VibeEngine::create(
        VibeEngineConfig::builder()
            .app_name("my-cli")
            .namespace("prod")
            .build(),
    )?;

    let settings = engine.store().bucket("settings");
    settings.set("first_run", false)?;

    engine.destroy_with_timeout(std::time::Duration::from_secs(2))?;
    Ok(())
}
```

### Background Worker

Tell your AI:

```text
Use vibe-ready to create a background worker. Use schedule_every for periodic sync, VibeCancellationToken for cooperative cancellation, engine.tasks() for diagnostics, and structured logs for each run.
```

Implementation shape:

```rust
use std::time::Duration;
use vibe_ready::prelude::*;

fn start_worker(engine: &VibeEngine) -> VibeResult<VibeTaskHandle> {
    engine.schedule_every("sync", Duration::from_secs(60), |token| async move {
        if token.is_cancelled() {
            return;
        }
        vibe_ready::log_i!("sync", "status", "tick");
    })
}
```

### Local-First App Prototype

Tell your AI:

```text
Use vibe-ready to build a local-first prototype. Put domain state in named VibeKvStore buckets, use transactions for multi-key changes, and use on_change listeners to update derived state.
```

Implementation shape:

```rust
use vibe_ready::prelude::*;

fn create_note(engine: &VibeEngine, id: &str, title: &str) -> VibeResult<()> {
    let notes = engine.store().bucket("notes");
    notes.transaction(|tx| {
        tx.set(format!("note:{id}:title"), title)?;
        tx.set(format!("note:{id}:updated"), vibe_ready::platform::now() as i64)?;
        Ok(())
    })
}
```

### Test-Friendly Generated Code

Tell your AI:

```text
When writing tests with vibe-ready, configure VibeLogBackend::Noop and VibeStoreBackend::Noop unless persistence behavior is under test.
```

Implementation shape:

```rust
use vibe_ready::prelude::*;

fn test_config() -> VibeEngineConfig {
    VibeEngineConfig::builder()
        .app_name("test-app")
        .namespace("tests")
        .log_backend(VibeLogBackend::Noop)
        .store_backend(VibeStoreBackend::Noop)
        .runtime_worker_threads(1)
        .callback_threads(1)
        .queue_capacity(16, 8)
        .build()
}
```

## Public API Map

Most users should import from the prelude:

```rust
use vibe_ready::prelude::*;
```

Important exported types:

- Engine and configuration: `VibeEngine`, `VibeEngineState`, `VibeEngineConfig`, `VibeEngineConfigBuilder`, `VibeEngineContext`, `VibeAppConfig`, `VibeBackupStrategy`, `VibeRuntimeConfig`, `VibeStoreConfig`, `VibeStoreBackend`.
- Runtime: `VibeEngineExecutor`, `VibeCallbackExecutor`.
- Scheduler: `VibeTaskHandle`, `VibeTaskInfo`, `VibeTaskKind`, `VibeTaskPanel`, `VibeTaskPriority`, `VibeTaskState`, `VibeCancellationToken`.
- Store: `VibeKvStore`, `VibeKvBucket`, `VibeKvTx`, `VibeKvValue`, `VibeKvChange`, `VibeKvChangeKind`, `VibeKvListenerId`.
- Database: `VibeDbClient`, `VibeTableKeyVal`, `VibeDbErrorInfo`, `DbError`.
- Logging: `VibeLogConfig`, `VibeLogBackend`, `VibeLogInfo`, `VibeLogLevel`, `VibeLogListener`, `VibeLogger`, `CODE_STR`, `DESC`, `RET_STR`.
- Errors: `VibeEngineError`, `VibeError`, `VibeErrorCode`, `VibeErrorKind`, `VibeResult`.
- Platform and status: `VibePlatformType`, `VibeConnectionStatus`, `VibeStatusManager`, `VibeCapabilities`.

## Shutdown Pattern

Always shut down engines explicitly in examples, tests, and applications:

```rust
engine.destroy_with_timeout(std::time::Duration::from_secs(2))?;
```

Use `destroy` when you need callback-style reporting:

```rust
engine.destroy(|result| {
    if let Err(error) = result {
        eprintln!("shutdown failed: {error}");
    }
});
```

## Development

Useful commands for contributors and AI agents:

```bash
cargo fmt
RUSTDOCFLAGS="-D warnings -D missing_docs" cargo doc --no-deps
cargo test --doc
cargo test
```

## License

MIT