A slack webhook integration that lets your team play cards against humanity

dev-master / 1.4.x-dev 2015-12-29 20:27 UTC



Slack Against Humanity is a Slack/Hubot implementation of the popular card game, Cards Against Humanity. Commands are issued in your slack channel via Custom Slash Commands, Github's Hubot, or a combination of both and then passed to this package. Cards will be dealt, Judges are picked at random, and who plays what card is kept secret until the end (if they win!).

  • This is Cards Against Humanity. If you have sensibilities that are easily offended, this game is NOT FOR YOU.
  • All commands are issued via GET and POST requests against a web API
  • 763 included cards!
  • 103 Black Cards
  • 660 White Cards
  • A randomly picked Judge each round
  • Ability to enter and exit play on your time
  • Laravel 5.x compatibility
  • Intelligence on who is actually playing or not
  • with many more features in the works.

Latest Stable Version Total Downloads Latest Unstable Version License SensioLabsInsight ghit.me

Anybody that wants to play needs to be dealt in. A check happens on every deal, and every new round that 3 people are playing. CAH with 2 people is kinda boring. Don't like your cards? Too bad, no cheating here.


Once there have been dealt in, a Judge is chosen at random, and a Black card is chosen at random. Everybody except the Judge needs to play a white card from their hand.


After each player plays a card a check happens to see if everybody who can play, did play. If they did, it's time to pick a winner! Only the Judge is allowed to choose the winner.


Everybody who played a card is then dealt a new card. And it starts all over again.



In it's current state, this package expects that you have set up Maknz/Slack on your own. This includes setting up the facade Slack:: as well as set up a #cards channel in Slack.

Require this package in your composer.json and update composer.

"hopkins/slack-against-humanity": "~0.5"

After updating composer, add the ServiceProvider to the providers array in app/config/app.php


Run the artisan command to bring the migrations and see files into your source db

php artisan vendor:publish

Make a new CardsController that extends the controller in the package

    <?php namespace Idop\Http\Controllers;

    use Hopkins\SlackAgainstHumanity\Game\BaseCardsController;

    class CardsController extends BaseCardsController{}

You will also need to add the below into your routes.php file

    Route::group(['prefix' => 'cards'], function () {
        Route::get('deal', 'CardsController@deal');
        Route::get('start', 'CardsController@start');
        Route::get('show', 'CardsController@show');
        Route::post('play', 'CardsController@play');
        Route::post('choose', 'CardsController@choose');
        Route::get('quit', 'CardsController@quit');

Players can use public messages to trigger all of these endpoints except for Route::post('play',...). This needs to played in secret. A Custom Slash Command is perfect for this. 687474703a2f2f692e696d6775722e636f6d2f614e65613441582e706e67

We use our hubot, Sterling, to play the other commands. The coffee script is a fairly simple one to make it work.

    # Description:
    #   Cards Against Humanity!
    # Dependencies:
    #   None
    # Commands:
    #   hubot cards deal - adds you to the current cards game
    #   hubot cards quit - removes you from the current cards game
    #   hubot cards show - messages you your cards again incase you forgot
    #   /cards {id} - plays the id of your chosen card for the current round (a slack slash command is taking care of it though)
    #   hubot cards choose {id} - The current round's judge chooses the best card against the pre determined black card
    #   hubot cards status - Returns the current rounds judge, and any players who have not yet played a card
    # Author:
    #   michael-hopkins
    url = "http://idop.appit.ventures/cards/"
    module.exports = (sterling) ->
      sterling.respond /cards deal/i, (msg) ->
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room}
        sterling.http(url+"deal").query(data).get() (err, res, body) ->
      sterling.respond /cards start/i, (msg) ->
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room}
        sterling.http(url+"start").query(data).get() (err, res, body) ->
      sterling.respond /cards quit/i, (msg) ->
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room}
        sterling.http(url+"quit").query(data).get() (err, res, body) ->
      sterling.respond /cards show/i, (msg) ->
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room}
        sterling.http(url+"show").query(data).get() (err, res, body) ->
      sterling.respond /cards choose (.*)/i, (msg) ->
        cardId = msg.match[1]
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room,'cardId': cardId}
        sterling.http(url+"choose").query(data).get() (err, res, body) ->
      sterling.respond /cards status/i, (msg) ->
        data = {'user_name': msg.message.user.name,'room': msg.message.user.room}
        sterling.http(url+"status").query(data).get() (err, res, body) ->


  • Add in tests to verify complete functioning package
  • Black cards that require 2 cards (and more) from each player
  • Using an image processing library to generate an actual "card" instead of just a message
  • Remove or build in, dependancy of maknz/flash, instead of trusting it's already implemented
  • Add configuration for which room to play SAH in instead of assuming #cards
  • Automate controllers and routes so the user doesn't need to interfere


This project is licensed using DBAD. Go have a blast.