Skip to content

Bot admin command surface (!mint, !ban, !stats) + co-admin handoff plan #7

@amiller

Description

@amiller

Why

Right now there's no way for a non-shell user to administer the Shape Rotator deployment. Adding a knock code requires SSH'ing into the CVM and editing /data/codes.json by hand. That's fine for a one-operator repo but makes co-administration painful — you'd have to share the deploy key, the phala account, and trust the helper not to break the JSON.

The natural Matrix-native answer: expose admin operations as bot commands in #bot-noise (or a dedicated #admin room). The bot reads the sender's MXID + power level on the room, refuses if PL < 50, and executes. This gives free auth (Matrix already verifies senders), free audit (every admin action has a real human sender), and free revocation (kick + lower PL).

Architecture: don't share @shape-rotator-2

Standing position from the design discussion (transcript in @amiller's notes):

  • @shape-rotator-2 stays the bot persona only — knock approval, captcha, future automated commands. Single process running in the TEE. One token, sealed in the CVM, rotated via deploy/admin/mint_token.sh (deploy/admin/mint_token.sh — rotate KNOCK_APPROVER_TOKEN end-to-end #6).
  • Each human admin gets their own MXID at PL ≥ 50 in the space. No shared bearer tokens, no conflated audit, no rotation coordination.
  • Admins issue commands by talking to @shape-rotator-2 from their own accounts.

Multi-device on a single account (multiple hermes agents signed in as @shape-rotator-2) was considered and rejected: it's technically fine for cleartext rooms but the megolm key-share burden in any E2EE child room makes it not portable. Easier to keep the bot as one process and let humans run their own infrastructure.

Proposed command surface

All commands live in #bot-noise (or whatever room we designate). Bot ignores anyone with PL < 50.

Code management

Command Effect
!mint [label?] Generate a fresh single-use knock code (the kind that takes you to the haiku captcha). Returns the URL https://mtrx.shaperotator.xyz/join?code=….
!mint signup [label?] Generate a single-use signup code (account-creation on this server).
!mint --uses N [label?] Multi-use code (default 1).
!codes List currently-valid codes with uses_remaining + label.
!revoke <code> Mark a code as 0-uses-remaining.

Room moderation

Command Effect
!kick <mxid> [reason?] Kick from the space. Child rooms restricted-rule re-evaluates.
!ban <mxid> [reason?] Ban from the space.
!unban <mxid> Lift ban.

Vetting / observability

Command Effect
!stats Last-24h: knocks received, vetted-and-promoted, rejected, currently-pending, captcha keywords seen.
!vetting List currently-open vetting rooms with knocker MXID + age. Useful when someone reports their captcha didn't fire.
!retry <vetting_room_id> Re-issue the captcha challenge to a stuck user.

Operator helpers (out-of-band, not via Matrix)

These stay as scripts in deploy/admin/:

Implementation sketch

Extend knock-approver/approver.py:

  1. New env: ADMIN_ROOM_ID (defaults to #bot-noise).
  2. In sync_loop, after the existing knock + vetting handling, add a third pass: iterate timeline events in ADMIN_ROOM_ID, dispatch on body.split()[0] (the !cmd).
  3. Per-command handler (handle_mint, handle_codes, etc.). Each:
    • Pulls sender's PL from m.room.power_levels state.
    • Refuses with a reaction () if PL < 50.
    • Executes, replies in-room with the result.
  4. Persistence: !mint writes to existing /data/codes.json (already volume-backed), !revoke zeroes uses, !stats reads /data/log.jsonl.

E2EE wrinkle: #bot-noise may be encrypted in prod (TBD). If so the approver can't read commands via raw HTTP. Two paths:

  • (a) Designate a non-encrypted #admin room for commands.
  • (b) Move the approver to mautrix-python, like Paste C, and have it own a real crypto store.

(a) is simpler for v1. (b) is the long-term direction (also unblocks bot self-vetting in encrypted spaces).

Co-admin handoff plan

Once the command surface is live, handing off to a helper admin = three independent grants:

  1. Matrix — give them an account on mtrx.shaperotator.xyz (or accept their existing matrix.org account), invite to space, set PL 50. They administer via !cmd from their own client.
  2. GitHub — add as collaborator on Account-Link/shape-rotator-matrix. They can push branches, review PRs, manage gh secrets if you grant write access to those.
  3. Phala/dstack (optional, only if they need direct CVM access) — share deploy/deploy_key (gives phala ssh); separately, share the phala account if they need to deploy outside the GitHub Actions flow. Most ops should go through CI auto-deploy, so this is rarely needed.

Don't share: @shape-rotator-2's password or access token, your personal ~/.phala-cloud/credentials.json, your hermes-agent staging credentials. Each of those is either revocable per-person elsewhere or shouldn't be admin-owned by anyone but you.

Acceptance

  • !mint (knock + signup) implemented and gates on PL.
  • !codes and !revoke implemented.
  • !ban / !kick / !unban implemented.
  • !stats reads from audit log, returns aggregate counts + top captcha keywords.
  • Decision recorded on E2EE-ness of the admin room (cleartext for v1 vs. mautrix bot).
  • deploy/admin/README.md updated with a "co-admin handoff" section pointing at this issue's plan.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions