Releases: ael-dev3/Warpkeep
Release list
Farcaster Mini App Notifications — Production Playbook
Technical publication: this release is not a new Warpkeep game version and is intentionally not marked Latest.
This is the public implementation and operations guide behind Warpkeep's first
confirmed Farcaster Mini App admission alert. The alert was visibly observed by
the owner canary on 4 August 2026. A public-safe operator receipt classified the
legacy admitted generation as already-sent after six bounded attempts with no
authority-verification failure. That canary proved the real transport could
work; because it was an already-admitted reconciliation, it did not prove the
required notification-before-admission ordering. The accompanying
notification-first path closes that gap for future admissions.
The useful lesson was simple: a notification is not one API call. It is a small
protocol with separate consent, provider, launch, identity, and
application-authority states.
The design below is intentionally reusable. Warpkeep's game-specific admission
rules are one example of a higher-stakes action that should happen only after
the notification flow has been verified.
The five states that matter
| State | Evidence | What it proves |
|---|---|---|
| Consent recorded | A valid signed miniapp_added or notifications_enabled webhook containing notification details |
A Farcaster client issued a token for this Mini App, client, and FID |
| Provider accepted | The exact token appears in successfulTokens |
The notification server accepted the handoff |
| Alert launch observed | context.location.type === "notification" and its notificationId matches |
The host launched the Mini App from that notification context |
| Identity verified | A server-verified Quick Auth JWT has the expected domain and FID | The current authenticated Farcaster identity matches the workflow |
| Application action committed | The app's authority layer accepts a compare-and-swap transition | The protected application state actually changed |
Do not collapse these into one status. In particular, successfulTokens does
not prove device delivery, OS display, a human read, or a click. Farcaster's
notification guide documents provider response categories separately from the
later notification launch context.
The working sequence
sequenceDiagram
actor Player
participant Host as Farcaster client
participant Bridge as Notification server
participant Store as Private token/state store
participant Authority as Application authority
Player->>Host: Add Mini App / enable notifications
Host->>Bridge: Signed add or enable webhook
Bridge->>Bridge: Verify JSON Farcaster Signature and app key
Bridge->>Store: Replace token + exact delivery URL
Bridge-->>Host: 200
Authority->>Bridge: Queue exact workflow generation
Bridge->>Authority: Re-read eligible state
Bridge->>Host: POST notification payload + private token
Host-->>Bridge: successfulTokens / invalidTokens / rateLimitedTokens
Bridge->>Store: Record provider outcome without token material
Player->>Host: Open alert
Host->>Bridge: Mini App launch with notification context
Bridge->>Bridge: Match notification ID + one-use capability + fresh Quick Auth FID
Bridge->>Store: Consume capability once
Bridge->>Authority: Re-read generation and compare-and-swap
Authority-->>Player: Commit protected actionWarpkeep does not admit a player merely because the provider accepted a
notification. Provider acceptance creates a one-use, time-bounded grant intent.
The alert opens the Mini App with:
- a unique
notificationIdin Farcaster's immutable notification launch
context; - a separate one-use capability in the target URL fragment, removed from the
visible URL before rendering; and - a freshly requested Quick Auth token that the server validates for the same
FID and domain.
Only after all three match does the notification service record a client
acknowledgement. The operator then re-reads the unchanged access-request
generation and uses a compare-and-swap admission reducer. A stale request,
different FID, launcher context, reused ticket, expired intent, or changed
authority state fails closed.
1. Publish the exact webhook URL
Notifications require webhookUrl in the Mini App manifest served from the
registered production domain:
{
"miniapp": {
"version": "1",
"name": "Example",
"homeUrl": "https://example.com",
"webhookUrl": "https://api.example.com/farcaster/webhook"
}
}The production domain matters. Farcaster documents that addMiniApp() works
against the deployed domain matching the manifest, not a development tunnel.
2. Treat webhooks as signed state transitions
Handle the four current events:
miniapp_added: store notification details when present; their presence is
optional;notifications_enabled: replace the existing token and URL;notifications_disabled: invalidate and erase the token immediately;miniapp_removed: invalidate and erase every token for that FID/client pair.
Verify the JSON Farcaster Signature and current app-key authority before using
the FID or notification details. The official @farcaster/miniapp-node package
provides parseWebhookEvent; its app-key validation callback still needs a
current Farcaster network view. Return 200 only after the relevant state is
durably stored. Clients may retry non-200 webhooks, so make each envelope
idempotent.
Store the token and the exact URL only on the server. A notification token is a
secret permission scoped to the Farcaster client, Mini App, and user FID. Never
put it in browser state, public tables, analytics, query strings, or logs.
Warpkeep additionally verifies app-key state through independent Hub views and
independent Optimism RPC views. That is application hardening, not a Farcaster
requirement. Its delivery pause suppresses sends but deliberately continues to
accept valid enable, disable, add, and remove events so consent state cannot be
lost during a rollout.
3. Send the notification
POST the payload to the exact URL supplied with the token:
{
"notificationId": "access-grant-<unique-intent>",
"title": "Welcome",
"body": "Open the app to continue.",
"targetUrl": "https://example.com/#grant=<one-use-capability>",
"tokens": ["<private-token>"]
}Current Farcaster limits are:
notificationId: 128 characters;- title: 32 characters;
- body: 128 characters;
targetUrl: 1,024 characters and the exact registered hostname;- tokens: at most 100 per request.
The hostname comparison includes subdomains. A mismatch can permanently
invalidate the affected token. Validate the stored destination against a
server-side allowlist before every send; never accept an arbitrary delivery URL
from an operator request or browser.
Use a stable notificationId while retrying the same logical alert. Farcaster
combines FID and notification ID as a 24-hour idempotency key. Generate a new ID
only when intentionally issuing a new alert. Warpcast currently documents one
notification per 30 seconds and 100 per day per token; other clients may apply
their own limits.
4. Classify the provider response exactly
An HTTP 200 response has three primary token lists:
successfulTokens: record provider acceptance;invalidTokens: erase those tokens and require a new signed enable event;rateLimitedTokens: retain consent and retry after backoff.
Validate that the response accounts for the token exactly once. Bound response
size and time, reject redirects, and distinguish transport failures from
application-authority verification failures. An authority outage should not
consume the entire outbound-delivery retry budget.
Warpkeep uses six bounded delivery attempts with backoff and a 24-hour pending
lifetime. Invalid tokens are removed immediately. A provider-accepted but
unopened grant can be deliberately reissued no more than twice for the exact
request generation, after a five-minute quiet period. Reissue rotates the
intent, notification ID, and capability; ordinary status polling never sends a
new alert.
5. Verify the launch separately
When a player opens an alert, the host sets:
sdk.context.location = {
type: 'notification',
notification: {
notificationId,
title,
body,
},
}Compare notificationId with server-side intent state. Do not authorize from
context.user: Farcaster's context documentation explicitly treats user and
client context as untrusted presentation data.
Authenticate the request independently. Quick Auth returns a signed JWT whose
sub is the FID; validate it on the server for the registered domain. For
Warpkeep's admission acknowledgement, a normal browser session cannot replace
Quick Auth, and the client requests a fresh host token for the first attempt.
That is a Warpkeep security policy rather than a platform requirement.
For sensitive workflows, bind the notification ID to an additional one-use
capability and the exact server-side workflow generation. Consume it once,
serialize acknowledgement against reissue, and perform the final authority
mutation with compare-and-swap.
Token-free diagnostics
Useful diagnostics do not need notification secrets. Warpkeep exposes a
protected operator projection containing only bounded state such as:
- system state: enabled or paused;
- subscription state and active count;
- workflow generation: pending request or admitted epoch;
- delivery state: queued, retrying, accepted, exhausted, or absent;
- grant state: created, provider accepted, or client acknowledged;
- attempt and verification-failure counts;
- coarse failure category and next retry time;
- provider-acceptance and client-acknowledgement timestamps.
Do not log notification tokens, delivery URLs, one-use capabilities,
notification IDs, webhook envelopes, Quick Auth JWTs, provider bodies, profile
data, IP addresses, or administrator credentials. Keep detailed receipts in a
private audit record; public re...
Warpkeep Alpha 0.3.43 — The Realm Stands Ready
Warpkeep’s invite-only Founder Alpha is ready for its official Farcaster Mini App introduction.
- The Realm now recovers intelligently on weaker phones and embedded browsers, stepping down visual quality before offering clear diagnostics and a safe way back.
- Request Access is now a quiet, one-shot petition with a durable recorded state and a finished confirmation screen.
- The Mini App listing, copy, screenshots, icons, README, patch notes, and in-game build identity now describe this release.
- The current Alpha supports permanent keeps, four Worker journeys, and persistent resource gathering. Construction, units, combat, and alliances remain in development.
Admission remains manual and invite-only. This release preserves every existing keep, Worker, resource, balance, and Realm record; no production data was reset.
Merged in #165.
Presentation update: PR #167 replaced the Farcaster feed embed with the owner-supplied Genesis 001 founder-realm artwork at a cache-safe, content-addressed URL. The live presentation commit is 44914e3; gameplay and persistent data are unchanged.
Warpkeep Alpha 0.3.42 — The Gate Falls Quiet
The Hegemony admission gate is deliberately quiet again.
- Request Access keeps its violet-and-gold response and one-request latch, without playing audio.
- The admission sample, runtime player, preload path, and bundled production bytes have been removed.
- Release guards now reject the retired filename and trigger if they re-enter a production artifact.
- The original audio remains preserved in the Warpkeep Assets release archive with its provenance receipts.
No authentication, admission, realm-state, or SpacetimeDB data was changed by this release.
Merged in #164.
Warpkeep Alpha 0.3.41 — The Realm Mends Itself
Genesis 001 now tries to mend an interrupted graphics session before asking its keeper to act.
Warpkeep bounds the entire initial and restored scene lifecycle, safely retires stalled renderer generations, and retries on a genuinely fresh canvas one visual tier lighter for the current session—without changing the player’s saved setting. If 3D remains unreliable, the Realm opens a lightweight 2D safety overview with clear Retry and Return choices instead of an endless restoring veil.
Every classified graphics failure now explains what stopped, likely device or browser causes, the automatic response in progress, a stable WK-GFX reference, privacy-safe compatibility details, and a direct support path. Android Chrome and Farcaster Android WebView regressions cover backgrounding, restoration, repeated first-frame loss, deadlines, stale callbacks, and terminal recovery.
Authentication, admission, Terms, keeps, Workers, resources, balances, and persistent world state are unchanged.
Merged in PR #163.
Warpkeep Alpha 0.3.40 — The Realm Endures
The Realm no longer leaves an Android keeper behind an endless restoring veil after WebGL context loss.
A disrupted scene now receives one bounded rebuild. If needed, Warpkeep retries one visual tier lighter for the current browser session without changing the keeper’s saved graphics choice. A stalled generation is safely released into clear Retry and Return choices, while late callbacks cannot revive an obsolete renderer.
Exact Android Chrome and Farcaster Android WebView lifecycle journeys cover successful recovery, timeout, repeated loss, dependency churn, and stale callbacks. Authentication, admission, keeps, Workers, resources, balances, and persistent world state are unchanged.
Merged in PR #162.
Warpkeep Alpha 0.3.39 — The Petition Holds
One petition now holds.
When a keeper asks to enter the Hegemony frontier, the first deliberate gesture seals immediately and remains Request Sent while the private records confirm it—even if the menu changes, the Mini App remounts, or the road briefly goes dark. The Hegemony resonance and violet-and-gold seal play once.
Check Again now performs a status-only reconciliation. It cannot silently send another petition. SpacetimeDB continues to preserve one private request per admission cycle, while admission remains a separate manual decision.
This release changes no castle, ownership, balance, resource, Worker, or persistent Realm data.
Merged in PR #161.
Warpkeep Alpha 0.3.38 — The Way Back
Returning keepers who enter Genesis 001 directly from Farcaster now retain the Mini App’s native Back control at the Realm root. It returns to Warpkeep’s menu without signing the keeper out.
Inside a Realm record or panel, Back still closes one layer at a time before returning to the menu. The route adds no new overlay to the map and does not alter authentication, admission, Terms, ownership, Workers, resources, balances, or persistent world state.
Merged in PR #160.
Warpkeep Alpha 0.3.37 — The Gate Heeds Once
Request Access now seals itself as Request Sent on the first accepted gesture, before any parent or network round trip can invite a second tap. The exact Hegemony resonance, gold strike, and violet water-like echo answer only that gesture.
A petition already held by SpacetimeDB returns as Request Received and remains closed across refreshes. A proven availability failure may still recover through the existing status-first retry, without weakening manual admission or changing Realm data.
Merged in PR #159.
Warpkeep Alpha 0.3.36 — The Gate Resounds
The Hegemony gate now answers an admission request with its own two-second resonance: a precise gold strike followed by a restrained violet, water-like echo. The motion is synchronized to the approved sound, respects reduced-motion and mute preferences, and remains stable inside Farcaster Mini App browsers.
The response is deliberately bounded to one voice at a time and stops cleanly when the page is hidden or audio is disabled. Admission authority and realm data are unchanged.
Merged in PR #158.
Warpkeep Alpha 0.3.35 — The Petition Is Sealed
A newly placed access petition now receives a restrained violet-and-gold Hegemony seal as the gateway acknowledges it.
- The flourish begins on the first Request Access click and carries through the immediate Request Sent state.
- It stays outside layout and input handling, so it neither moves the gateway nor captures another touch.
- Reduced-motion players receive the same clear state change without decorative movement.
- Existing private petition records remain calm, received, and impossible to submit again.
This is a frontend-only release. It does not publish a database module, grant admission, or mutate Realm data.