Feedback¶
The Feedback extension enables interactive feedback requests across external channels. It sends approval/denial prompts, acknowledgement requests, or free-form questions to Slack, Telegram, Microsoft Teams, email, or a built-in web UI. It collects responses and dispatches them to LimaCharlie subsystems (case notes via ext-cases, playbook triggers via ext-playbook).
Designed for AI-driven and human-initiated workflows where operator approval or input is required before taking an automated action. For example, a D&R rule or playbook can ask a human "Should we isolate host compromised-01?" and wait for a response before proceeding.
Enabling the Extension¶
Navigate to the Feedback extension page in the marketplace. Select the organization you wish to enable it for, and select Subscribe.
On subscription, the extension automatically:
- Creates a webhook adapter for the organization
- Installs a D&R rule that routes feedback responses to the extension for processing
No additional configuration is required. You can immediately start configuring channels and sending feedback requests.
Concepts¶
Channels¶
A channel defines how feedback requests are delivered to respondents. Each channel has a name and a type. Channels are configured through the extension config (see Channel Configuration).
| Channel Type | Description | In-Chat Buttons | Requirements |
|---|---|---|---|
web |
Built-in web UI. Returns a shareable URL that displays the question with response buttons or text input. | N/A | None |
slack |
Sends an interactive Block Kit message to a Slack channel with action buttons. | Yes | A Slack Tailored Output with slack_api_token and slack_channel. See Slack Setup. |
telegram |
Sends a message with inline keyboard buttons to a Telegram chat via Bot API. | Yes | A Telegram Tailored Output with bot_token and chat_id. See Telegram Setup. |
ms_teams |
Sends an Adaptive Card to a Microsoft Teams channel via webhook. A button links to the web UI for response. | No (link to web UI) | A Microsoft Teams Tailored Output with webhook_url. See Microsoft Teams Setup. |
email |
Sends an HTML email with the question and a link to the web approval page. | No (link to web UI) | An SMTP Tailored Output with dest_host, dest_email, from_email, and SMTP credentials. See Email Setup. |
Feedback Types¶
Each feedback type has a dedicated action:
| Feedback Type | Action | UI | Response Values |
|---|---|---|---|
simple_approval |
request_simple_approval |
Approve and Deny buttons | approved or denied |
acknowledgement |
request_acknowledgement |
Acknowledge button | acknowledged |
question |
request_question |
Free-form text input | answered + free-form text |
Feedback Destinations¶
When a respondent answers, the extension dispatches the response to the configured destination:
| Destination | Behavior |
|---|---|
case |
Adds a note to the specified case via ext-cases. Requires a case_id. |
playbook |
Triggers the specified playbook via ext-playbook with the response data. Requires a playbook_name. |
Response Content¶
Each feedback request can include optional JSON data per choice. When the respondent selects a choice, the corresponding content is included in the dispatched response. This allows automation to carry structured payloads through the human decision point.
- For
request_simple_approval, useapproved_contentanddenied_content. - For
request_acknowledgement, useacknowledged_content. - For
request_question, no content fields are available -- the respondent's free-form text IS the response.
Timeouts¶
All feedback actions accept an optional timeout. When timeout_seconds is set (minimum 60), the system automatically responds with a default choice if no human responds before the deadline. The timeout response flows through the same webhook/D&R/dispatch path as a normal response, with responder set to "timeout".
| Parameter | Applies To | Description |
|---|---|---|
timeout_seconds |
All actions | Number of seconds to wait before auto-responding (minimum 60) |
timeout_choice |
request_simple_approval |
Which choice to auto-select: approved or denied. Required when timeout_seconds is set. |
timeout_content |
All actions | JSON data to include in the timeout response (overrides the per-choice content). Required for request_question when timeout_seconds is set. |
For request_acknowledgement, the timeout choice is always acknowledged. For request_question, the timeout choice is always answered and timeout_content provides the automatic answer.
When a timeout is configured, the channel message includes a note like "(Auto-denied in 5 minutes if no response)" so the respondent knows the deadline.
Channel Configuration¶
Channels are managed through the extension config, not via extension actions. You can configure channels through the LimaCharlie web UI (extension settings page), via the CLI, or through infrastructure-as-code with git-sync.
# Add channels individually
limacharlie feedback channel add --name ops --type web
limacharlie feedback channel add --name slack-ops --type slack --output-name my-slack-output
limacharlie feedback channel add --name tg-ops --type telegram --output-name my-telegram-output
limacharlie feedback channel add --name teams-ops --type ms_teams --output-name my-teams-output
limacharlie feedback channel add --name email-ops --type email --output-name my-smtp-output
# List configured channels
limacharlie feedback channel list
# Remove a channel
limacharlie feedback channel remove --name old-channel
echo '{"data":{"channels":[{"name":"ops","channel_type":"web"},{"name":"slack-ops","channel_type":"slack","output_name":"my-slack-output"},{"name":"tg-ops","channel_type":"telegram","output_name":"my-telegram-output"},{"name":"teams-ops","channel_type":"ms_teams","output_name":"my-teams-output"},{"name":"email-ops","channel_type":"email","output_name":"my-smtp-output"}]},"usr_mtd":{"enabled":true}}' | \
limacharlie hive set --hive-name extension_config --key ext-feedback
Channels can be managed via git-sync by including the extension config in your synced repository:
# extension_config/ext-feedback
channels:
- name: ops
channel_type: web
- name: slack-ops
channel_type: slack
output_name: my-slack-output
- name: tg-ops
channel_type: telegram
output_name: my-telegram-output
- name: teams-ops
channel_type: ms_teams
output_name: my-teams-output
- name: email-ops
channel_type: email
output_name: my-smtp-output
For all channel types except web, the output_name field references a LimaCharlie Tailored Output that holds the credentials for the channel.
Sending Feedback Requests¶
Simple Approval¶
The request_simple_approval action sends a question with Approve/Deny buttons.
# Auto-deny after 5 minutes if no human responds
limacharlie feedback request-approval \
--channel ops \
--question "Should we isolate host compromised-01?" \
--destination case --case-id 78 \
--approved-content '{"action": "isolate", "sid": "sensor-abc"}' \
--denied-content '{"action": "skip"}' \
--timeout 300 --timeout-choice denied
limacharlie extension request \
--name ext-feedback \
--action request_simple_approval \
--data '{
"channel": "ops",
"question": "Should we isolate host compromised-01?",
"feedback_destination": "case",
"case_id": "78",
"approved_content": "{\"action\": \"isolate\", \"sid\": \"sensor-abc\"}",
"denied_content": "{\"action\": \"skip\"}"
}'
The response includes:
The url is the shareable link to the web UI where the respondent can answer. For Slack, Telegram, Microsoft Teams, and email channels, no URL is returned in the response -- the message is sent directly to the configured channel.
Acknowledgement¶
The request_acknowledgement action sends a question with an Acknowledge button.
Question (Free-Form Text)¶
The request_question action sends a question with a text input field. The respondent types a free-form answer.
The response event includes choice: "answered" and a text field with the respondent's answer.
D&R Rule Example¶
A D&R rule can request human approval before taking automated action. The response is dispatched to a playbook that performs the action.
Detection:
Response:
- action: extension request
extension name: ext-feedback
extension action: request_simple_approval
extension request:
channel: '{{ "ops-slack" }}'
question: '{{ "Suspicious process detected on " }}{{ .routing.hostname }}{{ ". Isolate host?" }}'
feedback_destination: '{{ "playbook" }}'
playbook_name: '{{ "isolate-host" }}'
approved_content:
action: '{{ "isolate" }}'
sid: routing.sid
denied_content:
action: '{{ "monitor" }}'
sid: routing.sid
timeout_seconds: '{{ 300 }}'
timeout_choice: '{{ "denied" }}'
The timeout_seconds: 300 and timeout_choice: "denied" ensure the rule auto-denies if no one responds within 5 minutes, preventing the workflow from hanging indefinitely.
Playbook Example¶
A playbook can request approval during execution:
def main(lc, data):
import json
# Request human approval with a 5-minute timeout
response = lc.extension_request(
"ext-feedback",
"request_simple_approval",
{
"channel": "ops",
"question": f"Isolate host {data.get('hostname', 'unknown')}?",
"feedback_destination": "playbook",
"playbook_name": "handle-isolation-response",
"approved_content": json.dumps({"action": "isolate", "sid": data.get("sid")}),
"denied_content": json.dumps({"action": "skip"}),
"timeout_seconds": 300,
"timeout_choice": "denied",
},
)
# The response will trigger the handle-isolation-response playbook
# when the human responds (or after 5 minutes with choice="denied"
# and responder="timeout").
return {"request_id": response.get("request_id")}
Response Flow¶
- A feedback request is created and stored with a 7-day TTL
- The question is delivered via the configured channel (Slack message or web URL)
- The respondent clicks a button or submits a text response (or the timeout fires if configured)
- The response is routed through the organization's webhook adapter (authenticated via
lc-secretheader) - A D&R rule matches the response event and triggers the extension's
process_responseaction - The extension atomically claims the request (preventing duplicate processing) and dispatches the response to the configured destination
If a timeout is configured and no human responds before the deadline, the system automatically sends a response with the configured default choice. The timeout response includes responder: "timeout" so downstream automation can distinguish it from human responses.
Feedback requests expire after 7 days. Expired requests show an error in the web UI and are rejected by the extension.
Responses are protected against replay: once a response is processed, any duplicate deliveries (from webhook retries or replay) are rejected. This also prevents races between a human response and a timeout firing simultaneously -- whichever is processed first claims the request.
Slack Setup¶
To use Slack channels:
- Create a Slack App with "Interactivity & Shortcuts" enabled
- Set the Request URL to the Slack callback endpoint:
https://feedback-system.limacharlie.io/callback/slack - Install the app to your Slack workspace and note the Bot User OAuth Token
- In LimaCharlie, create a Slack Tailored Output with:
slack_api_token: the Bot User OAuth Tokenslack_channel: the target channel (e.g.#security-ops)
- Add a Slack channel to your extension config referencing the output name (see Channel Configuration). For example, a channel with
name: "ops",channel_type: "slack", andoutput_name: "my-slack-output".
Note
For request_question feedback type, Slack shows a "Respond" button that links to the web UI, since Slack interactive messages do not support inline text input fields.
Telegram Setup¶
To use Telegram channels, you need a Telegram bot and a LimaCharlie Tailored Output with its credentials.
Step 1: Create a Telegram Bot¶
- Open Telegram and start a conversation with @BotFather (Telegram Bot API documentation)
- Send
/newbotand follow the prompts to choose a name and username - BotFather will respond with a bot token (e.g.
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11). Save this token. - Add the bot to the Telegram group or channel where you want feedback messages delivered
- Get the chat ID of the group or channel. You can do this by:
- Adding the bot to the group, sending a message, then checking
https://api.telegram.org/bot<TOKEN>/getUpdatesfor thechat.idfield - For channels, the chat ID is typically a negative number like
-1001234567890
- Adding the bot to the group, sending a message, then checking
For more information, see the Telegram Bot API documentation.
Step 2: Create a Tailored Output¶
In LimaCharlie, create a Telegram Tailored Output with:
bot_token: the bot token from BotFatherchat_id: the target chat, group, or channel ID
Step 3: Add a Telegram Channel¶
Add a channel to your extension config referencing the output name:
How Telegram Responses Work¶
For simple_approval and acknowledgement feedback types, Telegram messages include inline keyboard buttons (Approve/Deny or Acknowledge) that the respondent can tap directly in the chat. The response is processed immediately without leaving Telegram.
For request_question, a "Respond" button links to the web UI since Telegram inline keyboards do not support text input.
When a response is received, the original Telegram message is updated to show the choice and who responded.
Note
The extension automatically registers a webhook with the Telegram bot (using setWebhook) to receive button-click callbacks. If the bot is also used for other webhook-based integrations, the ext-feedback webhook registration will override the existing one. Use a dedicated bot for ext-feedback if this is a concern.
Microsoft Teams Setup¶
To use Microsoft Teams channels, you need a Teams Workflow webhook URL and a LimaCharlie Tailored Output.
Incoming Webhooks retired
Microsoft retired Office 365 Connectors (including Incoming Webhooks) from Teams. You must use a Power Automate Workflow as described below.
Create a Workflow Webhook¶
- In Microsoft Teams, navigate to the channel where you want feedback messages
- Click ... (More options) next to the channel name
- Select Workflows
- Search for and select the Send webhook alerts to a channel template
- Give the workflow a name (e.g. "LimaCharlie Feedback") and authenticate your account
- Click Next, confirm the Team and Channel, then click Add workflow
- Copy the webhook URL from the confirmation dialog
For details, see Create incoming webhooks with Workflows.
Create the Tailored Output¶
In LimaCharlie, create a Microsoft Teams Tailored Output with:
webhook_url: the Teams webhook URL (from either option above)
Add a Teams Channel¶
Add a channel to your extension config referencing the output name:
How Teams Responses Work¶
Feedback requests are delivered as Adaptive Cards in the Teams channel. The card displays the question and a button that opens the web approval page in a browser. Responses are collected through the web UI.
Email Setup¶
To use email channels, you need an SMTP server and a LimaCharlie Tailored Output with its credentials.
Create a Tailored Output¶
In LimaCharlie, create an SMTP Tailored Output with:
dest_host: SMTP server address, optionally with port (e.g.smtp.example.com:587). Defaults to port 587 if not specified.dest_email: the recipient email address (e.g.soc@example.com)from_email: the sender email address (e.g.limacharlie@example.com)username(optional): SMTP authentication usernamepassword(optional): SMTP authentication password
Add an Email Channel¶
Add a channel to your extension config referencing the output name:
How Email Responses Work¶
The extension sends an HTML email containing the feedback question and a Respond button that links to the web approval page. Responses are collected through the web UI.
Actions Reference¶
| Action | User-facing | Description |
|---|---|---|
request_simple_approval |
Yes | Send a feedback request with Approve/Deny buttons |
request_acknowledgement |
Yes | Send a feedback request with an Acknowledge button |
request_question |
Yes | Send a question with a free-form text input |
process_response |
No | Internal: processes a response received via webhook |
request_simple_approval Parameters¶
| Parameter | Required | Description |
|---|---|---|
channel |
Yes | Name of the feedback channel |
question |
Yes | The question or prompt to present |
feedback_destination |
Yes | case or playbook |
case_id |
When destination is case |
Case to add the response note to |
playbook_name |
When destination is playbook |
Playbook to trigger with the response |
approved_content |
No | JSON data included when the respondent approves |
denied_content |
No | JSON data included when the respondent denies |
timeout_seconds |
No | Auto-respond after this many seconds if no response (minimum 60) |
timeout_choice |
When timeout_seconds is set |
Choice to auto-select on timeout: approved or denied |
timeout_content |
No | JSON data for the timeout response (overrides the choice's content) |
request_acknowledgement Parameters¶
| Parameter | Required | Description |
|---|---|---|
channel |
Yes | Name of the feedback channel |
question |
Yes | The question or prompt to present |
feedback_destination |
Yes | case or playbook |
case_id |
When destination is case |
Case to add the response note to |
playbook_name |
When destination is playbook |
Playbook to trigger with the response |
acknowledged_content |
No | JSON data included when the respondent acknowledges |
timeout_seconds |
No | Auto-acknowledge after this many seconds if no response (minimum 60) |
timeout_content |
No | JSON data for the timeout response (overrides acknowledged_content) |
request_question Parameters¶
| Parameter | Required | Description |
|---|---|---|
channel |
Yes | Name of the feedback channel |
question |
Yes | The question or prompt to present |
feedback_destination |
Yes | case or playbook |
case_id |
When destination is case |
Case to add the response note to |
playbook_name |
When destination is playbook |
Playbook to trigger with the response |
timeout_seconds |
No | Auto-answer after this many seconds if no response (minimum 60) |
timeout_content |
When timeout_seconds is set |
JSON data used as the automatic answer on timeout (required for question type) |