{"id":31218563,"url":"https://github.com/fastn-stack/context","last_synced_at":"2025-09-24T02:33:56.265Z","repository":{"id":315252268,"uuid":"1058735234","full_name":"fastn-stack/context","owner":"fastn-stack","description":"Type-safe async context propagation for Rust applications","archived":false,"fork":false,"pushed_at":"2025-09-17T15:04:08.000Z","size":33,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-17T15:33:30.067Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fastn-stack.png","metadata":{"files":{"readme":"README-FULL.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-17T13:33:54.000Z","updated_at":"2025-09-17T15:04:11.000Z","dependencies_parsed_at":"2025-09-17T15:45:05.979Z","dependency_job_id":null,"html_url":"https://github.com/fastn-stack/context","commit_stats":null,"previous_names":["fastn-stack/context"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/fastn-stack/context","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastn-stack%2Fcontext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastn-stack%2Fcontext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastn-stack%2Fcontext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastn-stack%2Fcontext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastn-stack","download_url":"https://codeload.github.com/fastn-stack/context/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastn-stack%2Fcontext/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275999455,"owners_count":25567495,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-19T02:00:09.700Z","response_time":108,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-21T15:58:40.291Z","updated_at":"2025-09-21T15:58:46.351Z","avatar_url":"https://github.com/fastn-stack.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fastn-context: Hierarchical Application Context for Debugging and Operations\n\nThis crate provides a hierarchical context system for fastn applications, enabling tree-based cancellation, metrics collection, and operational visibility. It forms the operational backbone for all fastn services.\n\n\u003e **Note**: This README documents the complete design iteratively. Some sections may overlap as features build on each other. The design is internally consistent - later sections refine and extend earlier concepts.\n\n## Design Philosophy\n\n- **Hierarchical Structure**: Applications naturally form trees of operations\n- **Automatic Inheritance**: Child contexts inherit cancellation and settings from parents\n- **Zero Boilerplate**: Context trees build themselves as applications run\n- **Production Ready**: Status trees enable debugging of stuck/slow operations\n- **Bounded Complexity**: Simple spawn vs detailed child creation as needed\n\n## Core Concepts\n\n### Context Tree Structure\n\nEvery fastn application forms a natural hierarchy:\n\n```\nGlobal Context (application level)\n├── Service Context (e.g., \"remote-access-listener\")\n│   ├── Session Context (e.g., \"alice@bv478gen\")\n│   │   ├── Task Context (e.g., \"stdout-handler\") \n│   │   └── Task Context (e.g., \"stderr-stream\")\n│   └── Session Context (e.g., \"bob@p2nd7avq\")\n├── Service Context (e.g., \"http-proxy\")\n└── Service Context (e.g., \"chat-service\")\n```\n\n### Automatic Context Creation\n\nfastn-context integrates seamlessly with fastn ecosystem:\n\n```rust\n// 1. Global context created by main macro\n#[fastn_context::main]\nasync fn main() -\u003e eyre::Result\u003c()\u003e {\n    // Global context automatically available\n}\n\n// 2. Service contexts created by operations  \nlet listener = fastn_p2p::server::listen(key, protocols).await?;\n// Creates child context: \"p2p-listener\" under global\n\n// 3. Session contexts created per connection\n// Each incoming connection gets child context: \"session-{peer_id}\"\n\n// 4. Task contexts created by spawn operations\nsession_ctx.child(\"shell-handler\").spawn(handle_shell);\n```\n\n## API Reference\n\n### Core Context\n\n```rust\npub struct Context {\n    /// Context name for debugging/status\n    pub name: String,\n    \n    /// When this context was created\n    pub created_at: std::time::Instant,\n    \n    // Private: parent, children, cancellation, metrics, data\n}\n\nimpl Context {\n    /// Create new root context (typically only used by main macro)\n    pub fn new(name: \u0026str) -\u003e std::sync::Arc\u003cContext\u003e;\n    \n    /// Create child context with given name\n    pub fn child(\u0026self, name: \u0026str) -\u003e ContextBuilder;\n    \n    /// Simple spawn (inherits current context, no child creation)\n    pub fn spawn\u003cF\u003e(\u0026self, task: F) -\u003e tokio::task::JoinHandle\u003cF::Output\u003e\n    where F: std::future::Future + Send + 'static;\n    \n    /// Wait for cancellation signal\n    pub async fn wait(\u0026self);\n    \n    /// Cancel this context and all children recursively\n    pub fn cancel(\u0026self);\n    \n    /// Add metric data for status reporting\n    pub fn add_metric(\u0026self, key: \u0026str, value: MetricValue);\n    \n    /// Store arbitrary data on this context\n    pub fn set_data(\u0026self, key: \u0026str, value: serde_json::Value);\n    \n    /// Get stored data\n    pub fn get_data(\u0026self, key: \u0026str) -\u003e Option\u003cserde_json::Value\u003e;\n    \n    /// Increment total counter (historical count)\n    pub fn increment_total(\u0026self, counter: \u0026str);\n    \n    /// Increment live counter (current active count)\n    pub fn increment_live(\u0026self, counter: \u0026str);\n    \n    /// Decrement live counter (when operation completes)\n    pub fn decrement_live(\u0026self, counter: \u0026str);\n    \n    /// Get counter values\n    pub fn get_total(\u0026self, counter: \u0026str) -\u003e u64;\n    pub fn get_live(\u0026self, counter: \u0026str) -\u003e u64;\n}\n```\n\n### Context Builder\n\n```rust\npub struct ContextBuilder {\n    // Pre-created child context ready for configuration\n}\n\nimpl ContextBuilder {\n    /// Add initial data to context\n    pub fn with_data(self, key: \u0026str, value: serde_json::Value) -\u003e Self;\n    \n    /// Add initial metric to context\n    pub fn with_metric(self, key: \u0026str, value: MetricValue) -\u003e Self;\n    \n    /// Spawn task with this configured child context\n    pub fn spawn\u003cF\u003e(self, task: F) -\u003e tokio::task::JoinHandle\u003cF::Output\u003e\n    where F: FnOnce(std::sync::Arc\u003cContext\u003e) -\u003e Fut + Send + 'static;\n}\n```\n\n### Global Access\n\n```rust\n/// Get the global application context\npub fn global() -\u003e std::sync::Arc\u003cContext\u003e;\n\n/// Get current task's context (thread-local or task-local)\npub fn current() -\u003e std::sync::Arc\u003cContext\u003e;\n\n/// Print status tree for debugging\npub fn status() -\u003e StatusTree;\n```\n\n### Metric Types\n\n```rust\n#[derive(Debug, Clone)]\npub enum MetricValue {\n    Counter(u64),\n    Gauge(f64), \n    Duration(std::time::Duration),\n    Text(String),\n    Bytes(u64),\n}\n```\n\n## Usage Patterns\n\n### Simple Task Spawning\n\n```rust\n// Inherit current context (no child creation)\nlet ctx = fastn_context::current();\nctx.spawn(async {\n    // Simple background task\n});\n```\n\n### Detailed Task Spawning  \n\n```rust\n// Create child context with debugging info\nctx.child(\"remote-shell-handler\")\n    .with_data(\"peer\", alice_id52)\n    .with_data(\"shell\", \"bash\")\n    .with_metric(\"commands_executed\", 0)\n    .spawn(|task_ctx| async move {\n        // Task can update its own context\n        task_ctx.add_metric(\"commands_executed\", cmd_count);\n        task_ctx.set_data(\"last_command\", \"ls -la\");\n        \n        // Task waits for its own cancellation\n        tokio::select! {\n            _ = task_ctx.wait() =\u003e {\n                println!(\"Shell handler cancelled\");\n            }\n            _ = handle_shell_session() =\u003e {\n                println!(\"Shell session completed\");\n            }\n        }\n    });\n```\n\n### Status Tree Output\n\n```\n$ fastn status\nGlobal Context (2h 15m 32s uptime)\n├── Remote Access Listener (1h 45m active)\n│   ├── alice@bv478gen (23m 12s, bash shell)\n│   │   ├── stdout-handler (23m 12s, 15.2MB processed)\n│   │   └── stderr-stream (18m 45s, 2.1KB processed)\n│   └── bob@p2nd7avq (8m 33s, ls command)\n│       └── command-executor (8m 33s, exit pending)\n├── HTTP Proxy (2h 15m active)\n│   ├── connection-pool (45 active, 1,234 requests)\n│   └── request-handler-pool (12 workers active)\n└── Chat Service (35m active)\n    ├── presence-monitor (35m, 15 users tracked)\n    └── message-relay (35m, 4,567 messages)\n```\n\n## Integration with fastn-p2p\n\nfastn-p2p depends on fastn-context and automatically creates context hierarchies:\n\n```rust\n// fastn-p2p sessions provide access to their context\nasync fn handle_remote_shell(session: fastn_p2p::server::Session\u003cRemoteShellProtocol\u003e) {\n    let ctx = session.context(); // Auto-created by fastn-p2p\n    \n    // Simple spawn (inherits session context)\n    ctx.spawn(pipe_stdout(session.send));\n    \n    // Detailed spawn (creates child for debugging)\n    ctx.child(\"command-executor\")\n        .with_data(\"command\", session.protocol.command)\n        .spawn(|task_ctx| async move {\n            let result = execute_command(\u0026session.protocol.command).await;\n            task_ctx.set_data(\"exit_code\", result.code);\n        });\n}\n```\n\n## Main Function Integration\n\nThe main macro moves to fastn-context and sets up the global context:\n\n```rust\n#[fastn_context::main]\nasync fn main() -\u003e eyre::Result\u003c()\u003e {\n    // Global context automatically created and available\n    \n    let ctx = fastn_context::global();\n    ctx.child(\"startup\")\n        .with_data(\"version\", env!(\"CARGO_PKG_VERSION\"))\n        .spawn(|_| async {\n            // Application initialization\n        });\n}\n```\n\n## Design Benefits\n\n1. **Names Required for Debugging** - Every important operation has a name in status tree\n2. **Selective Complexity** - Simple spawn vs detailed child creation as needed  \n3. **Automatic Tree Building** - Context hierarchy builds as application runs\n4. **Production Debugging** - `fastn status` shows exactly where system is stuck\n5. **Clean Separation** - Context concerns separate from networking concerns\n6. **Ecosystem Wide** - All fastn crates can use the same context infrastructure\n\n**Key Insight**: Names aren't optional - they're essential for production debugging and operational visibility.\n\n## Comprehensive Timing and Lock Monitoring\n\nEvery context and operation tracks detailed timing for real-time debugging, including named lock monitoring for deadlock detection.\n\n### Timing Integration\n\n```rust\npub struct Context {\n    pub name: String,\n    pub created_at: std::time::Instant,      // When context started\n    pub last_activity: std::sync::Arc\u003cstd::sync::Mutex\u003cstd::time::Instant\u003e\u003e, // Last activity\n    // ... other fields\n}\n\nimpl Context {\n    /// Update last activity timestamp (called automatically by operations)\n    pub fn touch(\u0026self);\n    \n    /// Get how long this context has been alive\n    pub fn duration(\u0026self) -\u003e std::time::Duration;\n    \n    /// Get how long since last activity\n    pub fn idle_duration(\u0026self) -\u003e std::time::Duration;\n    \n    /// Create named mutex within this context\n    pub fn mutex\u003cT\u003e(\u0026self, name: \u0026str, data: T) -\u003e ContextMutex\u003cT\u003e;\n    \n    /// Create named RwLock within this context  \n    pub fn rwlock\u003cT\u003e(\u0026self, name: \u0026str, data: T) -\u003e ContextRwLock\u003cT\u003e;\n    \n    /// Create named semaphore within this context\n    pub fn semaphore(\u0026self, name: \u0026str, permits: usize) -\u003e ContextSemaphore;\n}\n```\n\n### Named Lock Types\n\n```rust\npub struct ContextMutex\u003cT\u003e {\n    name: String,\n    context: std::sync::Arc\u003cContext\u003e,\n    inner: tokio::sync::Mutex\u003cT\u003e,\n}\n\nimpl\u003cT\u003e ContextMutex\u003cT\u003e {\n    /// Lock with automatic status tracking\n    pub async fn lock(\u0026self) -\u003e ContextMutexGuard\u003cT\u003e;\n}\n\npub struct ContextMutexGuard\u003cT\u003e {\n    acquired_at: std::time::Instant,    // When lock was acquired\n    context_name: String,               // Which context holds it\n    lock_name: String,                  // Lock identifier\n    // Auto-reports to context status system\n    // Auto-cleanup on drop\n}\n```\n\n### Detailed Status Output with Comprehensive Timing\n\n```\n$ fastn status\nGlobal Context (2h 15m 32s uptime, active 0.1s ago)\n├── Remote Access Listener (1h 45m active, last activity 2.3s ago)\n│   ├── alice@bv478gen (23m 12s connected, active 0.5s ago)\n│   │   ├── stdout-handler (23m 12s running, CPU active)\n│   │   │   └── 🔒 HOLDS \"session-output-lock\" (12.3s held)\n│   │   └── stderr-stream (18m 45s running, idle 8.1s)\n│   │       └── ⏳ WAITING \"session-output-lock\" (8.1s waiting) ⚠️ STUCK\n│   └── bob@p2nd7avq (8m 33s connected, active 0.1s ago)\n│       └── command-executor (8m 33s running, exit pending)\n├── HTTP Proxy (2h 15m active, last request 0.8s ago)\n│   ├── connection-pool (2h 15m running, 45 connections, oldest 34m 12s)\n│   └── 🔒 HOLDS \"pool-resize-lock\" (0.2s held)\n└── Chat Service (35m active, last message 1.2s ago)\n    ├── presence-monitor (35m running, heartbeat 30s ago)\n    └── message-relay (35m running, processing queue)\n\n🔒 Active Locks (3):\n  - \"session-output-lock\" held by alice/stdout-handler (12.3s) ⚠️ LONG HELD\n  - \"user-table-write-lock\" held by user-service/db-writer (0.1s)  \n  - \"pool-resize-lock\" held by http-proxy/connection-pool (0.2s)\n\n⏳ Lock Waiters (1):\n  - alice/stderr-stream waiting for \"session-output-lock\" (8.1s) ⚠️ STUCK\n\n⚠️  Potential Issues:\n  - Long-held lock \"session-output-lock\" (12.3s) may indicate deadlock\n  - stderr-stream stuck waiting (8.1s) suggests blocked I/O\n```\n\n### Automatic Activity Tracking\n\n```rust\n// All operations automatically maintain timing\nctx.spawn(async {\n    // ctx.touch() called when task starts\n    loop {\n        do_work().await;\n        ctx.touch(); // Update activity timestamp\n    }\n});\n\n// Lock operations update timing automatically\nlet guard = ctx.mutex(\"data-lock\", data).lock().await;\n// Updates: context last_activity, tracks lock hold time\n\n// Long operations should periodically touch\nasync fn long_running_task(ctx: std::sync::Arc\u003cContext\u003e) {\n    loop {\n        process_batch().await;\n        ctx.touch(); // Show we're still active, not stuck\n        \n        tokio::select! {\n            _ = ctx.wait() =\u003e break, // Cancelled\n            _ = tokio::time::sleep(std::time::Duration::from_secs(10)) =\u003e {}\n        }\n    }\n}\n```\n\nThis provides **real-time operational debugging** - administrators can instantly identify stuck operations, deadlocked tasks, and performance bottlenecks with precise timing information.\n\n## Counter Management System\n\nEvery context can track both historical totals and live counts for detailed operational metrics.\n\n### Global Counter Storage with Dotted Paths\n\n```rust\npub struct Context {\n    pub name: String,\n    pub full_path: String,  // \"global.remote-access.alice@bv478gen.stdout-handler\"\n    // ... other fields\n}\n\nimpl Context {\n    /// Get full dotted path for this context\n    pub fn path(\u0026self) -\u003e \u0026str;\n    \n    /// Increment total counter (stored in global hashmap by full path)\n    pub fn increment_total(\u0026self, counter: \u0026str);\n    \n    /// Increment live counter (stored in global hashmap by full path)\n    pub fn increment_live(\u0026self, counter: \u0026str);\n    \n    /// Decrement live counter (stored in global hashmap by full path)\n    pub fn decrement_live(\u0026self, counter: \u0026str);\n    \n    /// Get counter values (retrieved from global storage)\n    pub fn get_total(\u0026self, counter: \u0026str) -\u003e u64;\n    pub fn get_live(\u0026self, counter: \u0026str) -\u003e u64;\n}\n\n// Global counter storage (persists beyond context lifetimes)\nstatic GLOBAL_COUNTERS: LazyLock\u003cRwLock\u003cHashMap\u003cString, u64\u003e\u003e\u003e = ...;\n\n// Counter keys format: \"{context_path}.{counter_name}\"\n// Examples:\n// \"global.connections\" -\u003e 1,247\n// \"global.remote-access.connections\" -\u003e 234  \n// \"global.remote-access.alice@bv478gen.commands\" -\u003e 45\n// \"global.http-proxy.requests\" -\u003e 1,013\n```\n\n### Automatic Counter Integration\n\n```rust\n// fastn-p2p automatically maintains connection counters\nasync fn handle_incoming_connection(session: fastn_p2p::server::Session\u003cProtocol\u003e) {\n    let ctx = session.context();\n    \n    // Automatically tracked by fastn-p2p:\n    ctx.increment_total(\"connections\");     // Total connections ever\n    ctx.increment_live(\"connections\");      // Current active connections\n    \n    // Your handler code...\n    \n    // When session ends:\n    ctx.decrement_live(\"connections\");      // Automatically called\n}\n\n// Custom counters for application logic\nasync fn handle_remote_command(session: server::Session\u003cRemoteShellProtocol\u003e) {\n    let ctx = session.context();\n    \n    ctx.increment_total(\"commands\");        // Total commands executed\n    ctx.increment_live(\"commands\");         // Currently executing commands\n    \n    let result = execute_command(\u0026session.protocol.command).await;\n    \n    ctx.decrement_live(\"commands\");         // Command completed\n    \n    if result.success {\n        ctx.increment_total(\"successful_commands\");\n    } else {\n        ctx.increment_total(\"failed_commands\");\n    }\n}\n```\n\n### Enhanced Status Display with Counters\n\n```\n$ fastn status\nfastn Status Dashboard\nSystem: CPU 12.3% | RAM 2.1GB/16GB (13%) | Disk 45GB/500GB (9%) | Load 0.8,1.2,1.5\nNetwork: ↓ 125KB/s ↑ 67KB/s | Uptime 5d 12h 45m\n\nGlobal Context (2h 15m 32s uptime, active 0.1s ago)\n├── Total: 1,247 connections, 15,432 requests | Live: 47 connections, 12 active requests\n├── Remote Access Listener (1h 45m active, last activity 2.3s ago)\n│   ├── Total: 234 connections, 2,156 commands | Live: 2 connections, 3 commands\n│   ├── alice@bv478gen (23m 12s connected, active 0.5s ago)\n│   │   ├── Total: 45 commands (42 success, 3 failed) | Live: 1 command\n│   │   ├── stdout-handler (23m 12s running, CPU active)\n│   │   │   └── 🔒 HOLDS \"session-output-lock\" (12.3s held)\n│   │   └── stderr-stream (18m 45s running, idle 8.1s)\n│   │       └── ⏳ WAITING \"session-output-lock\" (8.1s waiting) ⚠️ STUCK\n│   └── bob@p2nd7avq (8m 33s connected, active 0.1s ago)\n│       ├── Total: 12 commands (12 success) | Live: 1 command\n│       └── command-executor (8m 33s running, exit pending)\n├── HTTP Proxy (2h 15m active, last request 0.8s ago)\n│   ├── Total: 1,013 requests (987 success, 26 failed) | Live: 45 connections, 8 requests\n│   ├── connection-pool (2h 15m running, 45 connections, oldest 34m 12s)\n│   └── 🔒 HOLDS \"pool-resize-lock\" (0.2s held)\n└── Chat Service (35m active, last message 1.2s ago)\n    ├── Total: 4,567 messages, 89 users joined | Live: 15 users, 3 conversations\n    ├── presence-monitor (35m running, heartbeat 30s ago)\n    └── message-relay (35m running, processing queue)\n\n🔒 Active Locks (3): ...\n⏳ Lock Waiters (1): ...\n```\n\n### Counter Storage and Paths\n\n```rust\n// Counter keys are automatically generated from context paths:\n\n// Global level counters\n// \"global.connections\" -\u003e 1,247 total\n// \"global.live_connections\" -\u003e 47 current\n\n// Service level counters  \n// \"global.remote-access.connections\" -\u003e 234 total\n// \"global.remote-access.live_connections\" -\u003e 2 current\n\n// Session level counters\n// \"global.remote-access.alice@bv478gen.commands\" -\u003e 45 total\n// \"global.remote-access.alice@bv478gen.live_commands\" -\u003e 1 current\n\n// Task level counters\n// \"global.remote-access.alice@bv478gen.stdout-handler.bytes_processed\" -\u003e 1,234,567\n\n// Examples in code:\nasync fn handle_connection(session: server::Session\u003cProtocol\u003e) {\n    let ctx = session.context(); // Path: \"global.remote-access.alice@bv478gen\"\n    \n    // These create global entries:\n    ctx.increment_total(\"commands\");        // Key: \"global.remote-access.alice@bv478gen.commands\"\n    ctx.increment_live(\"commands\");         // Key: \"global.remote-access.alice@bv478gen.live_commands\"\n    \n    // Nested task context\n    ctx.child(\"stdout-handler\").spawn(|task_ctx| async move {\n        // task_ctx.path() -\u003e \"global.remote-access.alice@bv478gen.stdout-handler\"\n        task_ctx.increment_total(\"bytes_processed\");\n    });\n}\n```\n\n### Persistent Counter Benefits\n\n- **✅ Survives context drops** - Counters stored globally, persist after contexts end\n- **✅ Hierarchical aggregation** - Can sum all child counters for parent totals\n- **✅ Path-based queries** - Easy to find counters by context path\n- **✅ Historical tracking** - Total counters accumulate across all context instances\n- **✅ Live tracking** - Live counters automatically decremented when contexts drop\n\n**Live counters** show current activity (auto-decremented on context drop).  \n**Total counters** show historical activity (persist forever for trending).  \n**Global storage** ensures metrics survive context lifecycles.\n\n## Status Monitoring and HTTP Dashboard\n\nfastn-context automatically provides multiple ways to access real-time status information for debugging and monitoring.\n\n### P2P Status Access\n\n```rust\n#[fastn_context::main]\nasync fn main() -\u003e eyre::Result\u003c()\u003e {\n    // Status automatically available over P2P for remote access\n    // No HTTP server needed - uses secure P2P connections\n    \n    // Your application code...\n}\n```\n\nStatus is accessible over the P2P network using the remote access system.\n\n### Status API Functions\n\n```rust\n/// Get current status snapshot with ANSI formatting\npub fn status() -\u003e Status;\n\n/// Stream of status updates (max once per second)\npub fn status_stream() -\u003e impl futures_core::stream::Stream\u003cItem = Status\u003e;\n\n/// Get raw status data as structured JSON\npub fn status_json() -\u003e serde_json::Value;\n```\n\n### Status Type with ANSI Display\n\n```rust\n#[derive(Debug, Clone, serde::Serialize)]\npub struct Status {\n    pub global_context: ContextStatus,\n    pub active_locks: Vec\u003cLockStatus\u003e,\n    pub lock_waiters: Vec\u003cLockWaiter\u003e,\n    pub warnings: Vec\u003cStatusWarning\u003e,\n    pub timestamp: std::time::SystemTime,\n}\n\n#[derive(Debug, Clone, serde::Serialize)]\npub struct ContextStatus {\n    pub name: String,\n    pub duration: std::time::Duration,\n    pub last_activity: std::time::Duration, // Time since last activity\n    pub children: Vec\u003cContextStatus\u003e,\n    pub metrics: std::collections::HashMap\u003cString, MetricValue\u003e,\n    pub data: std::collections::HashMap\u003cString, serde_json::Value\u003e,\n    pub total_counters: std::collections::HashMap\u003cString, u64\u003e,  // Historical counts\n    pub live_counters: std::collections::HashMap\u003cString, u64\u003e,   // Current active counts\n}\n\n#[derive(Debug, Clone, serde::Serialize)]\npub struct LockStatus {\n    pub name: String,\n    pub held_by_context: String,\n    pub held_duration: std::time::Duration,\n    pub lock_type: LockType, // Mutex, RwLock, Semaphore\n}\n\n#[derive(Debug, Clone, serde::Serialize)]\npub struct StatusWarning {\n    pub message: String,\n    pub context_path: String,\n    pub severity: WarningSeverity,\n}\n\n#[derive(Debug, Clone, serde::Serialize)]\npub enum WarningSeverity {\n    Info,    // FYI information\n    Warning, // Potential issue  \n    Critical, // Likely problem\n}\n```\n\n### ANSI-Formatted Display\n\n```rust\nimpl std::fmt::Display for Status {\n    fn fmt(\u0026self, f: \u0026mut std::fmt::Formatter\u003c'_\u003e) -\u003e std::fmt::Result {\n        use colored::*; // For ANSI colors\n        \n        // Header with timestamp\n        writeln!(f, \"{}\", \"fastn Status Dashboard\".bold().blue())?;\n        writeln!(f, \"{}\", format!(\"Snapshot: {}\", \n            humantime::format_rfc3339(self.timestamp)).dimmed())?;\n        writeln!(f)?;\n        \n        // Context tree with colors and timing\n        self.display_context_tree(f, \u0026self.global_context, 0)?;\n        \n        // Active locks section\n        if !self.active_locks.is_empty() {\n            writeln!(f, \"\\n{} Active Locks ({}):\", \"🔒\".yellow(), self.active_locks.len())?;\n            for lock in \u0026self.active_locks {\n                let duration_str = humantime::format_duration(lock.held_duration);\n                let color = if lock.held_duration.as_secs() \u003e 10 { \n                    \"red\" \n                } else { \n                    \"white\" \n                };\n                writeln!(f, \"  - \\\"{}\\\" held by {} ({})\", \n                    lock.name.cyan(),\n                    lock.held_by_context.white(),\n                    duration_str.color(color))?;\n            }\n        }\n        \n        // Lock waiters section\n        if !self.lock_waiters.is_empty() {\n            writeln!(f, \"\\n{} Lock Waiters ({}):\", \"⏳\".yellow(), self.lock_waiters.len())?;\n            for waiter in \u0026self.lock_waiters {\n                let duration_str = humantime::format_duration(waiter.waiting_duration);\n                writeln!(f, \"  - {} waiting for \\\"{}\\\" ({})\", \n                    waiter.context_name.white(),\n                    waiter.lock_name.cyan(),\n                    duration_str.red())?;\n            }\n        }\n        \n        // Warnings section\n        if !self.warnings.is_empty() {\n            writeln!(f, \"\\n{} Warnings:\", \"⚠️\".red())?;\n            for warning in \u0026self.warnings {\n                let icon = match warning.severity {\n                    WarningSeverity::Info =\u003e \"ℹ️\",\n                    WarningSeverity::Warning =\u003e \"⚠️\", \n                    WarningSeverity::Critical =\u003e \"🚨\",\n                };\n                writeln!(f, \"  {} {}\", icon, warning.message.yellow())?;\n            }\n        }\n        \n        Ok(())\n    }\n}\n```\n\n### Status Stream (Event-Driven Updates)\n\n```rust\n/// Stream provides updates only when context tree actually changes\n/// No polling - efficient for long-running monitoring\nlet mut status_stream = fastn_context::status_stream();\nwhile let Some(status) = status_stream.next().await {\n    // Only prints when something actually changes\n    print!(\"\\x1B[2J\\x1B[H\"); // Clear screen\n    println!(\"{}\", status);   // Display with colors\n}\n```\n\n### CLI Integration with P2P Status Access\n\nfastn-context integrates with the main fastn CLI to provide both local and remote status access:\n\n```bash\n# Local machine status\nfastn status                 # One-time snapshot with ANSI colors\nfastn status -w              # Watch mode (event-driven, no polling)\nfastn status --json          # JSON output for programmatic use\n\n# Remote machine status over P2P (requires remote access)\nfastn status alice           # Status from machine with alias \"alice\"  \nfastn status bv478gen...     # Status from machine with ID52\nfastn status alice -w        # Watch remote machine's status in real-time\nfastn status alice --json    # Remote machine status as JSON\n\n# Multiple machines\nfastn status alice,bob,prod  # Status from multiple machines\n```\n\n**P2P Status Protocol:**\n- Uses secure fastn remote access (same as `fastn rshell`)\n- Requires target machine in your `remote-access/config.toml` \n- Status data transmitted over encrypted P2P connection\n- Real-time streaming for remote watch mode\n\n### Status Protocol Integration\n\nStatus access integrates seamlessly with fastn's remote access system:\n\n```rust\n// Status is available as a built-in remote command\n// When fastn-daemon receives status requests, fastn-context provides the data\n\n// Server side - automatic status command handling\n// fastn-daemon automatically handles:\n// - StatusRequest -\u003e returns current Status\n// - StatusStreamRequest -\u003e returns real-time Status stream\n\n// Client side - transparent remote access\nfastn status alice    // Translates to fastn_p2p::client::call(alice, StatusRequest)\nfastn status alice -w // Translates to fastn_p2p::client::connect(alice, StatusStreamProtocol)\n```\n\nThis gives **comprehensive status access** - terminal, HTTP, streaming, and programmatic - all from the same underlying Status structure with rich ANSI formatting for human consumption.\n\n## System Metrics Monitoring\n\nfastn-context automatically monitors system resources and integrates them into the status display.\n\n### Automatic System Monitoring\n\n```rust\n#[derive(Debug, Clone, serde::Serialize)]\npub struct SystemMetrics {\n    pub cpu_usage_percent: f32,         // Current CPU usage\n    pub memory_used_bytes: u64,         // RAM usage\n    pub memory_total_bytes: u64,        // Total RAM\n    pub disk_used_bytes: u64,           // Disk usage\n    pub disk_total_bytes: u64,          // Total disk\n    pub network_rx_bytes_per_sec: u64,  // Network receive rate\n    pub network_tx_bytes_per_sec: u64,  // Network transmit rate\n    pub load_average: [f32; 3],         // 1min, 5min, 15min load\n    pub uptime: std::time::Duration,    // System uptime\n}\n\n// Added to Status structure\npub struct Status {\n    pub system_metrics: SystemMetrics,  // System resource usage\n    pub global_context: ContextStatus,\n    pub active_locks: Vec\u003cLockStatus\u003e,\n    pub lock_waiters: Vec\u003cLockWaiter\u003e,\n    pub warnings: Vec\u003cStatusWarning\u003e,\n    pub timestamp: std::time::SystemTime,\n}\n```\n\n### Efficient Metric Collection\n\n```rust\n// System metrics cached and updated appropriately:\n// - CPU usage: Updated every 1 second (smooth average)\n// - Memory/disk: Updated every 5 seconds (less volatile)  \n// - Network rates: Updated every 1 second (calculated from deltas)\n// - Load average: Updated every 10 seconds (system provides this)\n\n// Metrics only recalculated when status is actually requested\n// No background polling unless someone is watching\n```\n\n### Enhanced Status Display with System Info\n\n```\n$ fastn status\nfastn Status Dashboard\nSystem: CPU 12.3% | RAM 2.1GB/16GB (13%) | Disk 45GB/500GB (9%) | Load 0.8,1.2,1.5\nNetwork: ↓ 125KB/s ↑ 67KB/s | Uptime 5d 12h 45m\n\nGlobal Context (2h 15m 32s uptime, active 0.1s ago)\n├── Remote Access Listener (1h 45m active, last activity 2.3s ago)\n│   ├── alice@bv478gen (23m 12s connected, active 0.5s ago)\n│   │   ├── stdout-handler (23m 12s running, CPU active)\n│   │   │   └── 🔒 HOLDS \"session-output-lock\" (12.3s held)\n│   │   └── stderr-stream (18m 45s running, idle 8.1s)\n│   │       └── ⏳ WAITING \"session-output-lock\" (8.1s waiting) ⚠️ STUCK\n│   └── bob@p2nd7avq (8m 33s connected, active 0.1s ago)\n│       └── command-executor (8m 33s running, exit pending)\n├── HTTP Proxy (2h 15m active, last request 0.8s ago)\n│   ├── connection-pool (2h 15m running, 45 connections, oldest 34m 12s)\n│   └── 🔒 HOLDS \"pool-resize-lock\" (0.2s held)\n└── Chat Service (35m active, last message 1.2s ago)\n    ├── presence-monitor (35m running, heartbeat 30s ago)\n    └── message-relay (35m running, processing queue)\n\n🔒 Active Locks (3):\n  - \"session-output-lock\" held by alice/stdout-handler (12.3s) ⚠️ LONG HELD\n  - \"user-table-write-lock\" held by user-service/db-writer (0.1s)  \n  - \"pool-resize-lock\" held by http-proxy/connection-pool (0.2s)\n\n⏳ Lock Waiters (1):\n  - alice/stderr-stream waiting for \"session-output-lock\" (8.1s) ⚠️ STUCK\n\n⚠️  Alerts:\n  - Long-held lock \"session-output-lock\" (12.3s) may indicate deadlock\n  - stderr-stream stuck waiting (8.1s) suggests blocked I/O\n  - CPU usage normal (12.3%), memory usage low (13%)\n```\n\n### Watch Mode (`fastn status -w`)\n\n```rust\n// Event-driven updates - only when something changes\n// No CPU overhead when system is idle\n// Immediately shows when new contexts/locks appear or disappear\n\n$ fastn status -w\n# Screen updates only when:\n# - New context created/destroyed\n# - Lock acquired/released  \n# - Significant activity changes\n# - System metrics cross thresholds\n# - No updates for days if system is stable\n```\n\nThis provides **complete operational visibility** with both application-specific context trees and system resource monitoring, all with efficient event-driven updates instead of wasteful polling.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastn-stack%2Fcontext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastn-stack%2Fcontext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastn-stack%2Fcontext/lists"}