Compiled Host Contract
Pharos can build an app artifact that is served by an executable host generated as part of pharos build, or served directly by the Pharos binary for static-pages app targets.
These are the current minimal contracts.
Pharos compiled hosts sit on top of a lower executable host/runtime process boundary. Pharos adds app-specific assembly, serving, artifact shaping, and state behavior on top of that boundary.
Contract IDs
pharos.compiled_host.static_pages.v1
pharos.compiled_host.dynamic_app.v1
Scope
These contracts are intentionally narrow.
static_pages.v1 covers a static app target whose artifact is fully materialized under the selected --build-dir.
dynamic_app.v1 covers a small stateful app target whose host owns:
- a local JSON state file
- a small HTML page surface
- a JSON state API
- form POST actions
- optional multipart/form-data parsing for bundle-based dynamic hosts
They do not yet cover:
- multi-surface dynamic applications
- auth/session flows
- richer maintenance mutations
- auth/session flows
App Manifest Shape
The app manifest declares:
{
"runtime": {
"host_profile": "static-pages | dynamic-app"
},
"fixtures": {
"integration_fixture": "data/framework/<integration-fixture>.json"
}
}
Meaning:
host_profiletells Pharos whether the app uses the static-pages direct-artifact contract or the dynamic-app native runtime contract- source manifests for both
static-pagesanddynamic-appmay omitcompiled_entrypoint - after P3.8,
dynamic-appapps must not depend onruntime/<app_id>_native_host static-pagesapps are served directly from the finalized artifact by the Pharos native runtime path rather than through an app-owned checked-in shell host- app-owned host bundles are no longer part of the canonical runtime story for
dynamic-app
Generated Host Surface
When a generated host artifact exists, the executable surface must support:
--build-dir PATH--summary--seed-state--serve--host HOST--port PORT
At the process/runtime layer, Pharos expects deterministic argv dispatch and explicit filesystem/report behavior. Hidden subprocess or network behavior is out of contract unless a higher runtime contract declares it directly.
Behavior:
--seed-state: returns a JSON seed acknowledgement--summary: returns JSON with route/surface/workflow counts--serve: serves the built artifact directory over HTTPdynamic_app.v1additionally owns a local JSON state file and simple POST mutations
For the current native runtime path, static-pages apps do not require a generated checked-in executable host in source control and the finalized native-built artifact records an empty compiled_entrypoint.
Bundle-Based Dynamic Host Surface
When a dynamic-app provides an app-owned host entry and companion bundle directory under runtime/<app-host>.d/, Pharos stages that source bundle into the built compiled host and exposes a stable helper surface for common HTTP/runtime behavior, multipart parsing, integrations, generated surfaces, and workflow logic.
Current core helper functions:
pharos_normalize_base_path BASE_PATHpharos_cookie_pathpharos_prefix_path PATHpharos_strip_base_path PATHpharos_apply_base_path_html HTMLpharos_url_decode VALUEpharos_cookie_value COOKIE_HEADER COOKIE_NAMEpharos_form_value FORM_BODY FIELD_NAMEpharos_query_value QUERY_STRING FIELD_NAMEpharos_http_response STATUS CONTENT_TYPE BODY [EXTRA_HEADERS]pharos_http_stream_begin STATUS CONTENT_TYPE [EXTRA_HEADERS]pharos_http_redirect LOCATION [EXTRA_HEADERS]pharos_builtin_route_dispatch_response STATE_PATH REQUEST_TARGET REQUEST_HEADERS METHOD ROUTED_PATH [USER_JSON] [SUBSCRIPTION_SCOPE_JSON]pharos_event_stream_response STATE_PATH REQUEST_TARGET REQUEST_HEADERS [USER_JSON] [SUBSCRIPTION_SCOPE_JSON]pharos_request_is_framework_csrf_exempt METHOD ROUTED_PATHpharos_webhook_route_response STATE_PATH REQUEST_TARGET REQUEST_HEADERS ROUTED_PATH REQUEST_CONTENT_TYPE REQUEST_BODY_PATHpharos_event_stream_rows STATE_PATH SINCE_ID LIMIT [SUBSCRIPTION_SCOPE_JSON] [FILTERS_JSON]pharos_event_stream_emit_rows STATE_PATH SINCE_ID LIMIT [SUBSCRIPTION_SCOPE_JSON] [FILTERS_JSON]pharos_state_append_audit_event STATE_PATH EVENT_KIND [PAYLOAD_JSON]pharos_state_append_workflow_execution_event STATE_PATH EVENT_KIND [PAYLOAD_JSON]pharos_content_type_for_file FILE_PATHpharos_serve_common_asset ROUTED_PATH ARTIFACT_DIR MANIFEST_PATH
Current helper functions:
pharos_multipart_extract_text BODY_FILE CONTENT_TYPE FIELD_NAMEpharos_multipart_extract_file BODY_FILE CONTENT_TYPE FIELD_NAME OUTPUT_PATH
These helpers are the formal dynamic_app.v1 surface for:
- base-path-aware routing and HTML rewriting
- cookie, form, and query parsing
- HTTP response, connection-close streaming response, and redirect emission
- framework-owned reserved runtime routes, SSE event transport, and inbound webhook dispatch
- framework-owned audit/workflow event publication helpers for dynamic hosts
- common static/media/manifest asset serving
- multipart form fields and uploaded files in template-based hosts
Native Listener Request/Response Boundary
The native Pharos listener owns a distinct forwarding and fail-closed boundary in front of compiled app hosts.
That boundary is an implementation seam, not a desired permanent divergence point. Validate native listener behavior and compiled-host behavior together in normal local testing.
Native-owned behavior includes:
- request line parsing
- newline-normalized forwarded headers
- default request metadata when headers are absent
- plain-text fallback responses for native-owned failures
502 Bad Gatewayfail-closed behavior when compiled app execution fails or returns no response bytes
That boundary is tracked explicitly in native-request-response-parity.md so request parsing and fallback response defaults do not drift silently from the compiled-host contract.
Preferred local convergence check:
scripts/check.sh native-compiled-flow
Artifact Manifest Fields
The built app manifest includes:
host_profilecompiled_entrypointcompiled_host_contractcompiled_host_capabilitiesprocess_runtime_contractprocess_runtime_capabilitiesintegration_fixture
Current values:
compiled_host_contract: "pharos.compiled_host.static_pages.v1"
or
compiled_host_contract: "pharos.compiled_host.dynamic_app.v1"
Example capabilities for a bundle-based dynamic host:
local_json_statehtml_routesjson_state_apiform_post_actionsbase_path_routingcookie_query_form_helpershttp_response_helpersstatic_media_asset_routesmultipart_form_fieldsmultipart_file_uploadsbuiltin_runtime_routesrealtime_sse_transportintegration_webhook_routes
Pharos also writes a compiled host sidecar manifest at:
<compiled_entrypoint>.manifest.jsonwhen a generated compiled host artifact exists
That sidecar is the runtime-checked process contract Pharos validates before executing a generated native host artifact.
Event Stream Contract Additions
The reserved runtime route GET /_pharos/events/ is the framework-owned SSE surface for compiled dynamic hosts.
Current query parameters:
sincelimittimeoutsourceevent_kindresource_idtrace_id- app-defined scope selectors such as
tenant_id
Current event frame payload fields:
stream_idsourceevent_kindcreated_atuser_idbusiness_idtenant_idresource_kindresource_idreplay_trace_idpayload_json
This keeps subscription transport, row shaping, and audit/workflow publication owned by Pharos while allowing app templates to provide only scope decisions and app-specific UI behavior.
Webhook Route Contract Additions
The reserved runtime route POST /_pharos/webhooks/<endpoint_id>/ is the framework-owned inbound webhook surface for compiled dynamic hosts.
Current behavior:
- resolves endpoint contracts from the built app manifest and declared
integration_fixture - accepts JSON payloads only
- verifies HMAC signatures and timestamp freshness when the endpoint contract requires them
- records webhook receipts into the app runtime state ledger
- appends framework-owned audit events for accepted and rejected webhook deliveries
- is CSRF-exempt through the framework helper surface for reserved webhook routes only
This keeps signature verification, receipt persistence, and operator-visible inbound integration evidence in Pharos while allowing apps to opt in declaratively through an integration fixture.
Current Proof Target
The checked static proof target is:
The checked dynamic proof target is:
Both targets have no Python runtime entrypoint. Pharos builds a native host target for them, and app outputs should converge on that native-host delivery path rather than splitting between compiled-host and direct static runtime modes.
Current Boundary
Pharos discovers demo and product apps as standalone app roots through pharos.app.json instead of built-in website target cases. The active launcher/runtime path uses the native Pharos binary for listener ownership, static app serving, shared-runtime routing, and dropped-in app discovery. UCAL still uses an app-owned compiled entrypoint for request handling.
Pharos still owns the higher-level app assembly/runtime layer in the shell dispatcher today. The current shared shell split is recorded in ../operations/runtime-surface-ownership.md and is organized around six sourced runtime surfaces plus the dispatcher:
scripts/pharos_runtime.shas the canonical shared dispatcherruntime/pharos_app_runtime_layer.shfor app discovery, path resolution, and shared runtime dispatch helpersruntime/pharos_data_runtime_layer.shfor migrations, seed/verify/apply helpers, and the relational runtime bridgeruntime/pharos_generated_surface_layer.shfor generated surface shaping helpersruntime/pharos_integration_runtime_layer.shfor integration delivery and webhook state helpersruntime/pharos_ops_runtime_layer.shfor operator-facing config/probe/report helpersruntime/pharos_workflow_runtime_layer.shfor workflow execution and replay helpers
On top of that split, Pharos still owns:
- app discovery through
pharos.app.json - artifact materialization
- compiled-host generation for dynamic Pharos app targets
- release/package operations