agentleFS
lettr-comlettr-com/lettr-skills/audience/SKILL.md

audience

Skill0 starsChanged 5 months agoMITView on GitHub

Use when managing Lettr audience data from code — contact lists, contacts (incl. double opt-in and bulk import), subscription topics, custom properties, and dynamic segments. This is the marketing/contacts side that campaigns send to.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. jamillazarev/opsinist★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository7 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Properties are typed and pre-declared: Create a property (String/Number/Boolean/Date/Json) before writing it on contacts.

    line 38
  2. Very specific:

    After a bulk import or segment change, read it back (GET the list/segment, or list contacts filtered by status/list) and report counts to …

    line 43

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Manage Lettr audience

The audience is what campaigns target: lists (static collections), contacts (the people), topics (subscription categories), properties (typed custom fields), and segments (dynamic groups defined by conditions). All five share a CRUD shape.

1. Load the references

  • SDK calls: detect the stack via ../_shared/detect-stack.md, then read ../_generated/sdk/<lang>/audience.md — the sub-services, DTOs, enums, and bulk helpers.
  • Wire contract: ../_generated/api/index.md, Audience section — every endpoint with required fields bolded.

2. Map the task to the right resource

GoalResource
Group contacts staticallylist (POST /audience/lists)
Add/import people, all treated the samecontacts — …/bulk with a flat emails list
Import people who differ from each othercontacts — …/bulk with contacts[], one row per person
Let people opt in/out of categoriestopics
Move many people on/off many topicsPOST/DELETE /audience/contacts/topics/bulk
Store typed custom fields (plan, signup date…)properties — create the property before setting it on contacts
Target by rules (plan = pro AND domain = …)segments

3. Gotchas that matter

  • Double opt-in. Creating a contact with a double-opt-in config sends a confirmation email and leaves the contact Unverified until they confirm — they are not subscribed yet. Don't treat creation as subscription. Requires a verified from domain and (usually) a confirmation template.
  • Contact status is meaningful. Subscribed, Unsubscribed, Bounced, Complained, Unverified. Don't resurrect Unsubscribed/Complained contacts by re-creating them — that's a compliance problem, not a bug.
  • Bulk over loops. For many contacts, or many list/topic attach/detach operations, use the …/bulk endpoints, not N single calls (rate limit is 3 req/s per team).
  • A successful bulk import does not mean every row landed. POST /audience/contacts/bulk answers 201 even when rows failed: bad rows are skipped, the rest of the batch commits. Always read error_count and errors[] (each carries a zero-based index into the rows you sent, plus email, error_code and error) and report skipped rows to the user. Never report "imported N contacts" from the row count you submitted.
  • already_existed and updated overlap — they never sum to the row count. They answer different questions: "was it already there?" and "did we change it?". A contact that already existed and got a list attached is counted in both. Reporting created + already_existed + updated as a total is wrong arithmetic. Note updated counts any change, including a list or topic attach — not just properties being written.
  • update_existing gates properties only. With it off, an existing contact keeps its properties but is still attached to the requested lists and topic opt-ins, and a row-level opt_out still drops an existing subscription. Consent and suppression imports do not need the flag. It used to gate opt-outs too, dropping them silently with no error row — so treat any advice to set update_existing: true in order to make opt-outs land as predating that fix.
  • Row-level opt_out beats batch-level opt_in. That precedence is the point of the feature: a topic whose default_subscription is opt_out auto-subscribes newly created contacts, and a row-level opt_out suppresses that in the same request instead of needing a cleanup call afterwards. It applies to contacts that already exist as well: a row-level opt_out unsubscribes them regardless of update_existing.
  • A duplicate contact is a 409, not a server error. POST /audience/contacts on an email that already exists returns 409 / resource_already_exists. It is client-correctable — update the existing contact, or bulk-create with update_existing — and it must not be retried. It used to escape as 500 / send_error; that code named email delivery, which was never involved, so ignore any older reference that maps send_error to this endpoint.
  • contacts[] gives you the ids back. The bulk response returns { id, email, created } for every contact that exists after the request, in submission order. Use it instead of a follow-up lookup to resolve ids.
  • Properties are typed and pre-declared. Create a property (String/Number/Boolean/Date/Json) before writing it on contacts; a fallback_value covers contacts that lack it.
  • Segment condition logic: conditions within a group are OR-ed, groups are AND-ed — i.e. (A OR B) AND (C OR D). One group means "any of these"; add a group to narrow, add a condition to widen. Getting this inverted silently changes who gets mail. Scope a segment to a list_id when you don't want it spanning the whole audience.

4. Verify

After a bulk import or segment change, read it back (GET the list/segment, or list contacts filtered by status/list) and report counts to the user before anything sends to it. Sending to the audience is the campaigns skill.

For a bulk import specifically, report created, already_existed and updated as three separate answers rather than a total (they overlap), and state the skipped-row count explicitly — including when it is zero, so "all rows landed" is something you checked rather than assumed.

What this skill does not do

  • It doesn't create or send campaigns — that's campaigns.
  • It doesn't send transactional one-offs — that's sending.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.