# Framework Embedding URL: /pounce/docs/deployment/embedding/ Section: deployment Tags: deployment, frameworks, serverconfig, lifecycle, proxy -------------------------------------------------------------------------------- Frameworks can serve their ASGI app through pounce.run() or construct pounce.server.Server directly. Direct construction is useful when a framework has a fused sync callable, a lifecycle collector, or its own CLI—but it creates an adapter contract that must stay aligned with Pounce. The goal is not to copy every ServerConfig field into a framework's public configuration. The goal is to make every production-critical difference an intentional, documented policy instead of an accidental Pounce default. Prefer A Frozen Config Pass-Through The smallest drift-resistant integration accepts a pre-built ServerConfig: from pounce import ServerConfig from pounce.server import Server def serve_framework_app( app, *, server_config: ServerConfig, app_path: str | None = None, sync_app=None, lifecycle_collector=None, ) -> None: Server( server_config, app, app_path=app_path, sync_app=sync_app, lifecycle_collector=lifecycle_collector, ).run() ServerConfig is frozen shared state. Build it once before workers start; do not mutate a framework config object and expect running workers to follow. If a framework maps its own config fields into ServerConfig, keep that mapping in one function and test both the framework's programmatic launcher and CLI launcher against it. Minimum Decision Surface “Decision” means forward a user value, accept a complete ServerConfig, or document a deliberate framework-owned fixed policy. Area Pounce surface Why an embedding framework must decide Bind and workers host, port, uds, workers, worker_mode Determines listener ownership and whether workers are threads, processes, async workers, or subinterpreters. Application identity Server(..., app_path=...) Required for subinterpreter import and for reload paths that reimport application code. A live callable alone is not importable in another interpreter. Worker hooks worker_startup_failure Generic ASGI compatibility defaults to ignore; frameworks with required worker hooks normally need shutdown so readiness cannot succeed after hook failure. Lifecycle bounds startup_timeout, shutdown_timeout, reload_timeout Bounds deploy readiness, graceful shutdown, and generation rotation. Platform drain windows must be longer than Pounce shutdown bounds. Connection timeouts header_timeout, keep_alive_timeout, request_timeout, write_timeout Preserve the state-specific header, request-body, between-request idle, and blocked-output controls independently. HTTP/3 output liveness uses http3_idle_timeout. Request envelope max_request_size, max_header_size, max_headers Pounce validates bytes before the framework sees them. A larger framework body limit is ineffective if Pounce retains its smaller default. Capacity backlog, max_connections, executor_threads_per_worker Bounds queued connections, live connections, and blocking work offloaded from async handlers. Proxy authority trusted_hosts, forwarded_for_trusted_hops, root_path Controls trusted client IP, scheme, host authority, and subpath routing before framework middleware runs. TLS and protocols ssl_certfile, ssl_keyfile, http3_enabled and protocol extras Defines whether Pounce or an edge owns TLS and which optional protocol handlers can be selected. Operator surfaces health/readiness, metrics, introspection, logging, lifecycle collector A framework may own these endpoints, but collisions, redaction, and disabled Pounce paths must be deliberate. Feature-specific fields—static files, middleware, compression dictionaries, Sentry, OpenTelemetry, rate limiting, and request queueing—only need adapter surface when the framework advertises that Pounce-owned feature. Constructor Inputs Are Part Of The Contract ServerConfig is not the entire embedding API: app_path is the import identity for subinterpreters and code reimport. sync_app enables the fused sync path for frameworks that implement Pounce's sync callable contract. Omitting it is valid, but gives up that path. lifecycle_collector connects framework/operator lifecycle evidence without changing the ASGI app. If a framework cannot supply app_path, it should reject worker_mode="subinterpreter" with an actionable error rather than silently falling back or starting an unusable worker. Pounce enforces this boundary with POUNCE_SUPERVISOR_SUBINTERPRETER_NO_APP_PATH; explicit subinterpreter mode is supervised even when workers=1. Process-Worker Initialization Is A Fork Boundary On a GIL build with multiple workers, Pounce uses fork. The live app and the state produced by main lifespan.startup are inherited by every worker. An embedding framework must therefore finish the pre-fork phase without live background threads, running executors, held synchronization primitives, or process-local clients that are unsafe to inherit. Readiness cannot prove that an inherited lock or executor will make progress when a later request uses it. Use pounce.worker.startup to create or replace process-local resources in each child, and set worker_startup_failure="shutdown" when that initialization is required. If the framework cannot provide a fork-safe boundary, it should select workers=1 or require Python 3.14t thread workers. Pounce does not currently provide a spawn or forkserver process-worker option; adding one would require an explicit app-import, lifespan, serialization, and reload contract rather than a silent fallback. Framework-Owned Endpoints A framework may own /health, /ready, metrics, or introspection. In that case, set the overlapping Pounce endpoint to disabled and test the framework's equivalent behavior: readiness turns non-200 when drain begins and before process termination; health and readiness paths do not collide with user routes silently; metrics names and paths are stable if publicly documented; runtime/config inspection remains redacted and off by default when exposed. “The framework owns it” is a valid policy. Leaving the Pounce field at its default without documenting the replacement is not. Adapter Proof Checklist At minimum, run these through the real framework launcher and a real Pounce socket: A request below and above the configured body limit. Trusted and untrusted forwarded authority, including the configured hop count. Required worker startup success and failure before readiness. On GIL process workers, fork-safe pre-start state and per-worker resource initialization. SIGTERM drain bounded by the configured shutdown timeout. Every supported worker mode; reject unsupported modes before binding. Programmatic and CLI launchers produce the same ServerConfig policy. Snapshot tests of a constructor call are useful drift guards, but lifecycle, protocol, and proxy claims still need observable worker/socket tests. Chirp Audit Snapshot The issue that produced this guide audited Chirp main at commit 9ada3ba4b26ed37fbfde0ef69b60c3897830d3d3 on 2026-07-08. Already aligned: worker_mode, metrics_path, keep_alive_timeout, request_timeout, and write_timeout; trusted_proxies → trusted_hosts plus forwarded_for_trusted_hops; TLS, logging, backpressure, WebSocket, OpenTelemetry, and Sentry settings; Chirp auth rate limiting uses the Pounce-normalized ASGI client rather than reparsing raw X-Forwarded-For. Machine-verified gaps: Chirp's 16 MiB max_request_body_size is not passed to Pounce, whose 1 MiB default rejects larger requests before Chirp sees them. Chirp pins Pounce 0.8.2 and rejects sync worker hooks using the old Pounce 0.7 lifecycle limitation; Pounce #244 and #245 now provide sync hooks and fail-loud startup on main. worker_startup_failure, startup_timeout, shutdown_timeout, header_timeout, and executor_threads_per_worker are not adapter inputs. Chirp passes a live app without app_path and deliberately rejects subinterpreter mode pending an import contract. The downstream work is tracked in Chirp #627. This is a dated audit snapshot; use Chirp's current source and issue state for the live answer. See Also Production — General production setup Railway — Edge/origin topology and proxy trust ServerConfig — Complete field reference Core contract — Canonical ownership and proof rules -------------------------------------------------------------------------------- Metadata: - Word Count: 1055 - Reading Time: 5 minutes