22 Commits
Author SHA1 Message Date
Bendik Aagaard LynghaugandClaude Opus 5 4e5ac9ceb7 The Atelic Antics poster, and the run it actually has
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
The poster goes under the exhibition question as a slideshow slide —
989×1400 webp, 85K, sized to the "around 1400 pixels tall is plenty"
the content reference asks for.

It also settles a date this page had wrong. The poster runs 24.10 to
15.11; the event here said `duration: 31d` from the 23rd, which reaches
23 November. The header announces the exhibition for as long as the
event window lasts, so that would have kept inviting people to a closed
room for eight days. It is 23d now, and the opening hours the poster
gives — Saturdays and Sundays, 13:00 to 17:00 — are on the feature that
tells people when to come.

The 23rd at 19:00 stays as the start: that is the opening, and the 24th
is the first day the doors are open to everyone else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByshXuDEzH8hXh5qp4VgGk
2026-10-16 10:52:11 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 7c2970c4cd The exhibition has its title, and the zine is not in the room
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
«Atelic Antics» names the group show at Podium where the page
introduces it; the zine feature goes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MznPTC31w5mSUK4XMehcpi
2026-10-06 22:23:49 +02:00
Bendik LynghaugandClaude Opus 5 8d36c819c1 Hide the sign-in link beside the wordmark
Lint and reload / reload (push) Successful in 0s
Lint and reload / lint (push) Successful in 2s
redoal.com is read and answered without an account, so the invitation
to sign in has no audience. Portal's header nav keeps it next to the
wordmark on every page; a skin hides it.

The rule only takes the link in: signed in, the nav still carries the
name and the way out, and the gate on /review still offers its own way
in. First custom.css here, wired through site.yaml's stylesheet key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
2026-10-06 08:10:54 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 da515feb0a The lint is portal lint from the portal release
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
iris stopped at v0.5.10; the lint has been portal itself since 0.6.0,
fetched from the portal release this site runs, as uhhm/questions does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 13:13:18 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 aedf45cf0a Releases come from dl.redoal.com, and the site runs portal 0.6.20
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Failing after 2s
Lint and reload / reload (push) Skipped
The front door's releases card read the private repo's Gitea releases
with its link nulled, since those 404 for visitors. It now reads the
public manifest redoal's release job writes to dl.redoal.com, which
portal renders as a download card with this device's file first. The
pins move from v0.5.2 to v0.6.20 for both the instance and the lint;
the content lints clean on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 12:56:32 +02:00
Bendik Aagaard LynghaugandClaude Opus 5 d1ae870f2d The releases card shows the cut you should run
Lint and reload / reload (push) Successful in 0s
Lint and reload / lint (push) Successful in 2s
One card per release made the section grow forever, and the newest cut
is the one a visitor should actually run — the rest are history, not an
invitation.

`limit` is the portal's mechanism for this (uhhm/portal 22d086f) and
this site is pinned to PORTAL_RELEASE v0.5.2, which predates it, so the
jq takes `.[0]` instead of `.[]` and that is what does the work today.
`limit: 1` is declared alongside it: v0.5.2 ignores fields it does not
know, so it costs nothing now and takes over when the pin moves
forward, at which point the jq goes back to `.[]`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByshXuDEzH8hXh5qp4VgGk
2026-10-04 22:52:50 +02:00
Bendik Aagaard Lynghaug cf5108aec4 Take portal v0.5.2 (the rate limiter needs connect info)
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 1s
2026-09-28 18:13:50 +02:00
Bendik Aagaard LynghaugandClaude Opus 5 6a72c67dab Take portal v0.5.1
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Attachments both ways, rate limiting, sessions that survive a deploy,
and an upload route that asks the policy like every other way in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 17:53:46 +02:00
Bendik Aagaard LynghaugandClaude Opus 5 5e10e21814 Take portal v0.4.0
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Four releases on from v0.3.36: maps and `place:`, a reply to a case
mail becoming a note on its record, and the access policy's newer
rules. iris moves with it, since it is the lint for exactly this
portal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 16:27:47 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 0a51852cb2 deploy: carry KANIDM_API_TOKEN into the instance env
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 1s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 12:27:36 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 2d4f46d152 Lint with iris v0.3.39 (iris is versioned as portal from here on)
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-23 06:04:41 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 32547d782f Lint: run iris from the cargo target dir (the checkout is noexec on this runner)
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-22 17:58:27 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 5ec32823b4 Lint with iris v0.1.0
Lint and reload / lint (push) Failing after 2s
Lint and reload / reload (push) Skipped
The lint now lives in uhhm/iris, pinned to the portal release it
matches; question_lint leaves the portal tarball.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-22 17:42:31 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 c674348b38 Pin portal v0.3.36
Deploy instance / deploy (push) Successful in 2s
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Question nav offers a followup only once it is earned; bounded
outbound fetches; uploads over 2 MB start working.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-22 17:02:32 +02:00
Bendik Aagaard LynghaugandClaude Fable 5 b12a601cae iPhone beta joins via the TestFlight public link
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
The 'redoal testers' external group now has a public link
(https://testflight.apple.com/join/eR9dvHkz) — one tap on an iPhone,
no invitation flow. Replace the Apple-ID form (and its action/
record_as plumbing) with the link; no email collection, nothing for
us to process. The n8n named-invite workflow stays shelved in
redoal/redoal ops/ for a future curated group.

Lint: OK (9 questions, 5 aggregates).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByshXuDEzH8hXh5qp4VgGk
2026-09-12 22:16:44 +02:00
Bendik Aagaard LynghaugandClaude Opus 4.8 59fc40e0cb Testers signup in the Releases alternative; redoal_testers bucket
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Desktop releases run free (the gitea_releases listing, no sign-up); a
'Join the public testers' form on the same alternative collects the
Apple ID for a TestFlight invite, recorded to redoal_testers. New
confirmation page /joined-testers, and an aggregates entry with
attended_by pointing at the n8n TestFlight onboarding automation
(events.redoal_testers.* → App Store Connect).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByshXuDEzH8hXh5qp4VgGk
2026-09-12 16:44:20 +02:00
Bendik Aagaard Lynghaug 45a9526ea2 Pin portal v0.3.35
Deploy instance / deploy (push) Successful in 1s
Lint and reload / lint (push) Successful in 3s
Lint and reload / reload (push) Successful in 0s
2026-09-12 12:21:16 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 a546c2b08f Pin portal v0.3.34
Deploy instance / deploy (push) Successful in 1s
Lint and reload / lint (push) Successful in 3s
Lint and reload / reload (push) Successful in 0s
Question nav offers followups by reach (on the visitor's verified
path, or further down from the current page), not to anyone carrying
any chain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4jrCgLiKKHAEFuZUJjckH
2026-09-11 19:43:44 +02:00
bl af572e91c8 Merge pull request 'Fix voices-echoed card: emit bare object, not wrapped array' (#5) from fix-pulse-jq-nested-array into main
Lint and reload / lint (push) Successful in 3s
Lint and reload / reload (push) Successful in 0s
Reviewed-on: #5
2026-09-11 12:07:47 +00:00
Bendik Aagaard LynghaugandClaude Opus 4.8 6c3aa46ab0 Fix voices-echoed card: emit bare object, not wrapped array
Lint and reload / lint (pull_request) Successful in 3s
Lint and reload / reload (pull_request) Skipped
The portal's apply_jq collects the jq output stream into an array
itself. The wrapping [ … ] made the filter emit one array-valued
output, which nested to [[{…}]] and failed the array-of-objects card
renderer, dumping raw JSON. Emit a bare object like the releases jq
does, so it collects into [{…}] and renders as a card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByshXuDEzH8hXh5qp4VgGk
2026-09-11 11:47:56 +02:00
bl c8d181b8a5 Merge pull request 'Flaunt 'voices echoed so far' on the index (live /pulse count)' (#4) from voices-echoed-count into main
Lint and reload / lint (push) Successful in 2s
Lint and reload / reload (push) Successful in 0s
Reviewed-on: #4
2026-09-11 08:21:18 +00:00
Bendik Aagaard LynghaugandClaude Fable 5 bafdb87102 Flaunt 'voices echoed so far' on the index, live from the relay's /pulse
Lint and reload / lint (pull_request) Successful in 2s
Lint and reload / reload (pull_request) Skipped
A 'The count so far' feature in the index's 'Meet a network' alternative
fetches https://relay.redoal.com/pulse (redoal ADR-0023) with a kind:url
resource and shapes { voices_echoed: N } into one card — the number as
the heading, 'voices echoed so far' beneath. Lint-clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-10 07:36:23 +02:00
11 changed files with 122 additions and 194 deletions
+5 -1
View File
@@ -18,7 +18,7 @@ on:
- .gitea/workflows/deploy.yml - .gitea/workflows/deploy.yml
env: env:
PORTAL_RELEASE: v0.3.33 PORTAL_RELEASE: v0.6.20
INSTANCE: redoal-portal INSTANCE: redoal-portal
jobs: jobs:
@@ -57,6 +57,10 @@ jobs:
KANIDM_URL=${{ vars.KANIDM_URL }} KANIDM_URL=${{ vars.KANIDM_URL }}
OAUTH2_CLIENT_ID=${{ vars.OAUTH2_CLIENT_ID }} OAUTH2_CLIENT_ID=${{ vars.OAUTH2_CLIENT_ID }}
OAUTH2_CLIENT_SECRET=${{ secrets.OAUTH2_CLIENT_SECRET }} OAUTH2_CLIENT_SECRET=${{ secrets.OAUTH2_CLIENT_SECRET }}
# Onboarding from a desk (portal 0.3.40+, `invite:` alternatives): a
# Kanidm service-account token in idm_people_on_boarding. Empty
# means invites are not configured on this instance.
KANIDM_API_TOKEN=${{ secrets.KANIDM_API_TOKEN }}
PUBLIC_URL=${{ vars.PUBLIC_URL }} PUBLIC_URL=${{ vars.PUBLIC_URL }}
COOKIE_SECURE=true COOKIE_SECURE=true
# This repo is its own instance's content source; branding # This repo is its own instance's content source; branding
+11 -6
View File
@@ -15,13 +15,18 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# Same bare-metal runner/host as this repo's own Deploy workflow, # The lint is portal itself (`portal lint`, since portal 0.6.0;
# which ships question_lint alongside the portal binary in every # iris is no longer released), at the version this site runs
# pinned release - so content is validated by the exact portal # (PORTAL_RELEASE in deploy.yml).
# version this instance runs, not a hand-maintained yq/jq subset
# of the same rules.
- name: Lint questions - name: Lint questions
run: /srv/app/redoal-portal/current/question_lint --path questions env:
PORTAL_RELEASE: v0.6.20
run: |
# The checkout is on a noexec mount for this runner; the cargo
# target dir is where it may run what it fetched.
bin="/var/local/cargo-target/portal-lint-$PORTAL_RELEASE"
[ -x "$bin" ] || { curl -sfL "${{ github.server_url }}/uhhm/portal/releases/download/$PORTAL_RELEASE/portal-x86_64-linux" -o "$bin" && chmod +x "$bin"; }
"$bin" lint --path questions
reload: reload:
runs-on: bare runs-on: bare
+16
View File
@@ -38,3 +38,19 @@ aggregates:
kept: { event: kept } kept: { event: kept }
transitions: transitions:
open: [removed, kept] open: [removed, kept]
# TestFlight beta signups (index.yaml's "Test it on your iPhone").
# Attended by automation, not a human desk: a new "requested" signup
# is handed to the App Store Connect API to invite the Apple ID to the
# closed beta; "withdrawn" (the /joined-testers self-transition) drops
# them from the invite list.
- bucket: redoal_testers
attended_by: >
n8n TestFlight onboarding workflow — ops/n8n/testflight-onboarding
in redoal/redoal. Consumes NATS events.redoal_testers.* and calls
App Store Connect POST /v1/betaTesters.
initial: open
states:
open: { event: requested }
withdrawn: { event: withdrawn }
transitions:
open: [withdrawn]
+15
View File
@@ -0,0 +1,15 @@
/* redoal - the skin over portal's own stylesheet
(site.yaml `stylesheet`, loaded after main.css, so these rules win). */
/* The way in sits beside the wordmark on every page. redoal.com is read
and answered without an account, so the invitation is not shown.
Whoever edits the site still signs in at /auth/login directly, and
once signed in the nav keeps its name and its way out. */
.session:has(a[href^="/auth/login"]) {
display: none;
}
/* Without :has(), the link alone goes and the empty nav stays. */
.session a[href^="/auth/login"] {
display: none;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

-99
View File
@@ -1,99 +0,0 @@
id: /advantages
name: What is it good for?
description: >
The same one trick — a drawing is an address — answers different
needs. Here's what redoal gives you, grouped by what you're trying to
do. None of it needs an account, a server that owns your words, or a
platform's permission.
alternatives:
- name: A community keeping its own memory
description: >
No company holds the recordings. The people who show up are the
infrastructure, and the network is built so their memory survives
them.
features:
- name: No server owns the words
description: >
Recordings live on the phones of the people who visit a
place, handed peer to peer. There is no central store to
seize, subpoena, or switch off — the memory is only ever
where its people are.
icon: lucide:server-off
- name: Attention is what preserves
description: >
Every time someone listens, their phone keeps a copy and
quietly becomes another place you can get it from. A voice
heard by many is, by that fact alone, held by many. The more
a thing is cared about, the harder it is to lose.
icon: lucide:ear
- name: The infrastructure points the right way
description: >
When a relay helps, it points visitors toward each other — it
never becomes the place the words live. The fewer servers it
takes to keep a voice reachable, the more the network is
doing what it was built to do.
icon: lucide:git-fork
- name: An artist placing work where it's found
description: >
Leave something at a shape, and it belongs to that shape — found
by feel, answered in kind, and not quietly unsaid later.
features:
- name: The drawing is the address
description: >
Your line becomes a twenty-byte fingerprint that reconstructs
back into the shape you drew. Similar drawings land at the
same place, so work is found by gesture, not by a name in a
directory.
icon: lucide:pen-tool
- name: A place holds voices, and answers
description: >
Leave a short recording at a shape; anyone who arrives hears
it, and can answer — not only with their own voice, but with
a drawn gesture that points somewhere, a reply in the same
wordless language.
icon: lucide:radio
- name: What's left is kept
description: >
A voice left at a place isn't retracted out from under the
people who heard it. The record is forward-only — you build
on it, you don't erase it.
icon: lucide:history
- name: Anyone tired of accounts and platforms
description: >
A network you carry in your hand, that asks nothing of you before
you use it.
features:
- name: Nothing to sign up for
description: >
No account, no profile, no directory of you. You draw, you
arrive, you're part of it — the gesture is the only
credential, and it's yours the moment your hand lifts.
icon: lucide:user-x
- name: Sovereign by construction
description: >
The parts that keep it running are ones you can run yourself —
no dependence on a big platform's servers to find each other
or move a recording. The whole design leans toward fewer
rented middlemen, not more.
icon: lucide:shield-check
- name: Leaving costs nothing
description: >
Your phone reclaims space on its own, and letting go of a
recording never deletes it from the world — the network
fetches it back the next time someone arrives wanting it. You
can travel light and still be a full member.
icon: lucide:feather
- name: Go deeper on how it remembers
description: >
The preservation model has a twist worth seeing on its own: your
phone protects what's *rare*.
action: /advantages/memory
consequence: [Show me how the memory works]
features:
- name: Memory that protects what's rare
description: >
Your phone can't hold everything, so it keeps the voices few
others do — releasing the ones already safe on many devices,
holding the ones in danger of vanishing. The network
preserves itself without anyone deciding what survives.
icon: lucide:gem
-46
View File
@@ -1,46 +0,0 @@
id: /advantages/memory
name: How redoal remembers
description: >
A place's voices should stay reachable as long as people care about
them, and no longer — and no phone should fill up preserving voices
nobody returns to. redoal gets there with three forces that need no
coordinator: attention spreads a voice, scarcity keeps it, and the
person who spoke it is the anchor of last resort.
alternatives:
- name: The three forces
description: >
No server decides what survives. The incentives do — and they
pull in exactly the right directions.
features:
- name: Attention replicates
description: >
Every time someone listens to a recording, their phone keeps
a copy and quietly announces itself as another place you can
get it from. A voice heard by a hundred people is, by that
fact alone, held by a hundred phones. Listening is hosting.
icon: lucide:ear
- name: Scarcity is kept
description: >
When a phone runs low on room, it doesn't drop the oldest
voice — it drops the safest one. The network already knows
how many phones hold each recording, so each device keeps the
ones held by almost no one and lets go of the ones held by
many. Everyone reaching for the rare voice is exactly what
protects it.
icon: lucide:gem
- name: The speaker anchors
description: >
Whoever left a recording never forgets their own — a place's
origin is always reachable through the person who made it.
Below everything else, the author is the backstop, so no
voice falls all the way out of the world while its speaker
still carries a phone.
icon: lucide:anchor
- name: Letting go is safe
description: >
A phone releasing a voice isn't deleting it — the drawing
still leads there, and the network fetches it back on demand
the next time someone arrives wanting it. Reclaiming space
and preserving memory are separate, which is what lets a
small phone be a full member without fear.
icon: lucide:recycle
+21 -14
View File
@@ -1,17 +1,28 @@
# The group exhibition at Podium, part of Attac's «Big Tech må vekk» # «Atelic Antics», the group exhibition at Podium, part of Attac's
# 2026: opens 23 October 2026 at 19:00 and runs for a month. Announced # «Big Tech må vekk» 2026: opens 23 October 2026 at 19:00 and runs for a month. Announced
# in every header while it runs (portal's event: window); afterwards a # in every header while it runs (portal's event: window); afterwards a
# followup, and a "post what happened" task lands on /review. # followup, and a "post what happened" task lands on /review.
name: Where can you see it in person? name: Where can you see it in person?
description: > description: >
redoal is part of the group exhibition at Podium, opening 23 October redoal is part of «Atelic Antics», the group exhibition at Podium,
and running for a month — the art strand of the conference opening 23 October and running for a month — the art strand of the
«Big Tech må vekk». Draw on the screens, leave a voice at a shape, conference «Big Tech må vekk». Draw on the screens, leave a voice at a shape,
hear who came before you. hear who came before you.
event: event:
starts: 2026-10-23T19:00:00+02:00 starts: 2026-10-23T19:00:00+02:00
duration: 31d # To 15 November, per the poster — not a month. The header announces
# this while it runs, so a duration that overshoots keeps inviting
# people to a closed room.
duration: 23d
place: Podium, Hausmanns gate 34, Oslo place: Podium, Hausmanns gate 34, Oslo
slideshow:
slides:
- image: images/atelic-antics.webp
caption: >
«Atelic Antics» — suggestions on digital resistance. Podium,
Hausmanns gate 34, 24 October to 15 November 2026.
width: 989
height: 1400
alternatives: alternatives:
- name: Come draw on the wall - name: Come draw on the wall
description: > description: >
@@ -21,9 +32,10 @@ alternatives:
features: features:
- name: Opening 23 October, 19:00 - name: Opening 23 October, 19:00
description: > description: >
At [Podium](https://podium.enterprises/), Hausmanns gate 34, «Atelic Antics» opens at [Podium](https://podium.enterprises/),
and up for a month. Come to the opening, or any Saturday Hausmanns gate 34, and is up until 15 November. Come to the
or Sunday after. opening, or any Saturday or Sunday after between 13:00 and
17:00.
icon: lucide:calendar-days icon: lucide:calendar-days
- name: Part of «Big Tech må vekk» - name: Part of «Big Tech må vekk»
description: > description: >
@@ -38,8 +50,3 @@ alternatives:
Listen to the voices left there, add your own, and watch Listen to the voices left there, add your own, and watch
your line find the lines drawn before it. your line find the lines drawn before it.
icon: lucide:hand icon: lucide:hand
- name: Take the zine with you
description: >
The printed zine sits in the room — six short pieces on what
a network like this could mean. Fold one, hand it on.
icon: lucide:book-open
+23 -28
View File
@@ -52,10 +52,12 @@ alternatives:
public: true public: true
# /pulse (redoal ADR-0023) returns { voices_echoed: N }; shape # /pulse (redoal ADR-0023) returns { voices_echoed: N }; shape
# it into one card — the number as the heading, the phrase # it into one card — the number as the heading, the phrase
# beneath. The card renders unlinked when the relay is quiet. # beneath. Emit a bare object, not a wrapped [ … ]: the portal
# collects the jq output stream into an array itself, so a
# wrapping [ ] nests it ([[{…}]]) and drops to a raw JSON dump.
jq: > jq: >
[{ "name": (.voices_echoed | tostring), { "name": (.voices_echoed | tostring),
"description": "voices echoed so far" }] "description": "voices echoed so far" }
empty: The first voice hasn't echoed yet. empty: The first voice hasn't echoed yet.
- name: A drawing is an address - name: A drawing is an address
description: > description: >
@@ -117,7 +119,8 @@ alternatives:
- name: Follow the build as it lands - name: Follow the build as it lands
description: > description: >
The network as it is being built — and we need collaborators on The network as it is being built — and we need collaborators on
every new surface it grows. every new surface it grows. Desktop releases run free; the iPhone
beta is one tap away below.
features: features:
- name: Communicate - name: Communicate
description: > description: >
@@ -129,34 +132,25 @@ alternatives:
description: Start exploring by running one of our applications. description: Start exploring by running one of our applications.
icon: lucide:package icon: lucide:package
resource: resource:
# The public manifest redoal's release job writes to
# dl.redoal.com (the repo is private; its own release assets
# 404 for visitors). Portal renders a manifest of this shape as
# one download card: the newest version, this device's file
# first, the Arch repo lines and TestFlight folded with the
# rest (content-reference, "A releases manifest").
source: source:
kind: gitea_releases kind: url
owner: redoal url: https://dl.redoal.com/releases.json
repo: redoal
public: true public: true
empty: Nothing released yet — the first cut lands here. empty: Nothing released yet — the first cut lands here.
# url pinned to null while the repo is private - a private - name: Test the iPhone app
# release's html_url 404s for anonymous visitors, and the
# card renders an unlinked heading instead (same lesson as
# uhhm/questions 9b7162f).
jq: >
.[] | {name: .name, description: .body, tag: .tag_name,
published: .published_at, url: null}
- name: See what it's good for
description: >
The same one trick answers different needs — a community keeping
its own memory, an artist placing work where it's found, anyone
done with accounts and platforms.
action: /advantages
consequence: [Show me the advantages]
features:
- name: Grouped by what you're after
description: > description: >
Not a feature list — the advantages sorted by the thing The desktop releases above run free, no sign-up. The iPhone
you're trying to do, including the one worth seeing on its build rides TestFlight (Apple's beta program) — [join the
own: how your phone protects what's rare. redoal testers](https://testflight.apple.com/join/eR9dvHkz)
icon: lucide:sparkles with one tap on your iPhone; no invitation, no email, no
waiting on us.
icon: lucide:smartphone
- name: Hear from us when it matters - name: Hear from us when it matters
description: > description: >
@@ -179,3 +173,4 @@ alternatives:
- name: email - name: email
label: Email label: Email
type: email type: email
+30
View File
@@ -0,0 +1,30 @@
id: /joined-testers
route: ^/joined-testers
followup: true
name: What happens next?
description: >
You asked for a place in the closed beta — here's the shape of it.
alternatives:
- name: Your invite is on its way
description: ""
features:
- name: Check your mail
description: >
A TestFlight invite goes to the Apple ID you left. Tap it on
your iPhone, install TestFlight if you don't have it, and
redoal lands on your home screen.
icon: lucide:mail
- name: It's rough on purpose
description: >
A beta, and an artwork before a product — the networked edges
are where the interesting questions live. Tell us what breaks.
icon: lucide:hammer
- name: Withdraw from the beta
description: >
Changed your mind? Confirm below and we'll drop your Apple ID from
the invite list.
self_transition:
bucket: redoal_testers
to: withdrawn
label: Remove me from the beta
+1
View File
@@ -5,3 +5,4 @@ hero:
kind: module kind: module
module: hero.js # this repo's sine-swings piece, served at /site/hero.js module: hero.js # this repo's sine-swings piece, served at /site/hero.js
wordmark_invert: true wordmark_invert: true
stylesheet: custom.css