{"id":25417348,"url":"https://github.com/kenjij/mos-eisley-lambda","last_synced_at":"2026-04-29T17:02:46.254Z","repository":{"id":56884551,"uuid":"351539562","full_name":"kenjij/mos-eisley-lambda","owner":"kenjij","description":"\"You will never find a more wretched hive of scum and villainy.\" (Slack bot framework ep. 2—AWS Lambda)","archived":false,"fork":false,"pushed_at":"2022-11-03T04:50:48.000Z","size":48,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-29T16:50:42.305Z","etag":null,"topics":["aws-lambda","bot","bot-framework","ruby","slack"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kenjij.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-25T18:37:40.000Z","updated_at":"2022-02-25T00:11:42.000Z","dependencies_parsed_at":"2023-01-21T11:46:51.534Z","dependency_job_id":null,"html_url":"https://github.com/kenjij/mos-eisley-lambda","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjij%2Fmos-eisley-lambda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjij%2Fmos-eisley-lambda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjij%2Fmos-eisley-lambda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjij%2Fmos-eisley-lambda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenjij","download_url":"https://codeload.github.com/kenjij/mos-eisley-lambda/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251572862,"owners_count":21611198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-lambda","bot","bot-framework","ruby","slack"],"created_at":"2025-02-16T17:38:37.144Z","updated_at":"2026-04-29T17:02:41.212Z","avatar_url":"https://github.com/kenjij.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mos-eisley-lambda\n\n[![Gem Version](https://badge.fury.io/rb/mos-eisley-lambda.svg)](http://badge.fury.io/rb/mos-eisley-lambda) \n\n“You will never find a more wretched hive of scum and villainy.” – Obi-Wan Kenobi\n\nEpisode 2 of the Ruby based [Slack app](https://api.slack.com/) framework, this time for [AWS Lambda](https://aws.amazon.com/lambda/). Pure Ruby, no external gem/library dependency.\n\n## Setup\n\n### AWS\n\n1. Create an IAM role for MosEisley Lambda function\n1. Create a Lambda function for MosEisley\n   - You can install this gem using [Lambda Layer](#using-with-lambda-layers) or just copy the `lib` directory to your Lambda code.\n1. Create an HTTP API Gateway\n   1. Create the appropriate routes (or use [the OpenAPI spec](https://github.com/kenjij/mos-eisley-lambda/blob/main/openapi3.yaml))\n   1. Create Lambda integration and attach it to all the routes\n\nConfigure Lambda environment variable.\n\n- `SLACK_CREDENTIALS_SSMPS_PATH`: hierarchy path to System Managers Parameter Store; e.g., `/slack/credentials/` would reference two parameters:\n  - `/slack/credetials/signing_secret`\n  - `/slack/credetials/bot_access_token`\n- `MOSEISLEY_HANDLERS_DIR`: _optional_, if other than `./handlers` \n- `MOSEISLEY_LOG_LEVEL`: _optional_, could be `DEBUG`, `INFO`, `WARN`, or `ERROR` \n- `SLACK_LOG_CHANNEL_ID`: _optional_, if you want to use `ME::SlackWeb.post_log()`\n\nConfigure Lambda code in your `lambda_function.rb` file.\n\n```ruby\nrequire 'mos-eisley-lambda'\n# Or, you can just copy the `lib` directory to your Lambda and...\n# require_relative './lib/mos-eisley-lambda'\n\ndef lambda_handler(event:, context:)\n  MosEisley::lambda_event(event, context)\nend\n```\n\n### Slack\n\nCreate a Slack app and configure the following.\n\n- **Interactivity \u0026 Shortcuts** – Request URL should be set to the `/actions` endpoint and Options Load URL should be set to the `/menus` endpoint.\n- **Slash Commands** – Request URL should be set to the `/commands` endpoint.\n- **OAuth \u0026 Permissions** – This is where you get the OAuth Tokens and set Scopes.\n- **Event Subscriptions** – Request URL should be set to the `/events` endpoint. You'll likely Subscribe to bot events `app_mention` at a minimum.\n\n### Handlers\n\nCreate your own Mos Eisley handlers as blocks and register them. By default, store these Ruby files in the `handlers` directory. Add handlers by passing a block to `MosEisley::Handler.add()` for the types below.\n\n```ruby\n:action\n:command_response\n:command\n:event\n:menu\n:nonslack\n```\n\n`:command_response` types are Slack command keyword and response pair. The response is sent as-is back to Slack as an [immediate response](https://api.slack.com/interactivity/slash-commands#responding_immediate_response). `ME` is an alias to `MosEisley`.\n\n```ruby\nME::Handler.add(:command_response, '/sample') do |event, myself|\n  {\n    response_type: \"in_channel\",\n    text: \"_Working on `#{event[:command]}`..._\",\n  }\nend\n```\n\nAdd handlers to process the Slack event.\n\n```ruby\nME::Handler.add(:command, 'A Slack command') do |event, myself|\n  next unless event[:command] == '/command'\n  myself.stop\n  txt = \"Your wish is my command.\"\n  payload = {\n    response_type: 'ephemeral',\n    text: txt,\n    blocks: [ME::S3PO::BlockKit.sec_text(txt)],\n  }\n  ME::SlackWeb.post_response_url(event[:response_url], payload)\nend\n```\n\nIf your function receives non-Slack events, you can add handlers for that as well.\n\n```ruby\nME::Handler.add(:nonslack, 'A CloudWatch event') do |event, myself|\n  next unless event['source'] == 'aws.events'\n  myself.stop\n  channel = 'C123SLCK'\n  txt = 'Shceduled event was received.'\n  ME::SlackWeb.chat_postmessage(channel: channel, text: txt)\nend\n```\n\n### Helpers\n\n- `MosEisley::S3PO` – collection of helpers to analyze/create Slack messages.\n- `MosEisley::SlackWeb` – methods for sending payloads to Slack Web API calls.\n\n## Event Lifecycle\n\n### Inbound\n\nTo an incoming Slack event, Mos Eisley will quickly respond with a blank HTTP 200. This is to keep [Slack's 3-second rule](https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events). To do this, handlers are not called yet, but the Slack event is passed on to a recursive asynchronous invoke and then the handlers are called.\n\nThe exception is when the incoming Slack event is for a slash command. You can define `:command_response` handlers for the purpose of generating a simple response message, but nothing more.\n\n```mermaid\nsequenceDiagram\n  participant S as Slack\n  participant L as Lambda MosEisley\n  S-\u003e\u003e+L: Slack event via API Gateway\n  alt Slash command\n    L--\u003e\u003eS: Response message\n    Note left of L: If a response handler is defined\n  else All other events\n    L--\u003e\u003e-S: HTTP 200 (blank)\n  end\n  L-\u003e\u003e+L: Slack event\n  Note right of L: Handlers are called\n  opt\n  L--\u003e\u003e-S: E.g., chat.postMessage\n  end\n```\n\n\u003c!-- ### Outbound, Messaging Only\n\nInvoke the function from another app to send a Slack message\n\n1. Create a Slack message packaged to be sent to the API and invoke the function\n1. Message is received, then sent to Slack API according to payload--\u003e\n\n## Using with Lambda Layers\n\nUsed the Makefile to create a zip file which can be uploaded to a Lambda Layer.\n\n```sh\nmake\n# Installs the gem to './ruby' then archives it to 'lambda-layers.zip'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjij%2Fmos-eisley-lambda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenjij%2Fmos-eisley-lambda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjij%2Fmos-eisley-lambda/lists"}