diff --git a/README.md b/README.md
index 80a6dfa9..d9614a92 100644
--- a/README.md
+++ b/README.md
@@ -328,6 +328,33 @@ ___
+## Provider-agnostic push outputs and Slack relay
+
+PR-Agent can optionally emit review results to external sinks without calling git provider APIs.
+This is disabled by default. To enable and forward to Slack via a lightweight relay:
+
+1) Start the relay (in a separate shell):
+ - Set an Incoming Webhook URL for Slack:
+ - CMD: set SLACK_WEBHOOK_URL=https://hooks.slack.com/services/TXXXX/BXXXX/XXXXXXXX
+ - PS: $env:SLACK_WEBHOOK_URL="https://hooks.slack.com/services/TXXXX/BXXXX/XXXXXXXX"
+ - Run:
+ uvicorn pr_agent.servers.push_outputs_relay:app --host 0.0.0.0 --port 8000
+
+2) In your repository, configure PR-Agent to emit to the relay by creating .pr_agent.toml:
+
+```
+[push_outputs]
+enable = true
+channels = ["webhook"]
+webhook_url = "http://localhost:8000/relay"
+presentation = "markdown"
+```
+
+Notes:
+- This mechanism is provider-agnostic and uses minimal API calls.
+- You can also use the "file" channel to append JSONL records locally.
+- The relay transforms the generic payload into Slack’s Incoming Webhook schema.
+
## Try It Now
Try the GPT-5 powered PR-Agent instantly on _your public GitHub repository_. Just mention `@CodiumAI-Agent` and add the desired command in any PR comment. The agent will generate a response based on your command.
diff --git a/pr_agent/servers/push_outputs_relay.py b/pr_agent/servers/push_outputs_relay.py
index bd281668..c2b6818b 100644
--- a/pr_agent/servers/push_outputs_relay.py
+++ b/pr_agent/servers/push_outputs_relay.py
@@ -70,10 +70,21 @@ async def relay(record: Dict[str, Any]):
text = _to_slack_text(record)
- body = {
- "text": text,
- "mrkdwn": True,
- }
+ # If using a Slack Workflow "triggers" URL, the workflow expects top-level fields
+ # that match the configured variables in the Workflow (e.g., "markdown", "payload").
+ # Otherwise, for Incoming Webhooks ("services" URL), use the standard {text, mrkdwn}.
+ if "hooks.slack.com/triggers/" in slack_url:
+ body = {
+ # Map our computed text to the workflow variable named "markdown"
+ "markdown": text,
+ # Provide original payload if the workflow defines a variable for it
+ "payload": record.get("payload", {}),
+ }
+ else:
+ body = {
+ "text": text,
+ "mrkdwn": True,
+ }
try:
resp = requests.post(slack_url, json=body, timeout=8)