pywatt_sdk 0.2.8

Standardized SDK for building PyWatt modules in Rust
Documentation
---
description:
globs:
alwaysApply: false
---
@id pywatt-module-creation
@goal Create a PyWatt Rust module.
@keywords pywatt, module, sdk, rust, axum, serve_module, AppState, #[pywatt::module], secret, announce
@matches rust, (create|build|develop|make) .*pywatt module
@information
**Goal:** Develop a standalone Rust service (module) managed by the PyWatt orchestrator, typically exposing an Axum-based HTTP API.

**Core Components:**
* `pywatt_sdk`: The Rust SDK providing necessary functions and types.
* `axum`: Web framework for building the module's API.
* `tokio`: Async runtime.
* `serde`: For JSON serialization/deserialization (IPC, API).
* `tracing`: For logging.
* `secrecy`: For handling sensitive data (`SecretString`, `Secret<T>`).

**Development Approaches:**
1. **`#[pywatt::module]` Macro (Recommended):**
   * Requires `proc_macros` feature.
   * Annotate an `async fn(AppState<()>) -> Router`.
   * Macro generates `main` function, handles bootstrap, IPC, serving.
   * Simplifies boilerplate significantly.
   * Manages state via `AppState<()>` (SDK state only) + separate custom state (e.g., `Arc<Mutex<T>>`, Axum extensions).
   * Attributes: `secrets = [...]`, `health = "..."`, `metrics = bool`, `version = "vX"`.
   * Requires `build.rs` with `pywatt_sdk::build::emit_build_info()` for default health endpoint.
2. **`serve_module` Function (Manual):**
   * Provides full control over initialization.
   * Write `#[tokio::main] async fn main() -> Result<()>`.
   * Define initial `secret_keys: Vec<String>`.
   * Define `announced_endpoints: Vec<AnnouncedEndpoint>` OR use `discover_endpoints` feature (pass `vec![]`).
   * Provide `state_builder: Fn(&OrchestratorInit, Vec<SecretString>) -> T` closure.
   * Provide `router_builder: Fn(AppState<T>) -> Router` closure.
   * Call `serve_module(secret_keys, announced_endpoints, state_builder, router_builder).await?`.

**Key Types & Structs:**
* `AppState<T>`: Shared state (module_id, orchestrator_api, secret_client, user_state: T). Passed via `Extension` layer.
* `SecretClient`: Client for secret operations (`Arc<SecretClient>`).
* `OrchestratorInit`: Initial data from orchestrator (via `read_init()`).
* `ModuleAnnounce`: Message sent to orchestrator (via `send_announce()`).
* `AnnouncedEndpoint`: Describes a single API endpoint for announcement.
* `SecretString`, `Secret<T>`: Wrapper types for sensitive data.
* `Error`: SDK error enum.
* `Result<T>`: Alias for `Result<T, pywatt_sdk::Error>`.

**Key Functions & Macros:**
* `#[pywatt::module]`: Proc macro for simplified setup.
* `serve_module(...)`: Core function for manual setup.
* `pywatt_sdk::prelude::*`: Imports common items.
* `init_module()`: Initializes logging (called by `serve_module`/macro).
* `read_init()`: Reads handshake info from stdin.
* `get_module_secret_client()`: Creates `SecretClient`.
* `get_secret()`, `get_secrets()`, `get_typed_secret()`: Fetch secrets.
* `subscribe_secret_rotations()`: Register callback for secret updates.
* `send_announce()`: Send endpoint info to orchestrator.
* `process_ipc_messages()`: Background task listening on stdin (rotations, shutdown).
* `build::emit_build_info()`: Used in `build.rs` for build metadata.

**Important SDK Features (Cargo.toml):**
* `proc_macros`: Enables `#[pywatt::module]`.
* `router_ext`: Enables `RouterExt` trait (`.with_default_health()`, `.with_prometheus_metrics()`).
* `metrics`: Enables metrics endpoint functionality.
* `jwt_auth`: Provides JWT authentication tools.
* `discover_endpoints`: Enables automatic endpoint announcement from Router.
* `builder`: Enables `ModuleBuilder`, `AppStateBuilder`.

**Module Lifecycle:**
Start -> Logging Init -> Handshake (`read_init`) -> Secret Client Init -> Initial Secret Fetch -> State Build -> Router Build -> Announce (`send_announce`) -> IPC Loop (`process_ipc_messages`) -> Serve -> Shutdown (via IPC).

**Setup:**
* `Cargo.toml`: Add `pywatt_sdk` with desired features, `tokio`, `axum`, `serde`, `tracing`, `secrecy`.
* `build.rs`: Add if using `#[pywatt::module]` or `RouterExt::with_default_health()`.
* `src/main.rs`: Entry point for module logic.

**State Management (Axum):**
* Use `Extension<AppState<T>>` layer/extractor to access shared state in handlers.
* For macro (`AppState<()>`): Manage custom mutable state using `Arc<Mutex<...>>` within an `Extension` or other shared state patterns.
* For manual (`AppState<T>`): Custom state `T` is part of `AppState` (`.user_state`).

**Reference:** See `MODULE_CREATION_GUIDE.md` for full details and examples.