action-bot
action-bot registers a guild-scoped Discord /aar command. Authorized members get a modal for title, summary, and details. The bot creates a dated Hugo Markdown file on a unique branch in vapor-sea/www.vapor-sea.space, opens a pull request, and returns the review URL as an ephemeral Discord response.
The bot never pushes directly to the site’s default branch.
Content contract
content/aar/YYYY/MM/DD/<slug>.md
aar/YYYY-MM-DD/<slug>-<interaction-suffix>
Gitea is the durable state store. Retrying one Discord modal submission returns the existing pull request instead of creating another one.
Configuration
Required secrets:
DISCORD_TOKENDISCORD_APPLICATION_IDDISCORD_GUILD_IDDISCORD_ALLOWED_ROLE_IDS— comma-separated Discord role IDs; empty configuration denies startupGITEA_TOKEN— token for a service account with write access only to the target site repository
Optional values:
GITEA_BASE_URL(defaulthttps://git.r3r4um.online)GITEA_OWNER(defaultvapor-sea)GITEA_REPO(defaultwww.vapor-sea.space)GITEA_BASE_BRANCH(defaultmaster)AAR_TIMEZONE(defaultAmerica/New_York)LISTEN_ADDR(default:8080)
Discord setup
- Create an application in the Discord Developer Portal.
- Add a bot and capture its token once.
- Install it in the target guild with the
botandapplications.commandsscopes. It does not need Message Content intent or broad server permissions. - Copy the application ID, guild ID, and authorized role IDs into the runtime Secret.
- Start the service. It creates/updates the guild-scoped
/aarcommand through Discord’s application-command API and then marks/readyzready.
Guild-scoped registration is deliberate for the first deployment: changes appear quickly and cannot leak the command into unrelated servers. Global registration can be added later.
Local verification
make check
make build
docker build -t action-bot:local .
docker run --rm action-bot:local
The last command should exit non-zero with DISCORD_TOKEN is required; that proves the image starts and fails closed without credentials.
Kubernetes
k8s/secret.example.yaml is a template and is intentionally excluded from k8s/kustomization.yaml.
./scripts/configure-k8s-secret.sh
kubectl apply -k k8s
kubectl -n action-bot rollout status deploy/action-bot
kubectl -n action-bot get pods
The helper prompts locally, stages credentials in a mode-0600 temporary file, applies the Secret, and securely removes the temporary file. It does not print secret values or pass them through process arguments.
The Deployment uses Recreate with one replica so two Discord Gateway consumers do not process the same command during rollout.