For builders
Your app reviews.
Swan rechecks.
Put Swan in the application that owns capture and sending. Your assistant proposes an action. Your trusted review screen shows the exact content and recipient. Swan checks that approval again right before the send.
Run Swan on your computer
Download the Swan 0.4 Python package into a folder. With Python 3.10 or newer, run these commands from that folder:
python3 -m venv .venv
.venv/bin/python -m pip install ./swan_wearable_security-0.4.0-py3-none-any.whl
.venv/bin/swan-demo --case valid_upload
.venv/bin/swan-demo --case recipient_drift
The demo uses a fixed sample and a private receiver on your computer. It checks what arrived, then closes the receiver. It needs no camera or account. Download the package.
Connect your application
Your application supplies the camera bytes, their real capture time, its bystander decision, and a trusted review screen. This is the connection pattern; the runnable demo above supplies those pieces locally.
from swan import CaptureGuard, HttpDestination
recipient = HttpDestination("https://your-service.example/observation")
guard = CaptureGuard(
max_capture_age=30,
allowed_destinations=(recipient,),
)
# Call these from trusted device and permission callbacks.
guard.connect("selected-device")
guard.permission("camera", True)
epoch = guard.start_stream()
def prepare_review(picture_bytes, captured_at, bystander_status):
frame = guard.observe_frame(
epoch, picture_bytes,
captured_at=captured_at,
bystanders=bystander_status,
)
return guard.propose(
frame, picture_bytes, recipient,
payload_kind="source",
)
# Your trusted review screen shows picture_bytes and recipient.
# Call this function only from its confirmed human-approval callback.
def on_person_approved(proposal, picture_bytes):
approval = guard.approve(proposal)
return guard.dispatch(
approval, proposal, picture_bytes, recipient,
)
The same exact recipient must be allowed, reviewed, and sent. captured_at comes from the source using the guard's monotonic clock; callback arrival is not capture time. Your application decides bystander status. If the person declines, call guard.cancel(proposal). Run the network send off the screen's main thread.
Know whether it arrived
Basic dispatch can report that the receiver answered, but a lost answer leaves delivery uncertain. Swan 0.4 can also check a durable receiver record. To use this, your authenticated service must save a receipt after POST /observation and return the same record from GET /observation/receipts/{id}. Save the operation ID before sending so the application can check again after a restart.
from swan import ReceiptClient, dispatch_with_receipt, new_operation_id
# Use these instead of the two functions above when your receiver
# supports durable receipts. save_intent is your app's durable callback.
def prepare_confirmed_review(
picture_bytes, captured_at, bystander_status, save_intent,
):
frame = guard.observe_frame(
epoch, picture_bytes,
captured_at=captured_at, bystanders=bystander_status,
)
operation_id = new_operation_id()
save_intent(operation_id, recipient, picture_bytes)
return guard.propose(
frame, picture_bytes, recipient,
operation_id=operation_id, payload_kind="source",
)
# Call only after your trusted screen confirms human approval.
def on_person_approved_with_receipt(
proposal, picture_bytes, your_trusted_auth_header,
):
approval = guard.approve(proposal)
client = ReceiptClient(
recipient, namespace="your-account",
authorization=your_trusted_auth_header,
)
return dispatch_with_receipt(
guard, approval, proposal, picture_bytes, client,
)
The receipt route must authenticate the same account as the upload route. your_trusted_auth_header is an application-owned function that supplies the Authorization header; Swan does not store credentials or create the receiver. A matching receipt confirms the receiver stored the exact payload record. It does not confirm later business actions.
One result. A clear next step.
| Result | What happened | What your app does |
|---|---|---|
blocked | This dispatch did not call the sender. | Explain the change. Ask for a fresh review. |
accepted | The service returned HTTP success. | Read the service's own record before claiming completion. |
confirmed | A matching stored receipt was read back. | Show that the receiver recorded the exact send. |
delivery_unknown | Delivery could not be confirmed. | Check the receiver. Never retry automatically. |
Keep the boundary intact
- All protected sends go through
dispatchordispatch_with_receipt. Keep approval and source-state methods out of the assistant's tools. - Invalidate pending work when the camera stops, permission changes or the source disconnects. Reconnecting needs a fresh stream and a fresh review.
- Dispatch consumes the approval on its first attempt. Restarting the guard loses pending approvals.
- Run the send off the UI thread. A network request that has already started cannot be recalled.
- The default sender uses HTTPS externally, follows no redirects, ignores environment proxies, and times out after five seconds. An authenticated service needs a transport you own that keeps the same destination and bytes.
What exists today
The downloadable Python 0.4 library includes the guard and optional receipt checks. An Android callback adapter is implemented separately. Your application provides its own authenticated review screen and receiver; neither is supplied as a hosted service here.