Case study — community engagement

One invitation at a time.
Often, none at all.

MyLimb is a community platform for the international limb-loss community — patients, families and the clinicians around them. Its engagement layer decides who to reach, with what, and how often. Most of the time it decides to say nothing.

Designed and built for MyLimb · the topic layer, the participation signals and the promise watchdog run in production · the invitation card is built and dark · the For You feed is specified

Research Three concepts One built Four review rounds before merge

The ceiling: one card in a week of daysMTWTFSSONE CARDAT MOST ONE A DAY · THREE A WEEKONE A WEEK ON “FEWER” · OFF MEANS OFF
Notice.Decide.Invite once.Stay quiet.
01 — The tension

Engagement here cannot be growth-hacking.

The member who has gone quiet is the hardest person a community serves. A platform that says nothing loses them; one that keeps prompting loses them faster — and here the second failure is the worse one, because every hollow notification teaches a member that the place built to understand them is chasing its numbers like everything else.

So the design began in the peer-support research rather than in a growth playbook, and it began by ruling things out. What survived is a single question, asked afresh each time a member opens the app: is reaching out worth it right now, or is silence the better move?

02 — What the member meets

A layer that can name its reasons.

The engagement layer reads only what members do in the open — the posts they write, the replies they give, the interests they name on their first day. It never watches them read.

What it is allowed to offer is deliberately small: one invitation at a time and never a stack, a dial the member owns, and a feed in which every card carries the signal that put it there.

The member’s surfaces — three moments
01 · The invitation
02 · The dial
03 · For You
Three surfaces, drawn — (01) The card is pull-only: it exists because a member opened the feed, and nothing about it ever pushes. Accepting deep-links to the real post or composer; declining is one tap with no reasons asked, and it rests that kind of ask rather than that person. (02) The dial is a member setting, not a budget the product spends — and “Off” is honoured with no confirmation ask and no copy that argues back. (03) Every For You card carries a machine-readable reason and its plain-language label, so the feed cannot place a card it cannot explain; the magazine lane is woven in rather than ranked, a fill card from the newest posts is never dressed up as personal, and no two cards in a row may carry the same reason.

Most days the right number of cards is zero.

Five shapes · one live card · never the same ask twice

03 — How it decides

The model supplies words. Code decides who gets asked.

Who to reach, with what, how often — every decision a member can feel is made by code that can be read, tested and argued with. The model’s whole job is to say what a post is about, in a vocabulary it did not write.

The vocabulary: retrieval decides what the model may considerTHE VOCABULARYWHAT SOMEONE WROTECHUNKED · EMBEDDED125 CURATED LIMB-LOSS TOPICS · TEN CATEGORIESFORTY CANDIDATES · THE MODEL SEES NO OTHERSConfirma slug from that lista confidence, a quoted lineTEMPERATURE 0 · ONE SCHEMAACCEPTED ≥ 0.70FEEDS THE SIGNALSNEEDS REVIEW ≥ 0.40WAITS FOR A PERSONREJECTEDAUDIT ONLYEVERY RUN COSTED IN TOKENS · AN UNCHANGED POST NEVER RE-RUNSNEEDS-REVIEW ROWS FEED NOTHING UNTIL A PERSON ACCEPTS The vocabulary: retrieval decides what the model may considerTHE VOCABULARYWHAT SOMEONE WROTE125 TOPICS · RETRIEVAL SHORTLISTS 40THE MODEL SEES NO OTHERSConfirmonly the slugs it was givena confidence, a quoted lineTEMPERATURE 0 · ONE SCHEMAACCEPTED ≥ 0.70 · FEEDS SIGNALSNEEDS REVIEW ≥ 0.40WAITS FOR A PERSONREJECTED · AUDIT ONLYEVERY RUN COSTED IN TOKENS
The vocabulary — A published post is chunked, embedded and matched against a curated catalogue of 125 limb-loss topics. Hybrid retrieval shortlists forty candidates and the prompt closes the world to that list, so an invented topic is not discouraged — it is unreachable. What comes back is a slug the model was handed, a confidence and a short quoted line of evidence. Two thresholds then split the result three ways, and the middle one is the interesting one: a topic the model is only fairly sure of is stored, shown to an administrator, and excluded from every downstream signal until a person accepts it. The system would rather know less than be confidently wrong.

The dial

the member’s own setting, read first
The dial: the member's setting is the first thing read, and Off ends the passREAD BEFORE ANYTHING IS COMPUTEDNormalat most one at a timeFewerat most one a weekOffwe won’t ask againON TO THE NEXT GATENOTHING RETURNEDNO CONFIRMATION ASK, NO ARGUING BACKA MEMBER SETTING · CHANGED AT ANY TIME“FEWER” EXPIRES A CARD RATHER THAN DECLINING IT — IT TEACHES NOTHINGNOTHING IS COMPUTED FOR A MEMBER WHO SAID NO The dial: the member's setting is the first thing read, and Off ends the passREAD FIRSTNormalat most one at a timeFewerat most one a weekOffwe won’t ask againOFF — NOTHING RETURNEDNO CONFIRMATION ASKNORMAL AND FEWER GO ON TO THENEXT GATE“FEWER” EXPIRES A CARD RATHERTHAN DECLINING IT

The live card

one at a time, re-checked rather than replaced
The live card: a stack is not a policy here, it is a constraintONE LIVE CARD AT A TIMELIVEAnswer a questionasked three days agostill unansweredMINTED YESTERDAY · STILL STANDINGONE LIVE CARD PER MEMBER · A UNIQUE INDEXA SECOND CARDA THIRDNOT MINTED WHILE ONE STANDS — THE DATABASE REFUSESThe premise, re-checkedstill visiblestill unanswered by anyone elseless than five days oldTHE SAME PREDICATE, USED IN FIVE PLACESSHOWN AGAINRETIRES QUIETLYUNCHANGED · THE PASS STOPS HEREAGED OUT, OR THE MOMENT PASSEDNOTHING IS PUSHED — THE CARD EXISTS BECAUSE THE FEED WAS OPENED The live card: a stack is not a policy here, it is a constraintONE LIVE CARDLIVEAnswer a questionasked three days agostill unansweredONE PER MEMBER · A UNIQUE INDEXThe premise, re-checkedstill visiblestill unanswered by anyone elseless than five days oldTHE SAME PREDICATE IN FIVE PLACESSHOWN AGAINUNCHANGEDRETIRESQUIETLYNOT MINTED WHILE ONE STANDSNOTHING IS PUSHED — THE FEED WAS OPENED

The budget

twelve hours, then one a day and three a week
The budget: spent is spent, whatever is waitingTHE BUDGETA MEMBER JOINSFIRST 12 HAT MOST ONE A DAYD1D2D3D4D5D6D7NOTHING IS OFFERED IN THE FIRST TWELVE HOURSTHE WEEK’S BUDGETSPENT — NOTHING TODAYTHREE A WEEK · ONE A WEEK ON “FEWER”NO CANDIDATE IS GOOD ENOUGH TO OVERSPEND ITTHE FIRST ASK COMES NO EARLIER THAN TWELVE HOURS AFTER JOININGTHE CAPS ARE MAXIMA — THEY ARE NOT QUOTAS TO FILL The budget: spent is spent, whatever is waitingTHE BUDGETNOTHING IN THE FIRST 12 HOURSAT MOST ONE A DAYD1D2D3D4D5D6D7THE WEEK’S BUDGETTHREE A WEEK · ONE ON “FEWER”SPENT — NOTHING TODAYNO CANDIDATE IS GOOD ENOUGH TOOVERSPEND THE BUDGETTHE FIRST ASK COMES NO EARLIERTHAN TWELVE HOURS AFTER JOINING

Five shapes

a fixed order, and the order is the whole ranking
Five shapes: the order is the entire ranking, and the walk can end in nothingFIVE SHAPES, WALKED IN ORDERCLINICIANS WALK A SHORTER POOL — ONLY EVER ASKED TO GIVEFIXED PRIORITY · THE ORDER IS THE RANKINGWelcome a newcomeran introduction under three days old, still unansweredRESTING · SKIPPEDAnswer a questiona question under seven days old, still unansweredIntroduce yourselfif you never haveRead a storya post on a topic you named on day oneAsk somethingthe evergreen floor — always thereNOT REACHEDONE CARD, MINTEDDECLINED → THE SHAPE RESTS14 D SOCIAL · 7 D EVERGREEN30 D ON A REPEATEVERY SHAPE RESTING OR EMPTY — NOTHING IS OFFEREDA PERSON IS NEVER OFFERED AS A TARGET TWICEENFORCED BY THE DATABASE, NOT BY CONVENTION Five shapes: the order is the entire ranking, and the walk can end in nothingFIVE SHAPES, IN ORDERWelcome a newcomeran intro under three days oldRESTINGAnswer a questiona question under seven days oldIntroduce yourselfif you never haveRead a storya post on a topic you namedAsk somethingthe evergreen floorNOTHING FITSONE CARD, MINTEDTHE ORDER IS THE ENTIRE RANKINGDECLINED → THE SHAPE RESTS 14 / 7 / 30 DA TARGET IS NEVER OFFERED TWICECLINICIANS WALK A SHORTER POOL

The dial, the live card, the budget, the shapes — in that order, and no other. The dial — the member’s own setting, read first. Off returns nothing, silently. The live card — re-checked, not replaced. One at a time is a constraint, not a policy. The budget — twelve hours, then one a day and three a week. Spent is spent. Five shapes — walked in a fixed order, and that order is the entire ranking. Tomorrow it runs again — against caps that have moved on and shapes that may be resting.

Three of the four gates can end the pass in silence — only the last one mints a card

One pass, gate by gate — (01) The dial is read before anything is computed, so a member who said no costs nothing to serve. (02) A card already standing is re-checked rather than replaced — still visible, still unanswered, less than five days old — and one live card per member is a database constraint. (03) The budget is absolute: nothing in the first twelve hours, then at most one a day and three a week, one a week on “Fewer”. (04) The five shapes are walked in a fixed order and that order is the entire ranking — no scores, no optimiser, no model. A resting shape is skipped, and declining rests the shape rather than the person, so a decline teaches the system without costing the member anything. Clinicians are walked through a shorter pool: they are only ever asked to give.

04 — The safety margin

Nothing sent from memory. Nothing welcomed by a bot.

Restraint is a promise, and a promise needs infrastructure behind it. The one thing this system does push is an alert to staff — and it is written down before it is sent, so an outage can delay it but cannot drop it and cannot repeat it.

The warmest moment is the one deliberately left to people. When a newcomer’s first hello is still unanswered near the end of the day the community promised it, the platform does not post a reply. It emails the crew.

The promise watchdog: written down before it is sent, and handed to a personONE FIRST POST, HOUR BY HOURH+0A first helloposted in IntroductionsTHEIR FIRST PUBLIC POST“INTROS GET ANSWERED WITHIN A DAY.”THE PROMISE, MADE AT SIGN-UPAN HOURLY SWEEP · PRODUCTION ONLY20–24 HSTILL UNANSWERED BY ANYONE ELSEQUESTIONS GET 40–48 HTHE WINDOWS SIT INSIDE THE PROMISE —A PERSON STILL HAS HOURS TO ACTWRITTEN DOWN BEFORE IT IS SENTOne row per postsubject, body, idempotency keyfrozen at detectionEVER — ENFORCED BY THE DATABASEANSWERED SINCE?THE ROW CLOSESEVERY RETRYBYTE-IDENTICALAN EMAIL TO THE CREWA PERSON DOES THE WELCOMINGDETECTION ONLYTHE ENGINE NEVER POSTS, EMAILS OR PUSHES TO A MEMBER The promise watchdog: written down before it is sent, and handed to a personHOUR BY HOURA first helloposted in IntroductionsTHEIR FIRST PUBLIC POST“INTROS GET ANSWERED WITHIN A DAY”THE PROMISE, MADE AT SIGN-UP20–24 HAN HOURLY SWEEP · PRODUCTION ONLYSTILL UNANSWERED BY ANYONE ELSEQUESTIONS GET 40–48 HWRITTEN DOWN BEFORE IT IS SENTOne row per postsubject, body, idempotency keyfrozen at detectionEVER — ENFORCED BY THE DATABASEANSWERED SINCE?THE ROW CLOSESEVERY RETRYBYTE-IDENTICALAN EMAIL TO THE CREWA PERSON DOES THE WELCOMINGDETECTION ONLY — NOTHING GOES TO A MEMBER
One first post, hour by hour — The sweep runs hourly in production and looks only at an author’s first public post: an introduction between twenty and twenty-four hours old, a question between forty and forty-eight, and still unanswered by anyone but its author. The windows sit inside the promise on purpose, so a person still has hours to act. Detection writes one ledger row per post, ever, with the subject, the body and the idempotency key frozen at that moment — the fix that came out of a real incident, where a payload recomputed per attempt made two retries different enough to be rejected once and duplicated later. At delivery the premise is checked one last time; if the post has been answered in the meantime, the row closes and nobody is emailed.
05 — What this proves

Engagement, engineered as restraint.

The discipline here is structural rather than aspirational. One live card is a unique index. The permanent no-repeat is a unique index. The dial is read before the work is done rather than after it. The selector and the feed can each name the reason for anything they show — and the only thing the whole system pushes is an email asking a person to go and be one.

We designed an engagement system, read the research, and removed the model from the decision. No scores. No ranking. No model call anywhere in the selector.

Stack — Rails · Postgres + pgvector · SvelteKit · OpenAI — every model call a background job, none in a member’s request path

Let's find the work AI should be doing in your organization.

Whether you are exploring an idea or improving a system already in use, we’ll help you decide what is worth doing next.

Prefer to start async?

hello@thoughtfulrobots.ai

Hyderabad · Remote

Questions before you book?

Read the FAQ

Follow along

START A CONVERSATION

Tell us about the work.

A few lines about your product and where AI might belong. We usually reply within one business day.