Files
keiko/REWRITE.md
hikari 1c31a49bc4
Node.js CI / CI (push) Successful in 29s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 55s
feat: rewrite as moderation bot (#11)
## Summary

- Replaces the old AI companion bot with a full Discord moderation system
- Adds 8 slash commands: `warn`, `mute`, `unmute`, `kick`, `softban`, `ban`, `unban`, `prune`
- Adds logging for member join/leave, activity (messages, threads, voice), and moderation actions
- Audit log integration captures manual bans, kicks, timeouts, and unbans
- All applicable actions post sanctions to the Hikari sanction API
- All commands are ephemeral, use Components v2, and enforce permission + role hierarchy checks

## Test plan

- [ ] Run `pnpm register` to register all 8 commands to the guild
- [ ] Verify each command appears in Discord and is only visible to members with the appropriate permissions
- [ ] Test each command against a valid target and confirm mod log entry, DM notification, and sanction record
- [ ] Test each command against an invalid target (equal/higher role, self, bot) and confirm correct error response
- [ ] Perform a manual ban, kick, and timeout in the Discord UI and confirm audit log handler picks them up
- [ ] Perform a manual unban and confirm it logs correctly without creating a sanction
- [ ] Verify join/leave messages appear in the welcome log channel
- [ ] Verify message edits, deletes, thread events, and voice state changes appear in the activity log channel

 This issue was created with help from Hikari~ 🌸

Reviewed-on: #11
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-03-24 20:35:26 -07:00

4.3 KiB

Keiko — Moderation Bot Rewrite

Overview

Complete rewrite of Keiko from an AI companion bot into a full-featured community moderation bot for Naomi's Discord server.


Tech Stack

  • Language: TypeScript
  • Runtime: Node.js
  • Discord Library: discord.js v14
  • Config: @nhcarrigan/typescript-config
  • Linting: @nhcarrigan/eslint-config
  • Logging: @nhcarrigan/logger
  • Package Manager: pnpm

Planned Commands

All moderation commands respond ephemerally using Discord Components v2.

Command Description Sanction Type
/warn <user> <reason> Issues a formal warning warning
/mute <user> <duration> <reason> Applies Discord native timeout mute
/unmute <user> <reason> Removes Discord native timeout (none)
/kick <user> <reason> Kicks user from server kick
/softban <user> <reason> Bans + immediately unbans (message purge) kick
/ban <user> <reason> [days] Permanently bans user ban
/prune <amount max:100> Deletes last N messages in current channel (none — logged to mod channel only)

Logging Channels

Three configurable logging channels (set via environment/config):

Channel Events
Welcome/Goodbye guildMemberAdd, guildMemberRemove
Activity Log Message create/edit/delete, thread create/delete/update, voice channel join/leave/move
Moderation Log All command-issued sanctions + parsed audit log actions (manual bans, kicks, timeouts)

Sanction API Integration

Endpoint: POST https://hikari.nhcarrigan.com/sanction Auth: Authorization: {SANCTION_TOKEN}

Payload:

{
  "platform": "discord",
  "uuid": "<target user ID>",
  "username": "<target username>",
  "type": "warning | kick | mute | ban",
  "reason": "<reason>"
}

Triggers (sanction created for each):

  • /warnwarning
  • /mutemute
  • /kickkick
  • /softbankick
  • /banban
  • Audit log: manual ban detected → ban
  • Audit log: manual kick detected → kick
  • Audit log: manual timeout detected → mute

No sanction: /unmute, /prune


Confirmed Decisions

Question Decision
Softban sanction type Maps to kick
Mute mechanism Discord native timeout
Prune scope Last N messages (up to 100) in current channel; no sanction, log to mod channel
Channel config Config object in src/config/ (single-server)
Deployment scope Single guild only
Repo strategy Replace in-place on feat/modbot branch

Project Structure (Planned)

keiko/
├── src/
│   ├── commands/          # Slash command definitions
│   ├── events/            # Discord event handlers
│   ├── modules/           # Business logic (sanction sending, audit log parsing, etc.)
│   ├── utils/             # Shared utilities
│   └── index.ts           # Entry point
├── prod.env               # 1Password secret references (safe to commit)
├── package.json
├── tsconfig.json
├── eslint.config.js
└── vitest.config.ts

Implementation Phases

  • Phase 1 — Project scaffold (package.json, tsconfig, eslint, entry point)
  • Phase 2 — Commands (all 7 slash commands with ephemeral Components v2 responses)
  • Phase 3 — Sanction API integration (send sanctions on command, handle errors)
  • Phase 4 — Logging events (welcome/goodbye, activity, moderation channel)
  • Phase 5 — Audit log parsing (detect manual moderation actions, send to sanction API)
  • Phase 6 — Deploy (fill in channel IDs in src/config/channels.ts, fill in clientId in src/config/guild.ts, run pnpm register to register commands, then pnpm start)

Next Steps Before Deploying

  1. Fill in actual channel IDs in src/config/channels.ts
  2. Fill in Keiko's bot client ID in src/config/guild.ts
  3. Ensure SANCTION_TOKEN is in 1Password at the vault path in prod.env
  4. Run pnpm register once to register slash commands with Discord
  5. Enable privileged intents in Discord Developer Portal: Server Members Intent and Message Content Intent
  6. Start the bot with pnpm start