No description
  • Rust 88.5%
  • Nix 11.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
yuuhikaze 687cc46c97 fix: exit on setup failure so systemd can retry
poise leaves the gateway connected after a failed setup, turning the
bot into a zombie that Restart=always never restarts.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JNyCHDUPAUa3UuVqVfpozk
2026-07-30 10:42:38 -05:00
nix feat: role-based access instead of a single friend ID 2026-07-30 03:50:41 -05:00
src fix: exit on setup failure so systemd can retry 2026-07-30 10:42:38 -05:00
.gitignore feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
Cargo.lock feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
Cargo.toml feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
flake.lock feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
flake.nix feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
LICENSE feat: initial yobidashi Discord companion-control bot 2026-07-30 03:37:57 -05:00
README.md feat: role-based access instead of a single friend ID 2026-07-30 03:50:41 -05:00

yobidashi

呼び出し — the caller who summons the wrestlers into the ring.

Discord control plane for a self-hosted AI companion stack running on a remote GPU machine. A pinned dashboard message shows per-component state (🏮 awake / 🌑 asleep) with buttons to summon, dismiss, and revive; sensitive operations go through an admin approval gate; startup console output is streamed live into the channel.

How it works

  • The bot runs on an always-on host and drives the GPU machine over SSH, calling a companion lifecycle script there (start, stop, status, start-component <x>).
  • The pinned dashboard message is the only persistence: on startup the bot adopts its own pinned message (or creates one), so restarts lose nothing.
  • Buttons work for the admin and for members of a configurable Discord role — granting someone access is a role assignment, not a config change.
  • Summon/Dismiss by anyone other than the admin posts an approval request with buttons; no answer within 10 minutes counts as approval.
  • Revive buttons skip approval but are only enabled while the stack is partially up — they can resuscitate a crashed component, never cold-start.
  • If the GPU machine does not answer ping, the requester is told to ask the admin to power it on.

Configuration

Environment variables (the NixOS module sets these):

Variable Meaning
DISCORD_TOKEN Bot token
YOBIDASHI_GUILD_ID Guild the bot operates in
YOBIDASHI_CHANNEL_ID Control channel (dashboard lives here)
YOBIDASHI_ADMIN_ID Admin user ID (approvals)
YOBIDASHI_ROLE_ID Role whose members may operate the dashboard (mentioned in notices; make it mentionable)
YOBIDASHI_ADMIN_NAME Admin display name in messages
YOBIDASHI_SSH_TARGET user@host of the GPU machine
YOBIDASHI_COMPANION_CMD Lifecycle command on the target (default companion)
YOBIDASHI_SSH_KEY SSH private key path (default: systemd credential ssh-key)

NixOS

The flake exports nixosModules.default:

services.yobidashi = {
  enable = true;
  settings = {
    guildId = "…";
    channelId = "…";
    adminId = "…";
    roleId = "…";
    adminName = "Steven";
    sshTarget = "[email protected]";
  };
  environmentFile = config.sops.secrets."yobidashi/env".path;
};

The service loads the host's ed25519 key as its SSH identity by default (sshKeyFile); authorize that key on the target machine.

Discord setup

Create an application + bot, invite it with the bot and applications.commands scopes and permissions to send messages, embed links, and manage messages (for pinning) in the control channel. The bot needs no privileged gateway intents.