Your channels
The bot posts to five places. Each one is a different kind of attention.
| Channel | What lands there | Attention |
|---|---|---|
| log | Every stock movement, every new item. Public. | None. It's the audit trail. |
| approvals | Checkouts that need a decision, purchase requests, the pick list before a meeting, the Sunday digests. | Press the button. Nothing moves until you do. |
| assignments | Tasks the bot lifted from a meeting recording, waiting for a name. | Assign, date, file under a project, or bin. Ideally within a day of the meeting. |
| tasks | Blocked-task cards and the daily "where the work stands." | Read. Chase what's rotting. |
| minutes | Finished meeting minutes. | Skim for anything the summariser got wrong; fix it on the Notion page. |
| errors | The bot's own failures, with the command and the reason. | Whoever owns the bot this term reads it. |
Members never see approvals, assignments, tasks or errors. Keep them private.
Stock
Lend a part to somebody. Refuses more than are available. Approval-tier parts post a card instead and move nothing until it's pressed.
Commit hardware to a project. It leaves the available pool but the club still owns it. Release gives it back.
A shipment arrived. This is also the last step of purchasing.
The pick list: what members asked to have brought to the next meeting, grouped by shelf so it's one walk. There's a button to close it all.
Pull from Notion right now instead of waiting for the ten-minute sync. Shows what changed.
Totals, value on hand, what needs attention.
Never fix a count by editing a number in Notion. Counts are derived from the ledger. To correct one, add a ledger row with Adjust and a reason, or delete the wrong row. Editing Qty Stocked directly silently breaks the arithmetic everywhere.
A flag from /report — broken, missing, count wrong, needs label — posts a card with a resolve button. Flags don't block anything; a part marked Broken still checks out. That's deliberate: a rule nobody maintains just teaches people to route around the bot.
Intake and labels
New part in hand → serial on it → on the shelf. Under a minute if the printer is on.
- Run
/intakewith a name, a count, and ideally a location, category, part number and a photo shot on the shelf. Addlabel:True./intake name:VL53L3CX ToF sensor qty:6 location:Cabinet shelf #2 category:Sensors part:497-VL53L3CXV0DH/1CT-ND label:True
- Read the serial back. It's permanent —
BURC-0137— and it never changes or gets reused, even if the part is retired. - The label prints on the printer in the bunker within a few seconds. QR for phones, barcode for the scanner, serial for people.
- Stick it on and shelve it. If you skipped the location, the part is flagged Needs label until you set one.
Reprint a label for anything. Serials, typed or scanned, in any spelling.
Add or replace the picture. Photos live on the club's Cloudflare, so they never expire.
If /label says the printer hasn't checked in, the Pi in the bunker is off or lost Wi-Fi. Jobs wait; they print when it's back. If a label fails, the errors channel says why.
The part-number field matters more than it looks: /request and /orders paste it straight into a supplier's order box. Copy it exactly as the supplier lists it.
Meetings and minutes
- Create the meeting.
/eventputs it on the server calendar and in Notion, and opens check-in half an hour before./meetingopens an ad-hoc one right now./event name:General meeting when:thursday 6pm location:the bunker minutes:90 code:banana
Thecodeis optional — write it on the whiteboard and people have to type it, so nobody checks in from their dorm. - Say you're recording. Before you press record: there's a sign in the bunker, and you say it out loud. That's the whole legal requirement in Massachusetts — awareness, not paperwork. Don't announce it in Discord; the people in the room are the ones being recorded.
- Record on a phone. Voice Memos on iPhone, Settings → Voice Memos → Audio Quality → Compressed. A 90-minute meeting is about 20 MB, under the 24 MB cap.
- Hand it in.
/notes announced:True audio:<the file>. The bot confirms it's queued. - Wait about ten minutes. Minutes land in the minutes channel and on the meeting's Notion page: summary, decisions, action items, what was discussed, open questions, and the full transcript in a collapsed toggle. The audio is deleted the moment the transcript exists.
- Check the assignments channel. Every piece of work the meeting created is there as a card. That's the next section.
Who's checked in right now, and when check-in shuts.
Anyone's grid and streak. Members can only see their own.
Posts the permanent check-in button. Run it once, ever, then pin the message.
The task board
The bot proposes; you decide. It never puts a name on anything by itself.
After every set of minutes, the assignments channel gets one card per job the meeting created — including work nobody volunteered for out loud. "Show a video on the TV" means somebody has to make the video and find a TV, and the bot says so:
📋 TSK-9 Source a TV for the demo table Due 2026-09-11, from the transcript. Nobody volunteered for this — it follows from showing video instead of the robot. No owner was named. [ Assign to… ▾ ] [ File under a project… ▾ ] [ Set a due date ] [ Not a task ]
Four things to do with each card, ideally the day after the meeting:
- Assign to… — pick a member. They get a DM with a Done button. If the transcript mentioned a name, the card says so, but it's a guess and it's never applied for you.
- File under a project — so
/tasks project:ARCTOSworks. Minutes never say which project; this is the moment somebody knows. - Set a due date —
friday,9/18,tomorrow. Nothing gets chased without one. A task with an owner and no date sits in the "no date" pile forever. - Not a task — one tap. Expect to use it; the bot would rather propose eight and have you bin three than propose two and miss the important one.
Got the wrong list? /retask bins every unassigned proposal from that meeting and reads the transcript again. Anything somebody already owns is left alone.
Assign something directly, outside a meeting.
Anyone's plate. /tasks project:… for a project's whole board.
Blocking. When a member runs /block naming who they're waiting on, the chasing moves to that person — the daily DM goes to the blocker, not the owner, until they tap Unblock. A card in the tasks channel shows every open block; it's struck through when it clears, with how long it lasted. If the same person is blocking three things, that's your signal.
Buying
Members ask. You approve. The bot writes the order for you. You paste it.
- A request arrives in approvals with the part, quantity, supplier, reason, and — if it's restocking something — the current stock and reorder point. Approve or Deny; the member is told either way.
- When you're ready to order,
/orders. Every approved line, grouped by supplier, as a paste-ready list:DigiKey — 2 lines · $14.00 1N4148,50 MAX11206EEE+-ND,2 Paste straight into their bulk order box.
DigiKey, Mouser and Amazon Business all take that format directly. McMaster doesn't have a paste box; the bot says so and you order those by hand. - Place the order, then press Mark DigiKey ordered. Those lines flip to Ordered with today's date. Put the supplier's order number in the
Order Refcolumn in Notion if you want to find it later. - When the box arrives, mark the rows Received in Notion and
/restockeach part onto the shelf. Purchasing and inventory are separate on purpose — one is money, the other is stock, and conflating them means you can't answer either question.
Automatic reordering is deliberately not a feature. A bot that spends club money with nobody in the loop is a bad idea at any budget.
The weekly rhythm
What the bot sends without being asked, so it isn't a surprise.
| When | What | Where |
|---|---|---|
| daily 08:00 | Task digest — each owner DMed what they owe; leads get "where the work stands" with what's overdue and who's blocking whom | DM · tasks |
| daily 09:00 | Overdue borrows — DM to the borrower; escalates to you at three days or if their DMs are off | DM · approvals |
| 2 h before a meeting | The pick list — everything members asked to have brought, grouped by shelf | approvals |
| Wed 17:00 | Retention nudges — people who missed the last two meetings get a friendly DM; the second one asks why. At most two, ever. Summary to you. | DM · nudges |
| Sun 19:00 | Restock digest — everything at or below its reorder point, priced, with a total | approvals |
| Sun 20:00 | Inventory gaps — items with no name, location, count, price or photo; flagged rows | approvals |
The retention messages are conservative on purpose. The failure mode of a retention system is becoming the thing people mute. The wording lives in the Nudge Templates database in Notion — change it there, no code involved. The answers to "why did you stop coming" land in Member Feedback, and they are the most useful thing the club collects.
When it breaks
Three places to look, in order.
- The errors channel. Almost every failure posts there with the command that caused it and the reason. Read it before anything else.
/health— openhttps://<the worker>/healthin a browser. It lists which settings are present, whether the printer has checked in, how many minutes jobs are queued, and the first error it hits.- Cloudflare → the Worker → Logs. Only if the first two are silent.
/refresh.••• → Connections → Bunker Bot./health → minutes_queued. Climbing means the cron is failing; errors channel will say why./health → printer_last_seen. Null or old means the Pi is off. On the Pi: journalctl -u labeld -f./register?secret=… on the Worker.TZ_OFFSET. It's -4 in summer and -5 from the first Sunday in November. Somebody has to change it by hand, twice a year.Handover
The bot has to outlive whoever built it. Five things have to be true before a term ends.
- The Discord application is owned by a Team, not a person's account.
- Cloudflare and Notion are on the club address, not a student address that dies at graduation.
worker.jsand this documentation are in the club GitHub.REGISTER_SECRET,PRINT_SECRET, the bot token, and the two model API keys (Groq, Gemini) are somewhere the next president can reach.- The model API keys are on club accounts, not personal ones. They're free tiers, but a free tier on somebody's personal Google account is a bot that stops working the day they leave.
Whoever inherits this should read the technical reference once, end to end, before they need it. It's long because it's honest about what breaks.