AT Protocol URIs (at://) have no default browser handler —
they're a natural fit for Alap's Option of Choice pattern. This example
shows two data modes: static entries in allLinks
and dynamic results from the :atproto: protocol handler.
allLinks — no API calls
Each post is hand-curated with entries for different clients and tools. Tags control which destinations appear in the menu.
EFF post — all destinations: client, inspector, raw JSON
Paul Frazee post (clients only) — intersection: .pfrazee_post + .client
All posts (dev tools only) — every post's inspection link
<a class="alap" data-alap-linkitems=".eff_post">EFF post</a>
<a class="alap" data-alap-linkitems=".pfrazee_post + .client">Paul Frazee post (clients only)</a>
<a class="alap" data-alap-linkitems=".atproto_post + .devtool">All posts (dev tools only)</a>
allLinks — no API calls
Profiles tagged by category. The expression grammar selects which
slice of allLinks to show.
Organizations — EFF, Internet Archive, Creative Commons, Signal
News & Publications — Nature, The Verge, Ars Technica, WIRED, NYT, New Yorker, TechCrunch
Tech Platforms — AT Protocol, Bluesky, GitHub, Node.js, WordPress, Linux Foundation
Everyone (clients) — macro: @all_profiles
<a class="alap" data-alap-linkitems=".orgs + .client">Organizations</a>
<a class="alap" data-alap-linkitems=".news + .client">News & Publications</a>
<a class="alap" data-alap-linkitems=".tech + .client">Tech Platforms</a>
<a class="alap" data-alap-linkitems="@all_profiles">Everyone (clients)</a>
:atproto: protocol — fetched from the network
The :atproto: handler calls the public Bluesky API and
maps the response to AlapLink objects. No auth needed.
AT Protocol team — :atproto:profile:atproto.com:
EFF — fetched live from the API
Internet Archive — a different organization
<a class="alap" data-alap-linkitems=":atproto:profile:atproto.com:">AT Protocol team</a>
<a class="alap" data-alap-linkitems=":atproto:profile:eff.org:">EFF</a>
<a class="alap" data-alap-linkitems=":atproto:profile:archive.org:">Internet Archive</a>
:atproto: protocol — fetched from the network
Recent posts from different accounts. Same handler, different content.
AT Protocol — recent posts — :atproto:feed:atproto.com:limit=5:
EFF — recent posts — digital rights and policy
Nature — recent posts — science journal
The Verge — recent posts — tech news
Internet Archive — recent 3 — with limit=3
<a class="alap" data-alap-linkitems=":atproto:feed:atproto.com:limit=5:">AT Protocol — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:eff.org:limit=5:">EFF — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:nature.com:limit=5:">Nature — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:theverge.com:limit=5:">The Verge — recent posts</a>
<a class="alap" data-alap-linkitems=":atproto:feed:archive.org:limit=3:">Internet Archive — recent 3</a>
:atproto: protocol — fetched from the network
Search for accounts by keyword. Results are live.
People: "open source" — :atproto:people:open_source:limit=5: (alias for "open source")
People: "creative commons" — alias for "creative commons"
People: "atproto" — protocol community
<a class="alap" data-alap-linkitems=":atproto:people:open_source:limit=5:">People: "open source"</a>
<a class="alap" data-alap-linkitems=":atproto:people:creative_commons:limit=5:">People: "creative commons"</a>
<a class="alap" data-alap-linkitems=":atproto:people:atproto:limit=5:">People: "atproto"</a>
// Multi-word queries use aliases defined in the config:
// searches: { open_source: 'open source', creative_commons: 'creative commons' }
allLinks blended with :atproto: protocol
The same expression grammar works across both data sources. Curated local entries and live API results in one menu.
Org profiles + live EFF posts — static org links merged with 3 recent EFF posts
News outlets, then Nature posts — comma-separated: sorted news profiles, then live science posts
Tech platforms + AT Proto people — curated platforms merged with live people search
<a class="alap" data-alap-linkitems=".orgs + .client | :atproto:feed:eff.org:limit=3:">Org profiles + live EFF posts</a>
<a class="alap" data-alap-linkitems="(.news + .client *sort:label*), (:atproto:feed:nature.com:limit=3:)">News outlets, then Nature posts</a>
<a class="alap" data-alap-linkitems=".tech + .client | :atproto:people:atproto:limit=3:">Tech platforms + AT Proto people</a>
:atproto: protocol — requires authentication
Post search (searchPosts) requires a logged-in session.
Use the login bar above with an
app password.
Log in above to enable these links.
Search: "decentralization" — :atproto:search:decentralization:limit=5:
Search: "open web" — find posts about the open web
Search: "accessibility" — a11y discussions
Or search for anything:
<a class="alap" data-alap-linkitems=":atproto:search:decentralization:limit=5:">Search: "decentralization"</a>
<a class="alap" data-alap-linkitems=":atproto:search:open_web:limit=5:">Search: "open web"</a>
<a class="alap" data-alap-linkitems=":atproto:search:accessibility:limit=5:">Search: "accessibility"</a>
The complete configuration object powering this example.
allLinks is static local data, protocols.atproto
is the dynamic handler that fetches from the network.
Next:
Three Sources, One Menu
— combine static config, :web:, and :atproto: in a single expression.