Cross-cutting "teams" concept: targeted tasks, scoped budgets, and shared rosters #55

Open
opened 2026-05-13 09:51:09 +00:00 by padreug · 0 comments
Owner

Context

Several modules already implicitly want a notion of "team" but each handles it differently or not at all:

  • tasks (aiolabs/tasks) — recurring chores naturally cluster by audience: "animal-chores" (paca/duck/puppy feeding, training), "farmers" (planting, harvesting), "kitchen", etc. Today the tasks module only supports per-pubkey participants (NIP-52 p tags) and freeform t category tags. There's no way to publish a task to "the animal-chores team" without enumerating every member's pubkey at create time.
  • libra (aiolabs/libra) — a team could plausibly own a budget envelope. Today there's no way to associate libra accounts/categories with a roster.
  • events / activities — community activities sometimes target a subset of members (volunteer crews, organizers). Currently public + open-RSVP.
  • forum — already on its way to NIP-72 communities (#31). Teams may or may not be the same primitive.

This issue collects possible avenues so we can pick one before scattering team-shaped logic across modules.

What we already have

  • NIP-52 p tags on tasks (per-pubkey participants with optional role).
  • NIP-12 t tags on tasks and events (freeform categories / hashtags).
  • LNbits accounts each carry a Nostr pubkey, so we have a stable identity per user.

Possible avenues

A. Tag convention (lightest)

  • Teams are just t tag strings: ["t", "animal-chores"], ["t", "farmers"].
  • Each user maintains a NIP-51 follow set (kind 30000 or kind 10000) listing the team tags they're subscribed to.
  • Clients filter their feeds by intersection.
  • Pros: zero new event kinds; works across modules instantly (libra could subscribe to the same tag list to scope a budget view); compatible with arbitrary Nostr clients.
  • Cons: no membership truth — anyone can self-claim a team; no admin/eject; tags are flat (no hierarchy).

B. NIP-51 lists as the team object (medium)

  • Each team is a kind 30000 follow set published by a team admin, with the team's d-tag as a stable identifier (e.g. team:animal-chores).
  • Tasks/budgets/events reference the team by a tag (30000:admin-pubkey:team:animal-chores).
  • Members read the list to know what they belong to; admin controls roster.
  • Pros: real membership truth; trivial admin (re-publish the list); standard NIP-51.
  • Cons: single admin / centralization per team; replaceable so all-or-nothing roster updates; clients must resolve the team address before filtering.

C. NIP-29 relay-enforced groups (heaviest)

  • Each team is a group on a NIP-29 relay; events scoped to the group's h tag.
  • Relay enforces membership at the protocol level — non-members can't read or post.
  • Pros: real access control; private team channels for free; aligns with where forum's headed if we go NIP-72-ish later.
  • Cons: need a NIP-29-aware relay (we don't run one yet); much bigger lift across every module; couples module behavior to a specific relay.

D. NIP-72 communities (forum-shaped)

  • Already on the table for forum (#31). Community kind 34550 + approval kind 4550.
  • Tasks/libra could ride the same community as a "post type."
  • Pros: one primitive across modules; matches forum's direction.
  • Cons: semantically a stretch — "approved post in community" isn't really how a chore assignment works; relays don't enforce membership for non-forum kinds.

Recommendation (to be debated)

Start with A. tag conventions because nothing needs to change server-side and it works today, then layer B. NIP-51 lists on top once we need real rosters (admin add/remove, "you're now on the animal-chores team"). C/D are only worth it if we hit a concrete access-control requirement that A+B can't meet.

Cross-module surface

If we commit to A or B:

  • tasks: filter the feed by subscribed team tags; "post to team" picker in create dialog. See aiolabs/tasks#1.
  • libra: optional team tag on budget envelopes; team view aggregates. See aiolabs/libra#X (TBD).
  • base auth / profile: a "your teams" preferences pane that maintains the user's NIP-51 follow set.
  • activities / events: optional team scoping for community-internal events (related to #34 public-vs-private).
  • #25 disambiguate task vs activity on shared relays — teams compound this; we'll need consistent t-tag conventions across modules.
  • #34 operator-configurable public-vs-private mode — team scoping is a finer-grained version of the same axis.
  • #31 forum: NIP-72 communities — overlapping primitive (option D).
  • #28 shared auth across standalone app modules — team subscriptions belong wherever shared auth lives.
## Context Several modules already implicitly want a notion of "team" but each handles it differently or not at all: - **tasks** ([aiolabs/tasks](https://git.atitlan.io/aiolabs/tasks)) — recurring chores naturally cluster by audience: "animal-chores" (paca/duck/puppy feeding, training), "farmers" (planting, harvesting), "kitchen", etc. Today the tasks module only supports per-pubkey `participants` (NIP-52 `p` tags) and freeform `t` category tags. There's no way to publish a task to "the animal-chores team" without enumerating every member's pubkey at create time. - **libra** ([aiolabs/libra](https://git.atitlan.io/aiolabs/libra)) — a team could plausibly own a budget envelope. Today there's no way to associate libra accounts/categories with a roster. - **events / activities** — community activities sometimes target a subset of members (volunteer crews, organizers). Currently public + open-RSVP. - **forum** — already on its way to NIP-72 communities (#31). Teams may or may not be the same primitive. This issue collects possible avenues so we can pick *one* before scattering team-shaped logic across modules. ## What we already have - NIP-52 `p` tags on tasks (per-pubkey participants with optional role). - NIP-12 `t` tags on tasks and events (freeform categories / hashtags). - LNbits accounts each carry a Nostr pubkey, so we have a stable identity per user. ## Possible avenues ### A. Tag convention (lightest) - Teams are just `t` tag strings: `["t", "animal-chores"]`, `["t", "farmers"]`. - Each user maintains a NIP-51 follow set (kind 30000 or kind 10000) listing the team tags they're subscribed to. - Clients filter their feeds by intersection. - **Pros:** zero new event kinds; works across modules instantly (libra could subscribe to the same tag list to scope a budget view); compatible with arbitrary Nostr clients. - **Cons:** no membership *truth* — anyone can self-claim a team; no admin/eject; tags are flat (no hierarchy). ### B. NIP-51 lists as the team object (medium) - Each team is a kind 30000 follow set published by a team admin, with the team's d-tag as a stable identifier (e.g. `team:animal-chores`). - Tasks/budgets/events reference the team by `a` tag (`30000:admin-pubkey:team:animal-chores`). - Members read the list to know what they belong to; admin controls roster. - **Pros:** real membership truth; trivial admin (re-publish the list); standard NIP-51. - **Cons:** single admin / centralization per team; replaceable so all-or-nothing roster updates; clients must resolve the team address before filtering. ### C. NIP-29 relay-enforced groups (heaviest) - Each team is a group on a NIP-29 relay; events scoped to the group's `h` tag. - Relay enforces membership at the protocol level — non-members can't read or post. - **Pros:** real access control; private team channels for free; aligns with where forum's headed if we go NIP-72-ish later. - **Cons:** need a NIP-29-aware relay (we don't run one yet); much bigger lift across every module; couples module behavior to a specific relay. ### D. NIP-72 communities (forum-shaped) - Already on the table for forum (#31). Community kind 34550 + approval kind 4550. - Tasks/libra could ride the same community as a "post type." - **Pros:** one primitive across modules; matches forum's direction. - **Cons:** semantically a stretch — "approved post in community" isn't really how a chore assignment works; relays don't enforce membership for non-forum kinds. ## Recommendation (to be debated) Start with **A. tag conventions** because nothing needs to change server-side and it works today, then layer **B. NIP-51 lists** on top once we need real rosters (admin add/remove, "you're now on the animal-chores team"). C/D are only worth it if we hit a concrete access-control requirement that A+B can't meet. ## Cross-module surface If we commit to A or B: - **tasks**: filter the feed by subscribed team tags; "post to team" picker in create dialog. See [aiolabs/tasks#1](https://git.atitlan.io/aiolabs/tasks/issues/1). - **libra**: optional team tag on budget envelopes; team view aggregates. See [aiolabs/libra#X](https://git.atitlan.io/aiolabs/libra) (TBD). - **base auth / profile**: a "your teams" preferences pane that maintains the user's NIP-51 follow set. - **activities / events**: optional team scoping for community-internal events (related to #34 public-vs-private). ## Related - #25 disambiguate task vs activity on shared relays — teams compound this; we'll need consistent `t`-tag conventions across modules. - #34 operator-configurable public-vs-private mode — team scoping is a finer-grained version of the same axis. - #31 forum: NIP-72 communities — overlapping primitive (option D). - #28 shared auth across standalone app modules — team subscriptions belong wherever shared auth lives.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/webapp#55
No description provided.