2026-09-23 14:49:25 +02:00
# UHHM, uhhm.no: the studio that builds portal and carries redoal.
# Rebuilt from the live site (uhhm/questions) on 2026-09-23. The five
# buckets the site already holds keep their live state and event
# names (`events:`), so every record on the owners' desk stays where
# it is. Two are new: a business trying the trainer on its own
# workflow (`trials`, approved by a person before anything is built),
# and what reaches UHHM as the custodian of the redoal network
# (`custody_requests`, a desk of its own).
business : UHHM
language : en
contact : { name : Bendik Aagaard Lynghaug, email : bl@uhhm.no }
2026-09-23 21:18:14 +02:00
# Every mail the site sends comes from here (gdo on ergo delivers).
mail : { from : "UHHM <portal@uhhm.no>" , reply_to : bl@uhhm.no }
2026-09-23 14:49:25 +02:00
about : >
UHHM builds software around a clear argument: infrastructure, tools
and products for organizations that can say what problem they have.
It also builds and carries the redoal network - the gesture math,
the relay, the first node, and the portal this site runs on - and
answers for what that network keeps.
groups :
- { id : owners, label : Owners }
# The people who answer for the redoal network: they host its first
# node and relay, keep what is left there, and decide what stays.
- { id : custodians, label : redoal custodians, invited_by : [ owners] }
# Owners onboard into every desk; a custodian can vouch for another.
invites_by : [ owners]
2026-09-23 18:24:23 +02:00
# The front door opens modestly: one or two features, one role each,
# and no button, before the offers further down the same page. The
# two roles UHHM exists for: an organization with a problem, and the
# people on the redoal network it keeps.
does :
- id : software
for : commission
text : >
Software built around a clear argument. Infrastructure, tools
and products for organizations that can say what problem they
have - and a working draft of your own workflow as a site,
before you pay for anything.
- id : redoal
for : custody
text : >
The redoal network, built and carried here: the gesture math,
the relay, the first node, and the portal this site runs on.
UHHM answers for what that network keeps.
# Things to look at before asking for anything.
shows :
- id : built
text : A few things already out in the world.
resource :
public : true
source : { kind : gitea_starred, username : bl }
jq : >
.[] | {name: .name, description: .description,
url: (if .website != null and .website != "" then .website
elif .private then null
else .html_url end)}
- id : voices
text : Live from the redoal relay - what has been left at places so far.
resource :
public : true
source : { kind : url, url : https://relay.redoal.com/pulse }
jq : >
{ "name": (.voices_echoed | tostring),
"description": "voices echoed so far" }
empty : The first voice has not echoed yet.
2026-09-23 14:49:25 +02:00
needs :
- id : commission
who : an organization with a problem it wants software to solve
wants : a considered reply to a brief, from people who read the whole thing
lands_in : projects
handled_by : owners
stages : [ open, accepted, declined]
done_when : [ accepted, declined]
success : [ accepted]
events : { open : submitted }
2026-09-24 06:01:56 +02:00
stages_text : { open : "received" , accepted : "taken on" , declined : "not a fit for us" }
2026-09-23 18:24:23 +02:00
# The client plays too: they can withdraw the brief themselves.
moves_by : { declined : [ submitter, owners] }
2026-09-23 21:18:14 +02:00
mails : { open : submitter, accepted : submitter, declined : submitter }
2026-09-23 14:49:25 +02:00
max_fields : 4
collects :
- { name : name }
- { name : email, type : email }
- { name : project, type : textarea }
- { name : organization }
- { name : org_contact, optional : true }
# The client feature: the trainer tried on a real business. A person
# approves each intake before anything is built from it.
- id : trial
who : someone who runs a business where requests, approvals and handovers get lost, and wants to see it as a site before committing to anything
wants : a first draft of a site for their own roles, built from their own words and approved by a person first
lands_in : trials
handled_by : owners
stages : [ open, approved, previewed, declined]
done_when : [ previewed, declined]
success : [ previewed]
2026-09-24 06:01:56 +02:00
stages_text : { open : "received" , approved : "approved for a draft" , previewed : "a preview is ready" , declined : "not a fit for us" }
2026-09-23 21:18:14 +02:00
mails : { open : submitter, approved : submitter, previewed : submitter, declined : submitter }
2026-09-23 14:49:25 +02:00
attended_by : >
approved -> previewed: the n8n workflow that builds the draft
site from an approved intake (docker, rauthy, portal content)
and sends the preview link. Until it exists, owners run
portal-trainer by hand and press the button.
max_fields : 6
collects :
- { name : business }
- { name : email, type : email }
- { name : what_we_do, type : textarea }
- { name : who_comes_to_us, type : textarea }
- { name : what_we_keep_track_of, type : textarea }
- { name : who_is_involved, type : textarea }
- { name : what_slows_us_down, type : textarea, optional : true }
- id : collaborate
who : someone who wants to work with us on what we build
wants : to be read as a person, and invited in if there is a fit
lands_in : applicants
handled_by : owners
stages : [ open, invited, active, departed, declined]
done_when : [ departed, declined]
success : [ departed]
events : { open : applied, active : onboarded }
2026-09-24 06:01:56 +02:00
# Declined before starting; after that a person departs.
turned_down_from : [ open, invited]
stages_text : { open : "received" , invited : "invited in" , active : "working with us" , departed : "moved on" , declined : "not a fit for us" }
2026-09-23 14:49:25 +02:00
max_fields : 3
collects :
- { name : name }
- { name : email, type : email }
- { name : interest, type : textarea }
- { name : note, type : textarea, optional : true }
- id : subscribe
who : someone who wants to hear from us when there is something to say
wants : a note now and then, and an easy way out
lands_in : subscribers
handled_by : owners
stages : [ open, unsubscribed]
done_when : [ unsubscribed]
events : { open : subscribed }
2026-09-24 06:01:56 +02:00
stages_text : { open : "on the list" , unsubscribed : "off the list" }
2026-09-23 14:49:25 +02:00
moves_by : { unsubscribed : [ submitter, owners] }
max_fields : 2
collects :
- { name : name }
- { name : email, type : email }
# This site proposes its own changes through itself.
- id : propose
who : a visitor who sees how a page on this site should change
wants : the change read by a person and, if approved, made
lands_in : development_proposals
handled_by : owners
stages : [ open, approved, rejected]
done_when : [ approved, rejected]
success : [ approved]
events : { open : proposed }
2026-09-24 06:01:56 +02:00
stages_text : { open : "received" , approved : "approved" , rejected : "turned down" }
2026-09-23 14:49:25 +02:00
max_fields : 3
collects :
- { name : submitted_by }
- { name : email, type : email, optional : true }
- { name : page, optional : true }
- { name : rationale, type : textarea }
- { name : proposed_yaml, type : textarea }
# The custodian role, on the front door: UHHM answers for the redoal
# network it hosts. Owners see these too, and move nothing.
- id : custody
who : someone who runs, builds on, or is affected by the redoal network and needs the people who keep its first node
wants : an answer from a custodian, and action where the network keeps something it should not
lands_in : custody_requests
handled_by : custodians
watched_by : [ owners]
stages : [ open, in_dialogue, resolved, declined]
done_when : [ resolved, declined]
success : [ resolved]
2026-09-24 06:01:56 +02:00
stages_text : { open : "received" , in_dialogue : "in dialogue with a custodian" , resolved : "resolved" , declined : "closed without action" }
2026-09-23 18:24:23 +02:00
# The person affected says when it is resolved, not only the custodian.
moves_by : { resolved : [ submitter, custodians] }
2026-09-23 21:18:14 +02:00
mails : { open : submitter, resolved : submitter, declined : submitter }
2026-09-23 14:49:25 +02:00
max_fields : 4
collects :
- { name : name }
- { name : email, type : email }
- { name : about, type : select, options : [ Running a node of my own, Building on the network, Something the network keeps about me, Something else] }
- { name : what, type : textarea }
# Internal: a relationship worth tracking before it is a project.
- id : prospect
who : an owner who has met an organization worth following up
wants : it written down and walked through its states from the desk
enters_as : owners
lands_in : organizations
handled_by : owners
stages : [ prospect, client, past_client]
done_when : [ past_client]
skippable : [ client]
2026-09-24 06:01:56 +02:00
stages_text : { prospect : "a prospect" , client : "a client" , past_client : "a past client" }
2026-09-23 14:49:25 +02:00
events : { prospect : identified, client : became_client, past_client : churned }
max_fields : 2
collects :
- { name : name }
- { name : contact }
- { name : note, type : textarea, optional : true }
# Held out from every model that writes words. The first eight are the
# 2026-09-21 set (runs/uhhm-2026-09-21); the rest are for what is new.
personas :
- { id : architecture-firm, need : commission, text : "We run a small architecture firm and our project files are scattered across three cloud drives. We want to pay someone to set up proper storage and backups we control ourselves." }
- { id : climbing-gym-founder, need : commission, text : "I have an idea for a booking app for climbing gyms and I'm looking for a team that can build the first version with me." }
- { id : municipality-buyer, need : commission, text : "Our municipality needs an internal tool for tracking building permits. We are looking for a vendor who can scope it and deliver it." }
- { id : exhibition-visitor, need : subscribe, text : "I saw your drawing network at an exhibition and liked it. I don't want to get involved, I'd just like to know when there is news." }
- { id : tech-journalist, need : subscribe, text : "I write about Nordic technology. Keep me posted on what you release so I can cover it." }
- { id : rust-developer, need : collaborate, text : "I'm a Rust developer between jobs and I like that you build in the open. I would love to contribute, and maybe join you." }
- { id : interaction-designer, need : collaborate, text : "I'm an interaction designer. I want to work with you on the drawing interface." }
- { id : student-intern, need : collaborate, text : "I'm a computer science student looking for a summer internship doing infrastructure work." }
- { id : plumber-owner, need : trial, text : "I run a plumbing company with four vans. Jobs come in by phone and text and some get lost. I'd like to see how this would look for us before I spend any money." }
- { id : dance-school, need : trial, text : "We are a dance school. Enrolments, cancellations and invoices all go through one email inbox that only I understand. Can you show me a version made for us?" }
- { id : node-runner, need : custody, text : "I run a small server in Berlin and want to host a redoal node that peers with yours. Who do I talk to?" }
- { id : recorded-name, need : custody, text : "Someone left a recording on redoal that says my full name and where I live. I want it gone, and I want to know who is responsible for that network." }
- { id : app-builder, need : custody, text : "I'm building a music app and would like to use redoal's gesture addresses in it. Is that possible, and who decides?" }
- { id : wording-fix, need : propose, text : "The subscribe page should say how often you actually write. I'd like to suggest that exact change to the page." }
- { id : rewrite, need : propose, text : "One page on this site reads wrong to me and I know exactly how I'd rewrite it. Where do I send the new text?" }