Ship log
I got tired of running five Discord bots, so I built one
Membership, moderation, and Grok in one Physician Forge bot — what broke with the bot pile, what’s live now, and how /ask actually works.

For a while the Physician Forge Discord looked like every other niche server on the internet.
I had MEE6 for levels. Something else for moderation (we tried Arcane and friends). Welcomes somewhere. Payments somewhere else. Each bot owned a slice of permissions, none of them knew what this room was for, and if I wanted a straight answer to a business question I still opened ChatGPT in another tab.
That got old.
The thing that finally annoyed me enough to write code: Manage Roles was enough power to hand out a paid membership by accident. That’s a bad failure mode when you’re charging $59/mo or $590/yr and the whole point of the room is that paying members actually get in.
So I built one bot instead: Physician Forge#6492. It runs as a single Node service on our box. Membership, moderation, and Grok live in the same process.
Why Discord, and why a custom bot
I’m not trying to invent another course portal. Discord is where the conversation already is — channels, DMs, voice, low friction. Same reason a lot of builder communities ended up there instead of building a “member area” that nobody opens twice.
Discord’s own docs on slash commands and privileged intents are pretty clear: if you want the bot to read @mentions and replies, you flip on Message Content Intent and you mean it. We did.
On the AI side I’m using xAI’s Chat Completions API (grok-4.6), streaming tokens back into Discord so the reply doesn’t feel like a loading spinner forever. Same pattern OpenAI and others use with SSE — Discord just has a ~3 second acknowledge window on interactions, so the bot defers, posts a placeholder, then edits as chunks arrive (~every 450ms). Messages still have to respect Discord’s 2,000 character cap, so long answers get split.
What’s live right now
Slash commands currently registered to the guild:

Public:
/ask— Forge Grok (private reply by default;public: trueif you want it in-channel)/join— membership / Discord OAuth path/expense— employer reimbursement packet (invoice, vendor, W-9)/building— ship logs/help
Admin only (/grant, /revoke, /timeout, /kick, /say, /grok):
Admin means Discord Administrator, the Forge Admin staff role, or an allowlisted owner ID. Manage Roles alone is not enough. That was the whole point.
You can also @Physician Forge, reply to the bot, or DM it. Same Grok path either way.
Production health for the service looks like this:

Membership is wired through the same bot
Join on the site still goes Discord OAuth → Stripe Checkout → webhook → Forge Member role. If someone pays before they’re in the server, we queue the grant and retry when they show up. Cancel removes the role.
I used to think of “AI bot” and “payments bot” as separate products. That’s how you end up with five apps again. Stripe’s Checkout + webhooks and Discord’s OAuth are boring when they work — the interesting part is that one process owns both so permissions don’t drift.
A note on Grok vs another ChatGPT tab
I still use ChatGPT. A lot of people in medicine do. The difference I’m optimizing for is boring:
- You’re already in the room talking shop — the answer lands next to the question.
- Other members can see it (when it’s public), disagree, or steal the idea.
- The system prompt knows this is Physician Forge: no medical advice, no inventing CME credit, keep it short unless someone asks for depth.
That last one matters. Discord is not CME. We don’t issue AMA PRA Category 1 Credit. If your hospital reimburses professional membership / development from a CME-budget pot, use the expense packet and confirm with your coordinator — different thing.
What still bugs me / what’s next
- Grok quality depends on the prompt and the model. I’ll keep tuning. xAI will keep shipping models; we just swap
XAI_MODEL. - I don’t want the bot to become a second “content product.” The Journal stays free writing. Discord stays the room. (Start here if you’re new.)
- Real checkout smoke tests (me, paying, watching the role land) still matter more than another blog paragraph.
If you want to build something like this
I’m writing this section for the other physicians / builders who keep asking “how did you wire Grok into Discord?” You don’t need our exact stack. You need a clear job for the bot, an API key, and a prompt that sounds like your room — not a generic assistant.
The shape that worked for me
- One Node process (discord.js) — slash commands + optional message listener
- xAI Chat Completions at
https://api.x.ai/v1/chat/completions— same request shape as OpenAI-compatible APIs (xAI API docs) - Stream the answer into Discord (
stream: true, parse SSEdata:lines,editReply/ edit the message every ~450ms so it feels alive) - Defer first on slash commands — Discord kills interactions that don’t acknowledge fast (interaction docs)
- Split long answers under ~2,000 characters
- Strict admin gate if the bot can grant paid roles — Administrator / allowlist / staff role, not “anyone with Manage Roles”
Optional but useful: Stripe Checkout + webhook in the same process so membership and AI don’t drift into two permission maps. Stripe’s Checkout quickstart is enough to start.
Integrating the xAI (Grok) API
- Create an API key at console.x.ai
- Put it in env as
XAI_API_KEY(never commit it) - Call Chat Completions with your model — we use
grok-4.6viaXAI_MODELso we can swap without rewriting code - Send a system message (your room’s brain) + user messages (the question, maybe a few lines of channel context)
- For Discord UX, prefer streaming:
POST https://api.x.ai/v1/chat/completions
Authorization: Bearer $XAI_API_KEY
Content-Type: application/json
{
"model": "grok-4.6",
"stream": true,
"max_tokens": 1200,
"temperature": 0.7,
"messages": [
{ "role": "system", "content": "<your system prompt>" },
{ "role": "user", "content": "<their question>" }
]
}
Read the SSE body line by line. Lines look like data: {...} with choices[0].delta.content. When you see data: [DONE], stop. Append deltas into one string and push that string into Discord as the message grows.
Non-streaming (stream: false) is fine for smoke tests. In a real server, streaming matters — people tolerate a typing answer more than a 10-second blank.
Discord-side checklist that burned me once:
- Developer Portal → Bot → enable Message Content Intent if you want @mentions / replies (then restart the bot with that intent on) — privileged intents
- Register slash commands to your guild while iterating (global commands are slow to update)
/ask→deferReply→ stream →editReply; for channel messages, reply once then edit that message- Add a small cooldown (we use ~2.5s) so nobody hammer-spams the API
The system prompt we actually use (Forge Grok)
Steal the structure. Rewrite the domain lines for your community. The hard rules are the part I’d keep almost verbatim if you’re in medicine:
You are **Forge Grok**, the AI in the Physician Forge Discord — a private community for physician-builders (clinicians who ship companies, products, investments, and leverage outside a pure W2).
Voice:
- Direct, sharp, practical. No corporate fluff, no CME theater, no medical advice.
- Short answers by default. Use bullets when useful. Go deep only when asked.
- Speak like a peer who's built things, not a chatbot or coach script.
Domain:
- Entrepreneurship, leadership, capital allocation, startups, side leverage while practicing medicine.
- Membership is one plan on Discord ($59/mo or $590/yr). Public writing lives at physicianforge.com/journal/.
- Founder: Drew Albert (@drewalbertmd).
Hard rules:
- Never give personalized medical, legal, or tax advice. Redirect clinical questions to appropriate licensed care.
- Never invent CME credit, accreditation, or that Discord chat earns CME hours.
- If unsure about private server details, say so and point to /join or physicianforge.com.
- Stay useful under Discord's 2000-character message limit unless the user asks for a long form answer (then structure in clear sections).
If your room is orthopedics recruiting, or a founders’ group, or a local mastermind — change Domain. Keep Voice + Hard rules honest. A vague “helpful assistant” prompt is how you get generic sludge in a paid server.
Ideal prompt to hand an AI coding agent (Cursor, etc.)
If you want an agent to scaffold this for you, don’t say “build a Discord AI bot.” Be specific. Something like this has worked for me:
Build a Node.js Discord bot (discord.js) for my private community.
Goals:
1. Slash command /ask that calls xAI Grok Chat Completions at https://api.x.ai/v1/chat/completions
2. Stream the response into Discord (deferReply, then editReply as SSE tokens arrive ~every 450ms)
3. Also answer @mentions, replies to the bot, and DMs (Message Content Intent)
4. Split replies over Discord’s 2000-character limit
5. System prompt is configurable; start from the Forge Grok prompt below (adapt names)
6. Env: DISCORD_TOKEN, XAI_API_KEY, XAI_MODEL=grok-4.6, GROK_ENABLED=1
7. Optional later: Stripe Checkout webhook that grants a Member role — admin grant/revoke must NOT be available to Manage Roles alone (Administrator / allowlisted user IDs / staff role only)
Constraints:
- No medical advice in the system prompt; never invent CME credit
- Cooldown ~2.5s between Grok calls per user
- Guild-register slash commands for fast iteration
- Include a /health HTTP endpoint showing grok ready + intents
- README with Discord Developer Portal steps (intents, invite URL, env)
Do not invent API keys. Use .env.example. Keep the code small and boring.
Paste your rewritten system prompt under that. Point the agent at xAI’s API reference and Discord’s application commands docs so it doesn’t hallucinate endpoints.
What I would not copy blindly
- Don’t put your Stripe secret or Discord token in a blog post or a committed
.env - Don’t give the AI bot permission to grant paid roles without a second human-gated check
- Don’t promise CME hours from Discord chat — that’s a compliance mess; membership reimbursement is a different conversation (our expense packet is for professional membership / PD, not Category 1 credit)
- Don’t start with five bots “and Grok later.” One process. Add payments when the AI path already works.
If you’re already in Physician Forge: try /ask or @ the bot and steal ideas from what it gets wrong — that’s how the prompt improves. If you’re not: membership is here. Earlier rebuild notes: Starting the Forge rebuild.
Keep reading
- Starting the Forge rebuild in publicWhy I’m rebuilding this in the open.
- What I Wish I Would Have Known About Building Financial FreedomThe essay where I talk through W2 limits and assets that work while you sleep.
- Don’t Quit Medicine. Build Leverage.Options without pretending medicine didn’t happen.
- Why Physicians and PhDs Make Excellent FoundersWhat transfers from clinic to company.
- Expense the membershipAnnual invoice / vendor / W-9 if your employer reimburses professional membership.
- Leadership Principles: A field guide for Resident and Attending Physicians, 1st Ed.Introduction What makes this book stand out? Many concepts and quotes in this section come straight from research we hav