Integration Adapters
Pharos ships a bounded integration-adapter layer so apps can declare outbound delivery and local operational record emission without owning transport code.
Apps declare adapters in data/contracts/integrations.yml. The shared runtime owns delivery behavior, retries, and reporting.
Adapter families
The supported adapter families are:
- outbound HTTP JSON
- outbound HTTP form
- framework webhook delivery
- framework webhook endpoints and receipt persistence
- local notification
- SMTP-backed notification
- local audit
- local JSONL file-record append
- local JSON file overwrite
Example files
| Goal | Best first example | Why | |---|---|---| | JSON and form webhook delivery | dynamic_app | smallest bounded transport proof | | inbound webhook verification and receipt persistence | ucal | smallest proof of framework-owned webhook endpoint handling | | authenticated workflow delivery | ucal | larger integration-aware app | | local audit or local file-record emission | dynamic_app | direct local effect proof | | password-reset and notification flow | ucal | real email-oriented workflow path |
Outbound HTTP JSON
Use http_json when the target expects a JSON payload.
Typical declared fields include:
- target URL environment variable
- content type
- auth header or auth scheme
- timeout
- retry policy
- response-size limit
Working example:
apps/dynamic_app/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
Expected result:
- declared JSON request is delivered to the mock endpoint
- auth and event headers are present
- delivery is recorded by the shared runtime
Outbound HTTP form
Use http_form when the target expects form-encoded data rather than JSON.
Working example:
apps/dynamic_app/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
Expected result:
- form body is encoded by the framework
- adapter-specific auth header is applied
- delivery remains visible through the same shared ledger
Framework webhook delivery
Use webhook delivery when an action or workflow should enqueue a declared delivery target rather than performing network code in the app.
Working examples:
apps/dynamic_app/data/contracts/actions.ymlapps/ucal/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
bin/pharos build app ucal --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
sh scripts/check.sh ucal integrations
Expected result:
- outbound deliveries are attempted through the shared runtime
- retryable failures are recorded
- successful deliveries are visible in the runtime ledger
Framework webhook endpoints and receipts
Use webhook_endpoints when a Pharos app should accept a signed inbound webhook through the framework-owned route shape instead of owning custom request verification code.
Working example:
apps/ucal/data/contracts/integrations.yml
Validation path:
bin/pharos build app ucal --build-dir dist
sh scripts/check.sh ucal integrations
Expected result:
- an invalid signature is rejected and still recorded as a receipt
- a valid signature is accepted
- verification results are persisted in
webhook_receipts
Local notification and SMTP-backed notification
Use notifications when the app needs a framework-owned message fan-out path.
Use local notifications for:
- local proving
- runtime evidence
- message inspection without external delivery
Use SMTP-backed notifications for:
- actual email delivery through declared adapter config
Working examples:
apps/dynamic_app/templates/email/*.ymlapps/ucal/templates/email/*.ymlapps/ucal/data/contracts/integrations.yml
Validation path:
bin/pharos build app ucal --build-dir dist
sh scripts/check.sh ucal auth-security
sh scripts/check.sh ucal integrations
Expected result:
- password-reset and invite flows render the declared email templates
- delivery work is recorded through the shared notification path
- SMTP-backed deliveries skip cleanly with explicit status when the runtime
relay is unavailable or disabled
Local audit
Use audit_local when the app should emit a bounded local audit record without adding custom write plumbing.
Working example:
apps/dynamic_app/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
Expected result:
- audit events are persisted through the declared local adapter
Local file-record adapters
Pharos now ships two bounded local file-record adapters.
append_jsonl_local
Use append_jsonl_local when the app should persist a structured local file record through a framework-owned append path.
Working example:
apps/dynamic_app/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
Expected result:
- file records are appended to the declared JSONL path
- the app does not need custom file-write logic
write_json_local
Use write_json_local when the app should overwrite one bounded local JSON file with the structured record payload.
Working example:
apps/dynamic_app/data/contracts/integrations.yml
Validation path:
bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime
Expected result:
- a bounded JSON snapshot file is written through the shared adapter path
- the written file contains the adapter id, adapter kind, action id, and
- the app does not need custom overwrite logic
resource identity from the emitted record
Failure-path expectations
Adapter families that talk to external destinations must prove failure handling.
The shared validation path proves:
- retryable outbound failure is recorded
- success delivery is recorded
- declared adapter policy is still bounded by framework-owned transport code
The proving path for this behavior is:
bin/pharos build app ucal --build-dir dist
sh scripts/check.sh ucal integrations