namespace App\DiscordBotCommands;
 
+use App\Models\ChannelCrew;
 use App\Models\DiscordBotCommand;
 use App\Models\DiscordGuild;
 use App\Models\Episode;
+use App\Models\EpisodeCrew;
 use App\Models\Round;
 use App\Models\User;
 use Discord\Discord;
                switch ($cmd->command) {
                        case 'cancel-event':
                                return new CancelEventCommand($discord, $cmd);
+                       case 'crew-signup-notify':
+                               return new CrewSignupNotifyCommand($discord, $cmd);
                        case 'episode-event':
                                return new EpisodeEventCommand($discord, $cmd);
                        case 'message':
                return $this->command->parameters[$name];
        }
 
+       protected function getCrew(): EpisodeCrew {
+               if (!$this->hasParameter('crew')) {
+                       throw new \Exception('no crew in parameters');
+               }
+               return EpisodeCrew::query()->findOrFail($this->getParameter('crew'));
+       }
+
        protected function getEpisode(): Episode {
                if (!$this->hasParameter('episode')) {
                        throw new \Exception('no episode in parameters');
                }
-               return Episode::findOrFail($this->getParameter('episode'));
+               return Episode::query()->findOrFail($this->getParameter('episode'));
        }
 
        protected function getRound(): Round {
 
--- /dev/null
+<?php
+
+namespace App\DiscordBotCommands;
+
+use App\Models\DiscordBotCommand;
+use Carbon\Carbon;
+use Discord\Discord;
+use Discord\Parts\User\User;
+use React\Promise\PromiseInterface;
+
+class CrewSignupNotifyCommand extends BaseCommand {
+
+       public function __construct(Discord $discord, DiscordBotCommand $cmd) {
+               parent::__construct($discord, $cmd);
+       }
+
+       public function execute(): PromiseInterface {
+               return $this->fetchUser()
+                       ->then(function (User $user) {
+                               $crew = $this->getCrew();
+                               // TODO: l10n
+                               $text = '<@'.$crew->user_id.'> signed up for '.$crew->role.' on '
+                                       .'['.$crew->episode->getScheduledEventName().']('.$crew->episode->event->getURL().')'
+                                       .' (<t:'.Carbon::parse($crew->episode->start)->timestamp.':F>)';
+                               return $user->sendMessage($text);
+                       });
+       }
+
+}
 
 namespace App\Http\Controllers;
 
 use App\Models\Channel;
+use App\Models\DiscordBotCommand;
 use App\Models\Event;
 use App\Models\Episode;
 use App\Models\EpisodeCrew;
                        }
                }
 
-               $episode->crew()->create([
+               $crew = $episode->crew()->create([
                        'channel_id' => $channel->id,
                        'role' => $as,
                        'user_id' => $user->id,
                ]);
 
+               foreach ($channel->crews as $channel_crew) {
+                       if ($channel_crew->wantsSignupNotifications()) {
+                               DiscordBotCommand::crewSignupNotify($channel_crew->user, $crew);
+                       }
+               }
+
                if ($user->isPrivileged()) {
                        return $episode->load(['crew', 'crew.user'])->toJson();
                } else {
 
                return $this->belongsTo(User::class);
        }
 
+
+       public function wantsSignupNotifications() {
+               return true;
+       }
+
        protected $casts = [
                'user_id' => 'string',
        ];
 
                return $cmd;
        }
 
+       public static function crewSignupNotify(User $user, EpisodeCrew $crew): DiscordBotCommand {
+               $cmd = new DiscordBotCommand();
+               $cmd->command = 'crew-signup-notify';
+               $cmd->parameters = [
+                       'crew' => $crew->id,
+                       'user' => $user->id,
+               ];
+               $cmd->status = 'pending';
+               $cmd->save();
+               return $cmd;
+       }
+
        public static function episodeEvent(DiscordGuild $guild, Episode $episode): DiscordBotCommand {
                $cmd = new DiscordBotCommand();
                $cmd->discord_guild()->associate($guild);