···402402header on all outgoing requests. The header value is a comma-separated list of
403403labeler DIDs from the user's `labelersPref`. This should be set once on login
404404and updated whenever preferences change.
405405+406406+## Lists
407407+408408+Lists let users organise accounts into named collections. There are two
409409+user-facing list types: **curation lists** (curated feeds of member posts) and
410410+**moderation lists** (mute or block every member at once). A third type,
411411+**reference lists**, exists only as the backing store for starter packs.
412412+413413+### API
414414+415415+| Endpoint | Purpose |
416416+| --------------------------------------- | ---------------------------------------- |
417417+| `app.bsky.graph.getList` | Paginated list view with member profiles |
418418+| `app.bsky.graph.getLists` | Lists created by an actor |
419419+| `app.bsky.graph.getListsWithMembership` | User's lists with membership info |
420420+| `app.bsky.graph.getListMutes` | Mod lists the user has muted |
421421+| `app.bsky.graph.getListBlocks` | Mod lists the user is blocking |
422422+| `app.bsky.feed.getListFeed` | Feed of posts from list members |
423423+| `app.bsky.graph.muteActorList` | Mute all accounts on a list |
424424+| `app.bsky.graph.unmuteActorList` | Unmute a previously muted list |
425425+426426+List records, list items, and list blocks are managed through
427427+`com.atproto.repo.createRecord`, `putRecord`, and `deleteRecord` with the
428428+appropriate collection (`app.bsky.graph.list`, `app.bsky.graph.listitem`,
429429+`app.bsky.graph.listblock`).
430430+431431+### List Purposes
432432+433433+| Purpose | Constant | Usage |
434434+| --------------- | ----------------------------------- | --------------------------------------- |
435435+| Curation list | `app.bsky.graph.defs#curatelist` | User-curated, viewable as a feed |
436436+| Moderation list | `app.bsky.graph.defs#modlist` | Mute or block all members at once |
437437+| Reference list | `app.bsky.graph.defs#referencelist` | Internal backing list for starter packs |
438438+439439+### List Record
440440+441441+| Field | Type | Notes |
442442+| ------------------- | --------- | --------------------------------- |
443443+| `purpose` | string | One of the list purpose constants |
444444+| `name` | string | 1–64 graphemes |
445445+| `description` | string? | Max 300 graphemes / 3000 bytes |
446446+| `descriptionFacets` | facets[]? | Rich text facets for description |
447447+| `avatar` | blob? | PNG or JPEG, max 1 MB |
448448+| `createdAt` | datetime | Required |
449449+450450+### List Item Record
451451+452452+| Field | Type | Notes |
453453+| ----------- | -------- | ------------------------- |
454454+| `subject` | string | DID of the account to add |
455455+| `list` | string | AT-URI of the parent list |
456456+| `createdAt` | datetime | Required |
457457+458458+Duplicate list items for the same subject are ignored by the AppView.
459459+460460+### List Views
461461+462462+`listView` includes: `uri`, `cid`, `creator` (profileView), `name`,
463463+`purpose`, `description?`, `avatar?`, `listItemCount?`, `labels?`,
464464+`viewer?` (listViewerState with `muted?` and `blocked?`), `indexedAt`.
465465+466466+`listItemView` includes: `uri` (of the listitem record), `subject`
467467+(profileView).
468468+469469+### List Feed
470470+471471+`getListFeed` returns `feedViewPost` items — posts and reposts from list
472472+members. Only curation lists support feeds. The existing feed rendering
473473+infrastructure can be reused.
474474+475475+### Screens
476476+477477+**My Lists screen** (accessible from profile or settings): shows lists the
478478+user has created, separated by curation and moderation tabs. Each row shows
479479+name, avatar, member count, and purpose badge. FAB to create a new list.
480480+481481+**List detail screen**: shows the list header (name, avatar, description,
482482+creator, member count) and two tabs — **Feed** (for curation lists, using
483483+`getListFeed`) and **Members** (paginated member profiles). The overflow
484484+menu includes: edit list, delete list, add/remove members, and for mod
485485+lists — mute list / block via list.
486486+487487+**Add/remove members**: a screen with a search field using
488488+`searchActorsTypeahead` to find users, plus a list of current members with
489489+remove buttons. Adding creates a `listitem` record; removing deletes it.
490490+491491+**Create/edit list dialog**: name, description, avatar picker, and purpose
492492+selector (curation or moderation — reference lists are not user-created
493493+directly).
494494+495495+### Bloc Architecture
496496+497497+Build a `ListBloc` with events: `ListRequested`, `ListRefreshed`,
498498+`ListItemAdded`, `ListItemRemoved`, `ListMuted`, `ListUnmuted`,
499499+`ListBlocked`, `ListUnblocked`.
500500+501501+Build a `MyListsCubit` that loads the user's lists via `getLists`.
502502+503503+Build a `ListFeedBloc` reusing the feed pagination pattern from the home
504504+feed, backed by `getListFeed`.
505505+506506+### Profile Integration
507507+508508+On profile screens, add a "Lists" tab that shows lists created by that
509509+actor via `getLists`. Also add an "Add to list" option in the profile
510510+overflow menu that shows `getListsWithMembership` and lets the user toggle
511511+membership.
512512+513513+## Starter Packs
514514+515515+Starter packs are curated bundles of recommended accounts and feeds,
516516+designed to help new users bootstrap their experience. Each starter pack is
517517+backed by a reference list that holds the recommended accounts.
518518+519519+### API
520520+521521+| Endpoint | Purpose |
522522+| ---------------------------------------------- | ----------------------------------------- |
523523+| `app.bsky.graph.getStarterPack` | Detailed view of a single starter pack |
524524+| `app.bsky.graph.getStarterPacks` | Batch-fetch up to 25 starter packs by URI |
525525+| `app.bsky.graph.getActorStarterPacks` | Starter packs created by an actor |
526526+| `app.bsky.graph.getStarterPacksWithMembership` | User's starter packs with membership info |
527527+| `app.bsky.graph.searchStarterPacks` | Search starter packs by query string |
528528+529529+Starter pack records are managed through `com.atproto.repo.createRecord`,
530530+`putRecord`, and `deleteRecord` with collection
531531+`app.bsky.graph.starterpack`.
532532+533533+### Starter Pack Record
534534+535535+| Field | Type | Notes |
536536+| ------------------- | ----------- | -------------------------------- |
537537+| `name` | string | 1–50 graphemes |
538538+| `list` | string | AT-URI to a reference list |
539539+| `description` | string? | Max 300 graphemes / 3000 bytes |
540540+| `descriptionFacets` | facets[]? | Rich text facets for description |
541541+| `feeds` | feedItem[]? | Up to 3 feed generator URIs |
542542+| `createdAt` | datetime | Required |
543543+544544+`feedItem` contains a single `uri` field pointing to a feed generator
545545+record.
546546+547547+### Starter Pack Views
548548+549549+`starterPackView` (full): `uri`, `cid`, `record`, `creator`
550550+(profileViewBasic), `list?` (listViewBasic), `listItemsSample?` (up to 12
551551+listItemView), `feeds?` (up to 3 generatorView), `joinedWeekCount?`,
552552+`joinedAllTimeCount?`, `labels?`, `indexedAt`.
553553+554554+`starterPackViewBasic` (compact): `uri`, `cid`, `record`, `creator`
555555+(profileViewBasic), `listItemCount?`, `joinedWeekCount?`,
556556+`joinedAllTimeCount?`, `labels?`, `indexedAt`.
557557+558558+### Creation Flow
559559+560560+1. Create a reference list via `com.atproto.repo.createRecord` with
561561+ collection `app.bsky.graph.list` and purpose `referencelist`.
562562+2. Add members to the reference list by creating `listitem` records.
563563+3. Create the starter pack record pointing to the reference list.
564564+565565+Updating the people in a starter pack means adding/removing `listitem`
566566+records on its backing reference list. Updating the name, description, or
567567+feeds means updating the starter pack record itself.
568568+569569+### Screens
570570+571571+**Starter pack detail screen**: shows name, description, creator profile,
572572+join stats (`joinedWeekCount`, `joinedAllTimeCount`), a sample of members
573573+(up to 12 from `listItemsSample`), and recommended feeds. A "See all
574574+members" button navigates to the full member list via the backing reference
575575+list. A "Follow all" button follows every member in the pack.
576576+577577+**Actor starter packs screen**: shows starter packs created by a specific
578578+user, accessible from their profile. Uses `getActorStarterPacks` with
579579+pagination.
580580+581581+**Create/edit starter pack screen**: name (max 50 graphemes), description,
582582+member search (using `searchActorsTypeahead`), and feed picker (up to 3
583583+feeds from `getActorFeeds` or `getSuggestedFeeds`). On save, the app
584584+creates the reference list, adds members, then creates the starter pack
585585+record.
586586+587587+### Bloc Architecture
588588+589589+Build a `StarterPackBloc` with events: `StarterPackRequested`,
590590+`StarterPackCreated`, `StarterPackUpdated`, `StarterPackDeleted`,
591591+`MemberAdded`, `MemberRemoved`.
592592+593593+Build a `ActorStarterPacksCubit` that loads starter packs for a given
594594+actor via `getActorStarterPacks`.
595595+596596+### Profile Integration
597597+598598+On profile screens, add a "Starter Packs" section or tab showing packs
599599+created by that actor. Starter pack cards show the pack name, creator,
600600+member count, and join stats.
+59
docs/tasks/phase-4.md
···8282- [ ] Self-label support — render self-labels embedded in posts and profiles
8383- [ ] Labeler detail screen: show labeler creator, policies, and custom label definitions with localised names
8484- [x] Drift table: `labeler_cache` (labeler_did, policies_json, fetched_at) for offline label definition lookup
8585+8686+## M18 — Lists
8787+8888+### Core
8989+9090+- [ ] `ListBloc` — events: `ListRequested`, `ListRefreshed`, `ListItemAdded`, `ListItemRemoved`, `ListMuted`, `ListUnmuted`, `ListBlocked`, `ListUnblocked`
9191+- [ ] `MyListsCubit` — load user's lists via `getLists`
9292+- [ ] `ListFeedBloc` — paginated feed via `getListFeed`, reuse existing feed pattern
9393+9494+### List CRUD
9595+9696+- [ ] Create list — name, description, avatar, purpose selector (curation/moderation) via `com.atproto.repo.createRecord`
9797+- [ ] Edit list — update name, description, avatar via `com.atproto.repo.putRecord`
9898+- [ ] Delete list via `com.atproto.repo.deleteRecord`
9999+- [ ] Add members — search via `searchActorsTypeahead`, create `listitem` records
100100+- [ ] Remove members — delete `listitem` records
101101+102102+### Moderation Actions
103103+104104+- [ ] Mute list via `muteActorList` / unmute via `unmuteActorList`
105105+- [ ] Block via list — create `listblock` record; unblock — delete `listblock` record
106106+107107+### Screens
108108+109109+- [ ] My Lists screen — curation and moderation tabs, FAB to create new list
110110+- [ ] List detail screen — header (name, avatar, description, creator, member count), Feed tab (curation lists), Members tab
111111+- [ ] Add/remove members screen — search field + current members with remove buttons
112112+- [ ] Create/edit list dialog — name, description, avatar picker, purpose selector
113113+114114+### Profile Integration
115115+116116+- [ ] "Lists" tab on profile screens via `getLists`
117117+- [ ] "Add to list" option in profile overflow menu using `getListsWithMembership`
118118+119119+## M19 — Starter Packs
120120+121121+### Core
122122+123123+- [ ] `StarterPackBloc` — events: `StarterPackRequested`, `StarterPackCreated`, `StarterPackUpdated`, `StarterPackDeleted`, `MemberAdded`, `MemberRemoved`
124124+- [ ] `ActorStarterPacksCubit` — load starter packs for an actor via `getActorStarterPacks`
125125+126126+### Viewing
127127+128128+- [ ] Starter pack detail screen — name, description, creator, join stats, member sample (up to 12), recommended feeds (up to 3)
129129+- [ ] "See all members" — navigate to full member list via backing reference list
130130+- [ ] "Follow all" button — follow every member in the pack
131131+- [ ] Actor starter packs screen — paginated list via `getActorStarterPacks`
132132+133133+### Creation & Editing
134134+135135+- [ ] Create starter pack — name (max 50 graphemes), description, member search, feed picker (up to 3)
136136+- [ ] Creation flow: create reference list → add `listitem` records → create starter pack record
137137+- [ ] Edit starter pack — update name/description/feeds via `putRecord`, add/remove members via `listitem` CRUD
138138+- [ ] Delete starter pack and its backing reference list
139139+140140+### Profile Integration
141141+142142+- [ ] "Starter Packs" section on profile screens showing packs created by actor
143143+- [ ] Starter pack cards — name, creator, member count, join stats