Skip to content

Kudos

Verified against v0.21.0 · internal/db/migrations/0033_kudos.sql, internal/db/migrations/0044_kudo_seen.sql, internal/db/migrations/0045_kudo_answers.sql, internal/store/kudos.go, internal/api/kudos.go, internal/standup/kudos.go, web/src/components/Kudos.tsx, web/src/components/AppShell.tsx, web/src/pages/SpacePage.tsx, web/src/pages/StandupRoom.tsx, web/src/pages/Landing.tsx, internal/store/spaces.go

A kudo is one sentence thanking a named person for something they did. It appears on the space’s kudos wall, newest first: beside the session list on a wide screen, and below it on a narrower one. Anyone who is a member of the space can give one, to anyone else who is a member of the same space, at any time — it needs no meeting open and no facilitator’s permission.

There are two places to write one. The wall itself has a form, folded under Thank someone so the wall reads first: pick a name from the roster, say what they did, send. Each member in the space’s sidebar has a Thank of their own, which opens the same form with their name already chosen. Two members who share a display name are told apart in the picker by the last four characters of their user id. And a daily standup offers the same form as its closing beat, once the round is done and everybody has just heard what everybody else was working on, which is the moment a team is most likely to mean it. A kudo given in a room is not a different kind of thing — it is the same row in the same table, and it lands on the space wall immediately, still carrying the session it was given in.

A kudo addressed to you is handed to you rather than listed: “Dana thanked you”, with the words set on a raised note. In the standup’s closing list the note is signed “— Dana” underneath, behind a brass edge and a light wash; on the wall the line above already names the sender, so the note is unsigned, and the edge is kept for a letter still waiting (below), so the one you have not read leads the ones you have. There is one note per kudo and nothing on it is counted. One you sent reads “You thanked Sam”. The wall shows the five newest kudos between other people and folds the rest behind Show all. One addressed to you is never folded and never counts toward the five, so putting a letter away never hides somebody else’s kudo. A guest is never handed a note, because a guest is never a recipient.

A kudo is capped at 280 characters. The form shows what is left once you are within 40 of the limit, and says why it will not send once you are over. It counts characters as a person reads them rather than as the browser stores them, so an emoji costs one. The server enforces the same limit and so does a database constraint, which means the number cannot quietly differ between the two surfaces.

Parley has no kudos count. Not per person, not per space, not per month. There is no total beside a name, no “most appreciated” list, and nothing anywhere that orders people by how many thank-yous they have collected.

This is the point of the feature, not a gap in it. The moment a number sits next to a name, the wall stops being a place people thank each other and starts being a thing they are measured by. Somebody notices they are on nine and their teammate is on fourteen. Somebody’s manager notices. From there, the kudos that keep being written are the ones that are worth writing, and the quiet honest ones — the ones from the person who says thank you twice a year and means it both times — are drowned out by volume.

So the constraint is built low, where a future redesign has to argue with it rather than route around it. The kudos table has no count column and there is no aggregate endpoint; the only read the store offers is “this space’s kudos, newest first”, a hundred at a time — and, for the recipient alone, which of those are still unread. The migration that creates the table says so in a comment, in as many words: adding a count column means arguing with that paragraph first. A UI rule can be relaxed in an afternoon by somebody who never heard the argument. A schema cannot.

The sender of a kudo can withdraw it, and the wall offers that only on your own. Nobody can edit one — not the sender, not the recipient, not an owner of the space. There is no edit endpoint to call.

Those two rules together are one decision. A kudo sent to the wrong person, or sent in a fit of sarcasm at four in the afternoon, should be retractable, and it is. But text that somebody has already read should never be rewritten underneath them: the thank-you you remember receiving must not turn into something else while you are not looking. Take it back or leave it as it stands.

Withdrawing is scoped to the sender at the server. Asking to delete somebody else’s kudo is refused, and asking for one that belongs to a different space answers as though it does not exist.

A kudo also outlives the people in it. One given to somebody who has since left the space stays on the wall, shown as being from or to “Someone who has left” — it is a record of something that happened, not an attribute of a current membership. It outlives the room, too: deleting the standup a kudo was given in leaves the kudo standing on the wall, for the same reason deleting a room does not retract the votes cast in it.

A kudo given on the wall while you are elsewhere is not left to chance. The next time you open the space, it is waiting above the wall under the words Waiting for you, as a letter: the sender’s words on a note, on the gold edge that only a waiting letter carries. It is found however long you have been away — a letter older than the wall’s first hundred rows still waits. It lands once; with reduced motion it simply appears. The letter on show stays until you put it away: one arriving while you read does not take its place.

Put it with the others marks it read. If its place on the wall — by date, so under anything newer — is on screen, the note slides down into it; if it is further down the page, the note is set down where it is and takes its place in the list without the page moving; with another letter waiting, it slides off the top of the pile and out of the slot, whole, uncovering the next. Either way, when another letter is waiting the label and the button stay exactly where they are and the next note is already underneath, and focus stays on the button. Holding the key down puts away one letter, not several. When it was the last, focus goes to the kudo in the wall. A letter arriving while a note is on its way is held back until the note has come to rest. Nothing about it is modal.

If the sender withdraws a letter while it waits, it is set down where it is and gone, rather than vanishing from under you: the next letter is uncovered, or when it was the last, focus goes to the wall’s heading. Putting away one that was withdrawn a moment ago does the same, without an error.

When more than one is waiting, the edge of one more sheet shows under the note. It looks the same for two as for thirty and carries no number — how many people thanked you is not a count the wall keeps. A screen reader hears “Another is waiting after this one”, also without a number.

Answering a kudo reads it, wherever the answer was written. Whether a kudo has been read is the recipient’s alone. The wall tells you which of yours are unread and tells nobody else anything: the sender never learns that their kudo was seen, and it is never aggregated or exported. A kudo already on the wall when Parley was upgraded to this version counts as read, so the upgrade does not deliver years of old letters at once.

The front page tells you too. A space holding an unread thank-you for you carries a slip of the same paper, with the letter’s gold edge, under its name in your list of spaces, and under the table you sat at last when it is that one: A thank-you is waiting. It is yes or no, never a number, reads the same for one sender as for several, and clears once you have put the last letter away or its sender withdraws it.

A guest link seats somebody in one room for a day and does not make them a member of the space. Guests neither send kudos nor receive them.

That follows from what a guest is. The instance deliberately does not remember them: the link expires, the seat goes away, and by morning there is nobody for a thank-you to be addressed to. A kudo pointing at an expired guest would be a name on a wall with nothing behind it. So the roster picker never offers a guest as a recipient, and the API refuses on both sides — the space’s kudos endpoints answer a guest’s cookie with a 401, and the standup’s kudo action carries its own membership check and answers a guest with a 403.

What a guest can do is read the closing beat of the standup they are sitting in. When the round is done and members start thanking each other, the kudos appear in the room for everybody connected to it, guest included, and the guest gets no form to give one. This is deliberate and worth stating plainly: a guest hears what is said in the room they were invited into, the same way they hear everything else said in it. They cannot read the space’s wall around it, which holds every kudo the team has ever given, and they never see one they were not in the room for.

CapabilityStatusWhat to do instead
Counts, totals or rankingsOut of scopeThe whole argument is above. There is no count column and no aggregate endpoint, by design.
Editing a kudoOut of scopeThe sender can withdraw one instead. Text somebody has already read is never rewritten underneath them.
Kudos to or from a guestOut of scopeA guest link is not a person the instance remembers, so a thank-you addressed to one would point at nobody by morning.
Kudos across spacesNot builtBoth people must hold a membership in the same space. A kudo belongs to the space it was given in.
Notifying the recipientBuilt inIn-app only: an unread kudo waits as a letter on the space page. Parley sends no email and no push.
Answering a kudoBuilt inThe recipient may write one line back, at most 80 characters, shown under the note as "Sam: …" to everyone who sees the kudo. One per kudo, so there is nothing to count; never edited, only withdrawn and written again, and withdrawing asks first. Nobody is prompted to answer, and a kudo without an answer looks like any other.
Reacting to a kudoNot builtNothing on a kudo is countable, and a reaction count is a count.

The wall reads back in pages of a hundred, with Show older for the rest, and a space may be given at most KUDO_LIMIT_PER_SPACE of them in any rolling 30 days — 500 by default. Older kudos stop counting, so storage is bounded per 30 days rather than for the space’s whole life. See Limits and defaults and Configuration.