Files
keiko/REWRITE.md
T
hikari 76e559876b
Node.js CI / CI (pull_request) Failing after 15s
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 54s
feat: rewrite as moderation bot (Keiko)
Replaces the old AI companion bot with a full Discord moderation system.

Commands: warn, mute, unmute, kick, softban, ban, unban, prune
Logging: member join/leave, activity (messages/threads/voice), mod actions
Audit log: captures manual bans, kicks, timeouts, and unbans
Sanctions: posts to Hikari sanction API for all applicable actions

All commands are ephemeral and use Components v2. Permission and role
hierarchy checks are enforced on every applicable command.
2026-03-24 20:15:41 -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