Rebuild Vibeflow as an n8n safety gate

This commit is contained in:
Felipe Domingues 2026-07-22 11:43:41 -03:00
parent 79fc67166a
commit febec32131
101 changed files with 2405 additions and 3557 deletions

View file

@ -1,10 +0,0 @@
# Example Briefs
## Example 1
Create an n8n workflow that receives leads from a webhook, scores them with AI, sends hot leads to Slack, and stores everything in HubSpot.
## Example 2
Create a workflow that runs every weekday at 8 AM, pulls yesterday's orders from an API, summarizes key metrics, and posts the summary to Microsoft Teams.
## Example 3
Create a workflow that watches Gmail for invoices, extracts key information with AI, stores structured records in Airtable, and alerts finance when the amount is above a threshold.

View file

@ -1,30 +0,0 @@
# Example Final Report
## Summary
A workflow named `Lead Intake and Triage` was created to receive incoming lead data, score urgency using AI, send high-priority leads to Slack, and store all leads in HubSpot.
## What was created
- Webhook trigger for incoming lead payloads
- Validation step for required lead fields
- AI scoring and summarization step
- Conditional branch for hot leads
- Slack notification for hot leads
- HubSpot create/update action
- Generic failure notification path
## Assumptions used
- Lead uniqueness is based on email
- Slack notifications are required only for hot leads
- Missing optional fields do not block processing
## Manual setup still required
- Connect OpenAI credentials
- Connect Slack credentials
- Connect HubSpot credentials
- Review final field mappings for HubSpot properties
## How to test
1. Send a sample payload to the webhook
2. Confirm the AI score is produced
3. Verify hot leads appear in Slack
4. Verify the record is stored in HubSpot

View file

@ -1,29 +0,0 @@
# Example Plans
## Example 1 Plan
- Workflow name: Lead Intake and Triage
- Trigger: Webhook
- Systems: Webhook, OpenAI, Slack, HubSpot
- Steps:
- Receive lead payload
- Validate required fields
- Score and summarize with AI
- Branch on urgency
- Notify Slack for hot leads
- Upsert lead in HubSpot
- Error handling:
- Return validation error on missing fields
- Send Slack alert on workflow failure
## Example 2 Plan
- Workflow name: Daily Orders Digest
- Trigger: Schedule weekdays 08:00
- Systems: HTTP API, Code/Transform, Microsoft Teams
- Steps:
- Run on schedule
- Fetch yesterday's orders
- Aggregate totals and deltas
- Generate concise summary
- Post digest to Teams

View file

@ -1,39 +0,0 @@
# Example Walkthroughs
## Walkthrough 1: Lead qualification
### User request
Create an n8n workflow that receives a website lead, summarizes the lead using AI, classifies urgency, sends hot leads to Slack, and saves all leads in Airtable.
### Agent follow-up questions
1. What triggers the workflow: webhook, form, or CRM event?
2. How should a hot lead be defined?
3. Should Airtable create new records only or update existing ones?
4. Which Slack channel should receive hot leads?
### Normalized plan summary
- trigger: webhook
- systems: OpenAI, Slack, Airtable
- duplicate strategy: upsert by email
- alert rule: hot if urgency score >= 8
- fallback: notify ops on failure
### Delivery excerpt
Workflow created with webhook trigger, AI enrichment, urgency classification, hot lead branch, Slack notification, Airtable upsert path, and failure alert stub.
## Walkthrough 2: Weekly finance digest
### User request
Every Monday morning, collect unpaid invoices from the ERP, summarize totals by customer, and send the finance team a Slack digest.
### Critical follow-ups
1. What ERP or source system holds the invoice data?
2. What timezone should Monday morning use?
3. Should the digest include overdue aging buckets?
4. Is Slack the only output?
### Plan summary
- trigger: schedule weekly
- output: internal Slack digest
- data grouping: by customer and due bucket
- caution: no customer-facing messages

View file

@ -0,0 +1,99 @@
{
"name": "Safe support agent",
"nodes": [
{
"id": "webhook",
"name": "Authenticated Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": { "authentication": "headerAuth", "path": "support" },
"credentials": { "httpHeaderAuth": { "id": "credential-reference", "name": "Webhook Header Auth" } }
},
{
"id": "dedupe",
"name": "Claim idempotency event",
"type": "n8n-nodes-base.postgres",
"onError": "continueErrorOutput",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO event_ledger (event_id) VALUES ($1) ON CONFLICT (event_id) DO NOTHING RETURNING event_id",
"queryReplacement": "={{ $json.event_id }}"
},
"credentials": { "postgres": { "id": "credential-reference", "name": "Event Ledger" } }
},
{
"id": "ledger-failure",
"name": "Ledger failure stop",
"type": "n8n-nodes-base.noOp",
"parameters": {}
},
{
"id": "enabled",
"name": "Agent enabled kill switch",
"type": "n8n-nodes-base.if",
"parameters": { "conditions": { "boolean": [{ "value1": "={{ $json.agent_enabled }}", "value2": true }] } }
},
{
"id": "agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"parameters": { "text": "={{ $json.body.message }}" }
},
{
"id": "model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"parameters": { "modelName": "gpt-4.1-mini" },
"credentials": { "openAiApi": { "id": "credential-reference", "name": "OpenAI" } }
},
{
"id": "confidence",
"name": "Confidence gate",
"type": "n8n-nodes-base.if",
"parameters": { "conditions": { "number": [{ "value1": "={{ $json.confidence }}", "operation": "smaller", "value2": 0.7 }] } }
},
{
"id": "handoff",
"name": "Human handoff ticket",
"type": "n8n-nodes-base.slack",
"onError": "continueErrorOutput",
"parameters": { "channel": "support", "text": "={{ $json.summary }}" }
},
{
"id": "handoff-failure",
"name": "Handoff failure stop",
"type": "n8n-nodes-base.noOp",
"parameters": {}
},
{
"id": "response",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"parameters": { "respondWith": "json", "responseBody": "={{ $json }}" }
}
],
"connections": {
"Authenticated Webhook": { "main": [[{ "node": "Claim idempotency event", "type": "main", "index": 0 }]] },
"Claim idempotency event": {
"main": [
[{ "node": "Agent enabled kill switch", "type": "main", "index": 0 }],
[{ "node": "Ledger failure stop", "type": "main", "index": 0 }]
]
},
"Agent enabled kill switch": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }], []] },
"OpenAI Chat Model": { "ai_languageModel": [[{ "node": "AI Agent", "type": "ai_languageModel", "index": 0 }]] },
"AI Agent": { "main": [[{ "node": "Confidence gate", "type": "main", "index": 0 }]] },
"Confidence gate": {
"main": [
[{ "node": "Human handoff ticket", "type": "main", "index": 0 }],
[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]
]
},
"Human handoff ticket": {
"main": [
[],
[{ "node": "Handoff failure stop", "type": "main", "index": 0 }]
]
}
},
"settings": { "executionTimeout": 120 }
}

View file

@ -1,105 +0,0 @@
{
"plan_version": "0.3.0",
"workflow_name": "Typeform Lead Triage",
"objective": "Capture new Typeform submissions, summarize with AI, classify lead temperature, notify Slack for hot leads, and store all submissions in Airtable.",
"trigger": {
"type": "typeform_submission",
"summary": "Runs whenever a new Typeform response is received.",
"input_shape": "Form response payload with contact, answers, and metadata."
},
"systems": [
"Typeform",
"OpenAI",
"Slack",
"Airtable",
"n8n"
],
"steps": [
{
"id": "step_1",
"name": "Receive submission",
"action": "Read the incoming Typeform payload."
},
{
"id": "step_2",
"name": "Summarize content",
"action": "Generate a concise summary with AI.",
"depends_on": [
"step_1"
]
},
{
"id": "step_3",
"name": "Classify lead",
"action": "Assign hot, warm, or cold label.",
"depends_on": [
"step_2"
]
},
{
"id": "step_4",
"name": "Branch urgent leads",
"action": "If hot, send a Slack alert.",
"depends_on": [
"step_3"
]
},
{
"id": "step_5",
"name": "Persist record",
"action": "Write all leads to Airtable.",
"depends_on": [
"step_3"
]
}
],
"branching": [
{
"condition": "lead_temperature == 'hot'",
"path": "notify_slack"
},
{
"condition": "lead_temperature != 'hot'",
"path": "skip_slack"
}
],
"credentials": [
{
"system": "Typeform",
"status": "required"
},
{
"system": "OpenAI",
"status": "required"
},
{
"system": "Slack",
"status": "required"
},
{
"system": "Airtable",
"status": "required"
}
],
"assumptions": [
"The Typeform payload includes enough text to summarize.",
"Slack alerting is only required for hot leads.",
"Airtable base and table are already chosen by the user."
],
"risks": [
"Missing credentials block full end-to-end testing.",
"Lead classification thresholds may need tuning after first runs."
],
"validation": {
"checks": [
"Confirm the Typeform trigger fires with a real payload.",
"Confirm AI output contains both summary and label.",
"Confirm Slack only receives hot leads.",
"Confirm Airtable receives every submission."
],
"manual_steps": [
"Connect credentials in n8n if placeholders were used.",
"Review the prompt used for classification before production rollout."
]
}
}

View file

@ -1,57 +0,0 @@
{
"name": "Vibeflow Demo - Support Escalation",
"active": false,
"meta": {
"source": "vibeflow-n8n",
"note": "Illustrative export skeleton for documentation and local experimentation."
},
"nodes": [
{
"id": "Webhook_1",
"name": "Incoming Ticket",
"type": "n8n-nodes-base.webhook",
"position": [260, 280],
"parameters": {
"path": "support-escalation-demo",
"httpMethod": "POST"
}
},
{
"id": "Set_1",
"name": "Normalize Payload",
"type": "n8n-nodes-base.set",
"position": [520, 280],
"parameters": {
"keepOnlySet": false,
"values": {
"string": [
{"name": "ticket_id", "value": "={{$json.id || ''}}"},
{"name": "priority", "value": "={{$json.priority || 'normal'}}"},
{"name": "summary", "value": "={{$json.summary || ''}}"}
]
}
}
},
{
"id": "If_1",
"name": "Urgent?",
"type": "n8n-nodes-base.if",
"position": [780, 280],
"parameters": {
"conditions": {
"string": [
{"value1": "={{$json.priority}}", "operation": "equal", "value2": "high"}
]
}
}
}
],
"connections": {
"Incoming Ticket": {
"main": [[{"node": "Normalize Payload", "type": "main", "index": 0}]]
},
"Normalize Payload": {
"main": [[{"node": "Urgent?", "type": "main", "index": 0}]]
}
}
}

View file

@ -0,0 +1,43 @@
{
"name": "Unsafe support agent",
"nodes": [
{
"id": "webhook",
"name": "Public Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": { "path": "support" }
},
{
"id": "agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"parameters": { "text": "Respond to the customer" }
},
{
"id": "api",
"name": "Send response",
"type": "n8n-nodes-base.httpRequest",
"retryOnFail": true,
"maxTries": 10,
"waitBetweenTries": 0,
"parameters": {
"url": "https://api.example.com/messages",
"headerParameters": {
"parameters": [{ "name": "Authorization", "value": "Bearer vf_fake_0123456789abcdef" }]
}
}
},
{
"id": "shell",
"name": "Run Shell",
"type": "n8n-nodes-base.executeCommand",
"parameters": { "command": "echo done" }
}
],
"connections": {
"Public Webhook": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] },
"AI Agent": { "main": [[{ "node": "Send response", "type": "main", "index": 0 }]] },
"Send response": { "main": [[{ "node": "Run Shell", "type": "main", "index": 0 }]] }
},
"settings": {}
}