Skip to content

/member — Slash Command Spec

/member events and /member info are implemented. /member tog is Phase 3 scope. /member me is a Phase 2 stretch goal.

Commands

/member events [@member] [optional:role]
/member info [@member]
/member tog [add|remove|info] [@member]
/member me

/member events [@member] [optional:role]

Access

Chapter Organizer+

Parameters

  • @member — Discord mention, resolved to $People via resolve_member(snowflake)
  • role (optional) — autocomplete: Attendee, Instructor, TA, Medic. If omitted, shows all roles where data exists.

Grist Fields Used

Grist field Type Notes
events_attended ReferenceList → Events Events where member appears in attendees
dates_instructed ReferenceList → Events Events where member appears in instructors
dates_TAed ReferenceList → Events Events where member appears in TAs
dates_mediced ReferenceList → Events Events where member appears in medic
regions_attended Text Pre-formatted regions breakdown

Each referenced Event row uses structured_event (ChoiceList) and event_date (Date).

Response Format

Ephemeral. Example for /member events @alice:

Event history — @alice
Last event: 6/14/24

                Attended      Instructor
Pistol 1        3x (last 4/15/24)  2x (last 6/14/24)
Pistol 2        1x (last 1/10/24)  —
Rifle 1         2x (last 3/2/24)   —

Regions: South: 8, North: 3
  • Future-dated events are excluded from all counts and dates.
  • Empty rows (no data for that event type) and empty columns (no data for that role) are omitted.
  • Event types are sorted by STRUCTURED_EVENT_TYPES order; unknown types sort alphabetically after.

Dev Notes

  • _build_matrix() fetches all referenced event IDs across all active roles, then fetches those event rows in one get_records call filtered by ID.
  • Future events are filtered by comparing event_date against datetime.now(utc).timestamp().
  • The matrix cell format is Nx (last M/D/YY) or for zero.

/member info [@member]

Access

Chapter Organizer+

Parameters

  • @member — Discord mention, resolved to $People via resolve_member(snowflake)

Grist Fields Used

Display Grist field Type
Last event derived via _build_matrix() see /member events
Handle common_handle Text
Aliases all_aliases_no_PII Text
Region(s) discord_id_Region_roles_region List
Officer role(s) discord_id_Officer_roles_role List
Backlog join date backlog_join_date Date
Vetted date done_vetting_date Date
Dues expiration dues_expiration Date
LC dues current LC_dues_current Bool
ToG is_ToG Bool

Response Format

Ephemeral. Example for /member info @alice:

Member info — @alice

Last event: 6/14/24 (Pistol 1, Instructor)

Handle: alice
Aliases: Alice Smith, alicesmith
Region(s): South, North
Officer role(s): Organizing Committee
Backlog join date: 3/15/23
Vetted date: 4/1/23
Dues expires: 4/1/26  ✅ current
ToG: ✅ Yes
  • Last event line shows date, event type, and role. Omitted if no event history.
  • Vetted date omitted if null. Officer roles omitted if empty.
  • Dues: ✅ current if LC_dues_current, otherwise ⚠️ expired. Omitted if dues_expiration is null.

Dev Notes

  • Calls _build_matrix() (all roles, no filter) to derive the last event line — same future-event exclusion applies.
  • All fields are read-only.

/member me

Stretch goal for Phase 2. Implementation contingent on available hours.

Signature

/member me
/member me email [new_email]

Access

Any verified member (no organizer role required)

me (no subcommand)

Returns an ephemeral showing the caller's own non-sensitive member profile (same fields as /member info but self-directed). Read-only.

me email [new_email]

Updates $People.preferred_email_address for the calling member. Bot confirms the change before writing.

Dev Notes

  • Resolves caller via resolve_person(interaction.user.id) — no @member param
  • preferred_email_address write requires confirming the no-PII bot user has write access to this field

/member tog [add|remove|info] [@member]

Signature

/member tog [@member]                    — defaults to info
/member tog info [@member]
/member tog add [@member]
/member tog remove [@member]

Access

Representative+

What is ToG

"Toucher of Grass" — a member who has attended at least one counts_for_ToG event in the past 18 months (~547 days). Tracked via $People.tog_dates_attended_instructed_etc and $People.is_ToG.

info action

Read-only. Returns ephemeral:

🌿 ToG status — @alice
  Current: ✅ Yes
  Last ToG event: Jun 14 2024 — South P1
  ToG events (18mo window): 4
  Officer role (exempt from ToG req): No

Fields: - is_ToG — bool, pre-computed on $People - last_facilitated_or_tog_attended → event date and title - tog_dates_attended_instructed_etc — count those within 547 days of today - discord_id_Officer_roles_role — if non-empty and not only ["Vetting Team"], note exemption

add action

Assigns the ToG Discord role to the member and adds a row to the Touchers_of_grass Grist table. No event selection, no changes to $Events.

Flow: 1. Assign the ToG Discord role to the member 2. POST a new row to Touchers_of_grass linking the member

Note: Bot may not have create-row permissions on Touchers_of_grass. Verify before implementing; if not, the organizer will need to add that row in Grist manually.

remove action

Revokes the ToG Discord role and removes the member's row(s) from the Touchers_of_grass Grist table. Used when ToG status expires.

Flow: 1. Remove the ToG Discord role from the member 2. DELETE the member's row(s) from Touchers_of_grass

Dev Notes

  • is_ToG formula in $People: if member has an officer role other than Vetting Team, returns True regardless of attendance. Bot should reflect this exemption in display.
  • Do not attempt to replicate is_ToG logic in the bot — read the field directly
  • tog_dates_attended_instructed_etc is ordered by -event_date — the first element is the most recent

Open Questions

  1. Bot write access to Touchers_of_grass — confirm whether the bot's API key has create-row permissions on this table before implementing tog add.
  2. Touchers_of_grass delete permissions — confirm whether the bot's API key can delete rows on this table before implementing tog remove.
  3. /member events for non-Discord members — all current members have Discord, so @mention is fine for now. Revisit at P3.