From 1feeb8c56e4cb83e6a554b64ba063111576c3096 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 14:36:16 -0700 Subject: [PATCH 1/6] feat(integrations): suggest curated skills per integration with one-click add Curate research-backed, capability-grounded skills for every catalog integration and surface them on the integration detail page. Each skill maps to operations the block actually supports and can be added to the workspace in one click; track adds in PostHog. - Add SuggestedSkill type + skills field on BlockMeta; populate skills for all 193 catalog integrations (3 audit passes for grounding/sourcing) - getSuggestedSkillsForBlock() with versioned-type (e.g. notion_v2) base fallback - Skills section on the integration detail page with add/added states - integration_skill_added PostHog event with workspace/integration metadata --- .../[block]/integration-block-detail.tsx | 16 ++- .../[block]/integration-skills-section.tsx | 107 ++++++++++++++++++ apps/sim/blocks/blocks/agentmail.ts | 23 ++++ apps/sim/blocks/blocks/agentphone.ts | 23 ++++ apps/sim/blocks/blocks/agiloft.ts | 23 ++++ apps/sim/blocks/blocks/ahrefs.ts | 23 ++++ apps/sim/blocks/blocks/airtable.ts | 23 ++++ apps/sim/blocks/blocks/airweave.ts | 16 +++ apps/sim/blocks/blocks/algolia.ts | 23 ++++ apps/sim/blocks/blocks/amplitude.ts | 30 +++++ apps/sim/blocks/blocks/apify.ts | 30 +++++ apps/sim/blocks/blocks/apollo.ts | 37 ++++++ apps/sim/blocks/blocks/arxiv.ts | 30 +++++ apps/sim/blocks/blocks/asana.ts | 23 ++++ apps/sim/blocks/blocks/ashby.ts | 23 ++++ apps/sim/blocks/blocks/athena.ts | 23 ++++ apps/sim/blocks/blocks/attio.ts | 30 +++++ apps/sim/blocks/blocks/azure_devops.ts | 30 +++++ apps/sim/blocks/blocks/box.ts | 30 +++++ apps/sim/blocks/blocks/brandfetch.ts | 23 ++++ apps/sim/blocks/blocks/brightdata.ts | 30 +++++ apps/sim/blocks/blocks/browser_use.ts | 23 ++++ apps/sim/blocks/blocks/calcom.ts | 30 +++++ apps/sim/blocks/blocks/calendly.ts | 23 ++++ apps/sim/blocks/blocks/clay.ts | 16 +++ apps/sim/blocks/blocks/clerk.ts | 30 +++++ apps/sim/blocks/blocks/clickhouse.ts | 23 ++++ apps/sim/blocks/blocks/cloudflare.ts | 23 ++++ apps/sim/blocks/blocks/cloudformation.ts | 23 ++++ apps/sim/blocks/blocks/cloudwatch.ts | 23 ++++ apps/sim/blocks/blocks/confluence.ts | 30 +++++ apps/sim/blocks/blocks/crowdstrike.ts | 16 +++ apps/sim/blocks/blocks/cursor.ts | 23 ++++ apps/sim/blocks/blocks/dagster.ts | 30 +++++ apps/sim/blocks/blocks/databricks.ts | 23 ++++ apps/sim/blocks/blocks/datadog.ts | 30 +++++ apps/sim/blocks/blocks/devin.ts | 23 ++++ apps/sim/blocks/blocks/discord.ts | 30 +++++ apps/sim/blocks/blocks/docusign.ts | 29 +++++ apps/sim/blocks/blocks/dropbox.ts | 29 +++++ apps/sim/blocks/blocks/dspy.ts | 23 ++++ apps/sim/blocks/blocks/dub.ts | 30 +++++ apps/sim/blocks/blocks/duckduckgo.ts | 23 ++++ apps/sim/blocks/blocks/dynamodb.ts | 22 ++++ apps/sim/blocks/blocks/elasticsearch.ts | 27 +++++ apps/sim/blocks/blocks/elevenlabs.ts | 22 ++++ apps/sim/blocks/blocks/emailbison.ts | 30 +++++ apps/sim/blocks/blocks/enrich.ts | 30 +++++ apps/sim/blocks/blocks/enrichment.ts | 23 ++++ apps/sim/blocks/blocks/evernote.ts | 27 +++++ apps/sim/blocks/blocks/exa.ts | 27 +++++ apps/sim/blocks/blocks/extend.ts | 23 ++++ apps/sim/blocks/blocks/fathom.ts | 23 ++++ apps/sim/blocks/blocks/findymail.ts | 30 +++++ apps/sim/blocks/blocks/firecrawl.ts | 30 +++++ apps/sim/blocks/blocks/fireflies.ts | 23 ++++ apps/sim/blocks/blocks/gamma.ts | 28 +++++ apps/sim/blocks/blocks/github.ts | 30 +++++ apps/sim/blocks/blocks/gitlab.ts | 23 ++++ apps/sim/blocks/blocks/gmail.ts | 27 +++++ apps/sim/blocks/blocks/gong.ts | 23 ++++ apps/sim/blocks/blocks/google.ts | 23 ++++ apps/sim/blocks/blocks/google_ads.ts | 23 ++++ apps/sim/blocks/blocks/google_bigquery.ts | 22 ++++ apps/sim/blocks/blocks/google_books.ts | 23 ++++ apps/sim/blocks/blocks/google_calendar.ts | 28 +++++ apps/sim/blocks/blocks/google_contacts.ts | 22 ++++ apps/sim/blocks/blocks/google_docs.ts | 22 ++++ apps/sim/blocks/blocks/google_drive.ts | 30 +++++ apps/sim/blocks/blocks/google_forms.ts | 21 ++++ apps/sim/blocks/blocks/google_groups.ts | 27 +++++ apps/sim/blocks/blocks/google_maps.ts | 28 +++++ apps/sim/blocks/blocks/google_meet.ts | 21 ++++ apps/sim/blocks/blocks/google_pagespeed.ts | 21 ++++ apps/sim/blocks/blocks/google_sheets.ts | 26 +++++ apps/sim/blocks/blocks/google_slides.ts | 30 +++++ apps/sim/blocks/blocks/google_tasks.ts | 22 ++++ apps/sim/blocks/blocks/google_translate.ts | 22 ++++ apps/sim/blocks/blocks/google_vault.ts | 23 ++++ apps/sim/blocks/blocks/grafana.ts | 29 +++++ apps/sim/blocks/blocks/grain.ts | 22 ++++ apps/sim/blocks/blocks/granola.ts | 22 ++++ apps/sim/blocks/blocks/greenhouse.ts | 22 ++++ apps/sim/blocks/blocks/greptile.ts | 23 ++++ apps/sim/blocks/blocks/hex.ts | 26 +++++ apps/sim/blocks/blocks/hubspot.ts | 34 ++++++ apps/sim/blocks/blocks/huggingface.ts | 22 ++++ apps/sim/blocks/blocks/hunter.ts | 22 ++++ apps/sim/blocks/blocks/iam.ts | 30 +++++ apps/sim/blocks/blocks/identity_center.ts | 23 ++++ apps/sim/blocks/blocks/incidentio.ts | 29 +++++ apps/sim/blocks/blocks/infisical.ts | 22 ++++ apps/sim/blocks/blocks/instantly.ts | 28 +++++ apps/sim/blocks/blocks/intercom.ts | 30 +++++ apps/sim/blocks/blocks/jina.ts | 20 ++++ apps/sim/blocks/blocks/jira.ts | 27 +++++ .../blocks/blocks/jira_service_management.ts | 21 ++++ apps/sim/blocks/blocks/kalshi.ts | 22 ++++ apps/sim/blocks/blocks/ketch.ts | 27 +++++ apps/sim/blocks/blocks/langsmith.ts | 16 +++ apps/sim/blocks/blocks/launchdarkly.ts | 22 ++++ apps/sim/blocks/blocks/lemlist.ts | 23 ++++ apps/sim/blocks/blocks/linear.ts | 30 +++++ apps/sim/blocks/blocks/linkedin.ts | 23 ++++ apps/sim/blocks/blocks/linkup.ts | 23 ++++ apps/sim/blocks/blocks/linq.ts | 23 ++++ apps/sim/blocks/blocks/loops.ts | 29 +++++ apps/sim/blocks/blocks/luma.ts | 29 +++++ apps/sim/blocks/blocks/mailchimp.ts | 29 +++++ apps/sim/blocks/blocks/mailgun.ts | 29 +++++ apps/sim/blocks/blocks/mem0.ts | 23 ++++ apps/sim/blocks/blocks/microsoft_ad.ts | 23 ++++ apps/sim/blocks/blocks/microsoft_dataverse.ts | 27 +++++ apps/sim/blocks/blocks/microsoft_excel.ts | 29 +++++ apps/sim/blocks/blocks/microsoft_planner.ts | 23 ++++ apps/sim/blocks/blocks/microsoft_teams.ts | 27 +++++ apps/sim/blocks/blocks/mistral_parse.ts | 21 ++++ apps/sim/blocks/blocks/monday.ts | 20 ++++ apps/sim/blocks/blocks/mongodb.ts | 20 ++++ apps/sim/blocks/blocks/neo4j.ts | 21 ++++ apps/sim/blocks/blocks/new_relic.ts | 22 ++++ apps/sim/blocks/blocks/notion.ts | 27 +++++ apps/sim/blocks/blocks/obsidian.ts | 20 ++++ apps/sim/blocks/blocks/okta.ts | 26 +++++ apps/sim/blocks/blocks/onedrive.ts | 21 ++++ apps/sim/blocks/blocks/onepassword.ts | 23 ++++ apps/sim/blocks/blocks/openai.ts | 23 ++++ apps/sim/blocks/blocks/outlook.ts | 26 +++++ apps/sim/blocks/blocks/pagerduty.ts | 30 +++++ apps/sim/blocks/blocks/parallel.ts | 29 +++++ apps/sim/blocks/blocks/peopledatalabs.ts | 30 +++++ apps/sim/blocks/blocks/perplexity.ts | 23 ++++ apps/sim/blocks/blocks/pinecone.ts | 29 +++++ apps/sim/blocks/blocks/pipedrive.ts | 30 +++++ apps/sim/blocks/blocks/polymarket.ts | 30 +++++ apps/sim/blocks/blocks/posthog.ts | 33 ++++++ apps/sim/blocks/blocks/profound.ts | 30 +++++ apps/sim/blocks/blocks/prospeo.ts | 29 +++++ apps/sim/blocks/blocks/pulse.ts | 22 ++++ apps/sim/blocks/blocks/qdrant.ts | 20 ++++ apps/sim/blocks/blocks/quiver.ts | 20 ++++ apps/sim/blocks/blocks/railway.ts | 33 ++++++ apps/sim/blocks/blocks/rb2b.ts | 20 ++++ apps/sim/blocks/blocks/rds.ts | 23 ++++ apps/sim/blocks/blocks/reddit.ts | 28 +++++ apps/sim/blocks/blocks/redis.ts | 26 +++++ apps/sim/blocks/blocks/reducto.ts | 21 ++++ apps/sim/blocks/blocks/resend.ts | 20 ++++ apps/sim/blocks/blocks/revenuecat.ts | 26 +++++ apps/sim/blocks/blocks/rippling.ts | 33 ++++++ apps/sim/blocks/blocks/rootly.ts | 34 ++++++ apps/sim/blocks/blocks/s3.ts | 26 +++++ apps/sim/blocks/blocks/salesforce.ts | 33 ++++++ apps/sim/blocks/blocks/sap_concur.ts | 29 +++++ apps/sim/blocks/blocks/sap_s4hana.ts | 30 +++++ apps/sim/blocks/blocks/secrets_manager.ts | 30 +++++ apps/sim/blocks/blocks/sendgrid.ts | 30 +++++ apps/sim/blocks/blocks/sentry.ts | 30 +++++ apps/sim/blocks/blocks/serper.ts | 30 +++++ apps/sim/blocks/blocks/servicenow.ts | 23 ++++ apps/sim/blocks/blocks/ses.ts | 30 +++++ apps/sim/blocks/blocks/sharepoint.ts | 27 +++++ apps/sim/blocks/blocks/shopify.ts | 33 ++++++ apps/sim/blocks/blocks/similarweb.ts | 23 ++++ apps/sim/blocks/blocks/sixtyfour.ts | 22 ++++ apps/sim/blocks/blocks/slack.ts | 29 +++++ apps/sim/blocks/blocks/sqs.ts | 16 +++ apps/sim/blocks/blocks/stagehand.ts | 23 ++++ apps/sim/blocks/blocks/stripe.ts | 28 +++++ apps/sim/blocks/blocks/sts.ts | 30 +++++ apps/sim/blocks/blocks/supabase.ts | 29 +++++ apps/sim/blocks/blocks/tailscale.ts | 22 ++++ apps/sim/blocks/blocks/tavily.ts | 29 +++++ apps/sim/blocks/blocks/telegram.ts | 21 ++++ apps/sim/blocks/blocks/textract.ts | 23 ++++ apps/sim/blocks/blocks/tinybird.ts | 29 +++++ apps/sim/blocks/blocks/trello.ts | 27 +++++ apps/sim/blocks/blocks/twilio.ts | 21 ++++ apps/sim/blocks/blocks/twilio_voice.ts | 28 +++++ apps/sim/blocks/blocks/typeform.ts | 26 +++++ apps/sim/blocks/blocks/upstash.ts | 29 +++++ apps/sim/blocks/blocks/vercel.ts | 26 +++++ apps/sim/blocks/blocks/wealthbox.ts | 28 +++++ apps/sim/blocks/blocks/webflow.ts | 23 ++++ apps/sim/blocks/blocks/whatsapp.ts | 23 ++++ apps/sim/blocks/blocks/wikipedia.ts | 22 ++++ apps/sim/blocks/blocks/wiza.ts | 22 ++++ apps/sim/blocks/blocks/wordpress.ts | 29 +++++ apps/sim/blocks/blocks/workday.ts | 29 +++++ apps/sim/blocks/blocks/x.ts | 29 +++++ apps/sim/blocks/blocks/youtube.ts | 23 ++++ apps/sim/blocks/blocks/zendesk.ts | 30 +++++ apps/sim/blocks/blocks/zep.ts | 23 ++++ apps/sim/blocks/blocks/zoom.ts | 23 ++++ apps/sim/blocks/blocks/zoominfo.ts | 30 +++++ apps/sim/blocks/registry.ts | 22 +++- apps/sim/blocks/types.ts | 17 +++ apps/sim/lib/posthog/events.ts | 12 ++ 198 files changed, 5104 insertions(+), 2 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx index 827e1e7684a..3d19c178989 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx @@ -14,6 +14,7 @@ import { } from '@/lib/integrations' import { getServiceConfigByProviderId } from '@/lib/oauth' import { ConnectOAuthModal } from '@/app/workspace/[workspaceId]/components/connect-oauth-modal' +import { IntegrationSkillsSection } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section' import { ConnectServiceAccountModal } from '@/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal' import { IntegrationSection } from '@/app/workspace/[workspaceId]/integrations/components/integration-section' import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' @@ -21,7 +22,11 @@ import { CONNECT_MODE, CONNECT_QUERY_PARAM, } from '@/app/workspace/[workspaceId]/integrations/connect-route' -import { getTemplatesForBlock, type ScopedBlockTemplate } from '@/blocks/registry' +import { + getSuggestedSkillsForBlock, + getTemplatesForBlock, + type ScopedBlockTemplate, +} from '@/blocks/registry' import { useWorkspaceCredentials } from '@/hooks/queries/credentials' import { useOAuthReturnRouter } from '@/hooks/use-oauth-return' @@ -46,6 +51,7 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration const searchParams = useSearchParams() const Icon = blockTypeToIconMap[integration.type] const matchingTemplates = getTemplatesForBlock(integration.type) + const suggestedSkills = getSuggestedSkillsForBlock(integration.type) const oauthService = resolveOAuthServiceForIntegration(integration) const [oauthOpen, setOAuthOpen] = useState(false) @@ -210,6 +216,14 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration )} + {suggestedSkills.length > 0 && ( + + )} + {matchingTemplates.length > 0 && ( +
+ +
+ + ) +} + +interface SkillRowProps { + skill: SuggestedSkill + added: boolean + pending: boolean + onAdd: () => void +} + +function SkillRow({ skill, added, pending, onAdd }: SkillRowProps) { + return ( +
+ +
+ {skill.name} + {skill.description} +
+ {added ? ( + + Added + + ) : ( + + {pending ? 'Adding...' : 'Add'} + + )} +
+ ) +} + +/** + * Curated, research-backed skills for an integration. Each row adds the skill + * to the workspace via the same `useCreateSkill` mutation the Skills page uses; + * a skill already present in the workspace (matched by name) renders as + * "Added" instead of an add button. + */ +export function IntegrationSkillsSection({ + skills, + workspaceId, + integrationType, +}: IntegrationSkillsSectionProps) { + const posthog = usePostHog() + const { data: existingSkills = [] } = useSkills(workspaceId) + const createSkill = useCreateSkill() + const [pendingName, setPendingName] = useState(null) + + const existingNames = useMemo(() => new Set(existingSkills.map((s) => s.name)), [existingSkills]) + + const handleAdd = async (skill: SuggestedSkill, position: number) => { + setPendingName(skill.name) + try { + await createSkill.mutateAsync({ workspaceId, skill }) + captureEvent(posthog, 'integration_skill_added', { + workspace_id: workspaceId, + integration_type: integrationType, + skill_name: skill.name, + position, + skill_count: skills.length, + }) + } finally { + setPendingName(null) + } + } + + return ( +
+ Skills +
+
+ {skills.map((skill, index) => ( + handleAdd(skill, index)} + /> + ))} +
+
+ ) +} diff --git a/apps/sim/blocks/blocks/agentmail.ts b/apps/sim/blocks/blocks/agentmail.ts index 11863592b55..f89af3c7eae 100644 --- a/apps/sim/blocks/blocks/agentmail.ts +++ b/apps/sim/blocks/blocks/agentmail.ts @@ -690,4 +690,27 @@ export const AgentMailBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'triage-inbox-messages', + description: + 'Read new messages in an AgentMail inbox, classify them, and reply or escalate as needed.', + content: + '# Triage Inbox Messages\n\nProcess unread email in an AgentMail inbox and act on each thread.\n\n## Steps\n1. List recent messages in the inbox and identify which threads are unread or unanswered.\n2. Read each thread for context including prior replies.\n3. Classify intent (question, request, spam, follow-up needed) and urgency.\n4. Draft and send a reply on the thread for routine items, or escalate by flagging the ones needing a human.\n\n## Output\nA summary of threads handled: who, the classification, and the action taken (replied, escalated, ignored).', + }, + { + name: 'extract-verification-code', + description: + 'Read a verification or OTP email in an AgentMail inbox and extract the code or confirmation link.', + content: + '# Extract Verification Code\n\nPull a 2FA/OTP code or confirmation link from an email so an agent can complete a signup or login flow.\n\n## Steps\n1. Search the inbox for the most recent message from the expected sender or matching the subject.\n2. Read the message body and extract the verification code or the confirmation URL.\n3. Return only the code or link.\n\n## Output\nThe extracted code or link. If multiple recent matches exist, return the newest and note its timestamp.', + }, + { + name: 'send-and-track-outreach', + description: + 'Send an email from an AgentMail inbox and monitor the thread for a reply to continue the conversation.', + content: + '# Send and Track Outreach\n\nSend an outbound email and follow the resulting thread.\n\n## Steps\n1. Compose the message with a clear subject and body from the provided details.\n2. Send it from the AgentMail inbox to the recipient.\n3. Check the thread for a reply; when one arrives, read it and determine the next action.\n\n## Output\nConfirm the message was sent with the thread ID. When a reply arrives, summarize it and recommend the next step.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/agentphone.ts b/apps/sim/blocks/blocks/agentphone.ts index 6750c85b700..ad69c01d148 100644 --- a/apps/sim/blocks/blocks/agentphone.ts +++ b/apps/sim/blocks/blocks/agentphone.ts @@ -822,4 +822,27 @@ export const AgentPhoneBlockMeta = { alsoIntegrations: ['zendesk'], }, ], + skills: [ + { + name: 'send-sms-notification', + description: + 'Send an SMS or iMessage from an AgentPhone number to notify or remind a recipient.', + content: + '# Send SMS Notification\n\nSend a text message to a person from an AgentPhone number.\n\n## Steps\n1. Determine the sending number and the recipient phone number.\n2. Write a clear, concise message (reminder, alert, confirmation, or update).\n3. Send the SMS or iMessage.\n\n## Output\nConfirm the message was sent with the recipient number and a short preview of the text. Note any send failure.', + }, + { + name: 'place-outbound-call', + description: + 'Place a voice call from an AgentPhone number to deliver a message or run a short scripted interaction.', + content: + '# Place Outbound Call\n\nMake a voice call from an AgentPhone number for reminders, confirmations, or notifications.\n\n## Steps\n1. Determine the AgentPhone number to call from and the destination number.\n2. Prepare the spoken message or script to deliver.\n3. Place the call and deliver the message.\n\n## Output\nConfirm the call was placed with the destination number and the message delivered. Report call status or transcript if available.', + }, + { + name: 'provision-and-respond', + description: + 'Provision a phone number and handle inbound SMS by reading the message and sending an appropriate reply.', + content: + '# Provision and Respond\n\nSet up a phone number and respond to incoming texts.\n\n## Steps\n1. Provision a US or Canadian phone number if one is not already assigned.\n2. Read inbound SMS messages received on that number.\n3. For each message, determine intent and send a relevant reply.\n\n## Output\nReport the provisioned number, the inbound messages handled, and the replies sent.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/agiloft.ts b/apps/sim/blocks/blocks/agiloft.ts index ea6440e5b0f..82761c28a59 100644 --- a/apps/sim/blocks/blocks/agiloft.ts +++ b/apps/sim/blocks/blocks/agiloft.ts @@ -504,4 +504,27 @@ export const AgiloftBlockMeta = { alsoIntegrations: ['linear'], }, ], + skills: [ + { + name: 'flag-expiring-contracts', + description: + 'Query Agiloft for contracts approaching their renewal or expiration date and report the ones at risk.', + content: + '# Flag Expiring Contracts\n\nFind contracts in Agiloft that are nearing expiration or auto-renewal so the team can act in time.\n\n## Steps\n1. Query the contract records for upcoming expiration or renewal dates within the target window.\n2. For each match, read key terms: counterparty, value, renewal type, and notice period.\n3. Identify contracts with auto-renewal clauses that need a decision before the notice deadline.\n\n## Output\nA list of at-risk contracts sorted by date, with counterparty, expiration date, renewal type, and recommended action.', + }, + { + name: 'create-contract-record', + description: + 'Create a new contract or related record in Agiloft from provided deal or request details.', + content: + '# Create Contract Record\n\nAdd a new contract record to Agiloft from intake details.\n\n## Steps\n1. Map the provided details to the contract record fields (counterparty, type, value, start/end dates, owner).\n2. Set status to the correct initial stage in the lifecycle.\n3. Create the record and capture its ID.\n\n## Output\nConfirm the record was created with its ID and key fields. Note any required fields that were missing.', + }, + { + name: 'summarize-contract-terms', + description: + 'Read a contract record in Agiloft and produce a plain-language summary of its key obligations and dates.', + content: + '# Summarize Contract Terms\n\nTurn an Agiloft contract record into a concise brief.\n\n## Steps\n1. Read the contract record and its key fields and attached terms.\n2. Identify obligations, payment terms, renewal/termination clauses, and critical dates.\n3. Note any unusual or high-risk terms.\n\n## Output\nA short brief: parties, term, value, key obligations, critical dates, and any risk flags. Keep it readable for non-lawyers.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/ahrefs.ts b/apps/sim/blocks/blocks/ahrefs.ts index 46fe918cf7b..ce016ff4066 100644 --- a/apps/sim/blocks/blocks/ahrefs.ts +++ b/apps/sim/blocks/blocks/ahrefs.ts @@ -645,4 +645,27 @@ export const AhrefsBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'analyze-competitor-backlinks', + description: + "Pull a competitor domain's backlink profile from Ahrefs and surface link-building opportunities.", + content: + "# Analyze Competitor Backlinks\n\nUse Ahrefs to study a competitor's backlinks and find outreach targets.\n\n## Steps\n1. Run a backlink/referring-domains report for the competitor URL or domain.\n2. Identify high-authority referring domains and the anchor texts they use.\n3. Compare against your own domain to find sites linking to them but not you.\n\n## Output\nA prioritized list of link opportunities: referring domain, authority, linked page, and why it is worth pursuing.", + }, + { + name: 'keyword-research-report', + description: + 'Research keywords in Ahrefs for a topic and report volume, difficulty, and ranking opportunities.', + content: + '# Keyword Research Report\n\nBuild a keyword opportunity report from Ahrefs data.\n\n## Steps\n1. Pull the organic keywords a competitor domain already ranks for to source candidate keywords for the topic.\n2. Run a keyword overview on the most relevant candidates to collect search volume and keyword difficulty.\n3. Highlight keywords with meaningful volume and lower difficulty as quick wins.\n\n## Output\nA table of keywords with volume and difficulty, grouped into quick wins vs long-term targets, with a short recommendation.', + }, + { + name: 'track-organic-rankings', + description: + "Pull a domain's organic keyword rankings from Ahrefs and report top movers and lost positions.", + content: + '# Track Organic Rankings\n\nReport how a domain is ranking in organic search using Ahrefs.\n\n## Steps\n1. Pull the organic keywords report for the target domain.\n2. Identify the top-ranking keywords and their positions.\n3. Compare against a prior snapshot if available to find gains and losses.\n\n## Output\nA summary of top organic keywords, notable position gains and drops, and pages that may need attention.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/airtable.ts b/apps/sim/blocks/blocks/airtable.ts index ca5e1cabb58..f8905dbc2ab 100644 --- a/apps/sim/blocks/blocks/airtable.ts +++ b/apps/sim/blocks/blocks/airtable.ts @@ -432,4 +432,27 @@ export const AirtableBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'sync-records-to-table', + description: + 'Parse incoming emails, forms, or documents and create or update structured Airtable records.', + content: + '# Sync Records to Airtable\n\nTurn unstructured inbound data into clean Airtable records.\n\n## Steps\n1. Read the source content (email body, form payload, or document text).\n2. Extract the fields that map to the target table columns (name, email, company, amount, status, etc.).\n3. Search the table for an existing record matching a unique key (such as email or order ID).\n4. Update the existing record if found; otherwise create a new one.\n5. Set any derived fields (category, priority, owner) based on the content.\n\n## Output\nReport how many records were created vs updated and list the record IDs. Flag any rows skipped for missing required fields.', + }, + { + name: 'triage-and-route-records', + description: + 'Classify new Airtable records (leads, tickets, requests) and assign owner, priority, and due dates.', + content: + '# Triage and Route Records\n\nAutomatically qualify and route new Airtable records.\n\n## Steps\n1. List recently created records in the target table.\n2. For each record, read the free-text fields (notes, message, transcript) and classify intent, urgency, and category.\n3. Set the owner, priority, and status fields based on the classification.\n4. Compute and set a due date for time-sensitive items.\n\n## Output\nSummarize the records triaged grouped by owner and priority. Note any records that need human review.', + }, + { + name: 'generate-status-report', + description: + 'Query an Airtable table or view and produce a rolled-up status report of progress, blockers, and trends.', + content: + '# Generate Status Report\n\nBuild a concise report from an Airtable table or view.\n\n## Steps\n1. Read records from the specified table or filtered view.\n2. Group by the relevant dimension (project, status, owner, or stage).\n3. Count totals per group and identify overdue or stalled items.\n4. Highlight notable changes or anomalies in the data.\n\n## Output\nA short report: totals per group, items at risk, and 2-3 takeaways. Keep it scannable with bullet points.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/airweave.ts b/apps/sim/blocks/blocks/airweave.ts index b54d190f713..d23da5ba9c4 100644 --- a/apps/sim/blocks/blocks/airweave.ts +++ b/apps/sim/blocks/blocks/airweave.ts @@ -172,4 +172,20 @@ export const AirweaveBlockMeta = { tags: ['research', 'reporting'], }, ], + skills: [ + { + name: 'answer-from-collection', + description: + 'Search an Airweave collection across synced sources and answer a question with grounded, cited results.', + content: + '# Answer From Collection\n\nUse Airweave to retrieve current context across connected apps and answer a question.\n\n## Steps\n1. Take the user question and search the relevant Airweave collection.\n2. Review the top results, noting which source each came from (docs, tickets, CRM, etc.).\n3. Synthesize an answer grounded only in the retrieved content.\n4. If the collection returns nothing relevant, say so instead of guessing.\n\n## Output\nA concise answer with citations back to the source records. Do not include claims unsupported by the results.', + }, + { + name: 'build-context-brief', + description: + 'Search an Airweave collection for a person, account, or project and compile a context brief from all sources.', + content: + '# Build Context Brief\n\nGather everything Airweave knows about a subject across synced sources into one brief.\n\n## Steps\n1. Search the collection for the subject (account name, project, customer, or person).\n2. Pull relevant hits from each source type and group them.\n3. Summarize the current state, recent activity, and any open items.\n\n## Output\nA short brief organized by source, highlighting the most recent and relevant facts plus open questions.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/algolia.ts b/apps/sim/blocks/blocks/algolia.ts index 0bfe97c4ccf..47f07e57e58 100644 --- a/apps/sim/blocks/blocks/algolia.ts +++ b/apps/sim/blocks/blocks/algolia.ts @@ -716,4 +716,27 @@ export const AlgoliaBlockMeta = { tags: ['engineering', 'automation'], }, ], + skills: [ + { + name: 'answer-from-search-index', + description: + 'Search an Algolia index for a user question and return a grounded answer with the matching records.', + content: + '# Answer From Search Index\n\nUse Algolia retrieval to answer questions over indexed content (docs, products, knowledge base).\n\n## Steps\n1. Take the user question and run a search against the relevant Algolia index.\n2. Apply filters or facets to narrow results (category, status, language) when appropriate.\n3. Read the top hits and synthesize an answer grounded only in the returned records.\n4. If no relevant hits are returned, say so rather than guessing.\n\n## Output\nA concise answer plus the titles and IDs of the records used. Do not invent content not present in the hits.', + }, + { + name: 'index-new-records', + description: + 'Take new or updated content and push it into an Algolia index as searchable records.', + content: + '# Index New Records\n\nKeep an Algolia index in sync with new content.\n\n## Steps\n1. Collect the source items to index (products, articles, entries).\n2. Map each item to a record object with a stable objectID and the searchable/filterable attributes.\n3. Save the records to the target index, updating existing objectIDs in place.\n4. Verify by running a quick search for one of the new records.\n\n## Output\nReport how many records were added or updated and confirm one is retrievable via search.', + }, + { + name: 'audit-search-relevance', + description: + 'Run a set of test queries against an Algolia index and report which return weak or empty results.', + content: + '# Audit Search Relevance\n\nCheck that important queries return good results from an Algolia index.\n\n## Steps\n1. Run each query in the provided test set against the index.\n2. Record the top results, total hit count, and whether the expected record appears.\n3. Flag queries that return zero hits, too many hits, or miss the expected record.\n\n## Output\nA table of queries with result counts and pass/fail, plus suggestions for synonyms or ranking tweaks where relevance is weak.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/amplitude.ts b/apps/sim/blocks/blocks/amplitude.ts index 34d65c45e0b..689dd6ef8ca 100644 --- a/apps/sim/blocks/blocks/amplitude.ts +++ b/apps/sim/blocks/blocks/amplitude.ts @@ -819,4 +819,34 @@ export const AmplitudeBlockMeta = { alsoIntegrations: ['hex', 'slack'], }, ], + skills: [ + { + name: 'track-product-event', + description: + 'Send a behavioral event to Amplitude with user and event properties for analytics.', + content: + '# Track Product Event\n\nLog a user action to Amplitude so it shows up in analytics.\n\n## Steps\n1. Determine the event name and the user identifier (user ID or device ID).\n2. Attach relevant event properties (plan, source, value) and user properties.\n3. Send the event to Amplitude.\n\n## Output\nConfirm the event was sent with its name and the user it was attributed to. Note any required field that was missing.', + }, + { + name: 'segment-event-counts', + description: + 'Run Amplitude event segmentation over a date range and report unique and total counts, optionally grouped by a property.', + content: + '# Segment Event Counts\n\nMeasure how often an event fires in Amplitude over a time window.\n\n## Steps\n1. Identify the event type and the start and end dates (YYYYMMDD) to analyze.\n2. Pick the measurement (uniques, totals, or average) and the interval (daily, weekly, monthly).\n3. Optionally group by a user or event property to break the counts down by segment.\n4. Run the event segmentation query and read the resulting time series.\n\n## Output\nThe series of counts per interval, the segment breakdown if grouped, and a callout of the largest movement versus the start of the range.', + }, + { + name: 'summarize-engagement-metrics', + description: + 'Pull Amplitude active users, top events, and revenue and summarize product engagement for a period.', + content: + '# Summarize Engagement Metrics\n\nProduce a short product engagement summary from Amplitude data.\n\n## Steps\n1. Query active and new users for the target period.\n2. Pull the most-triggered events with event segmentation to see what users do most.\n3. Pull revenue metrics for the same period.\n4. Compare each against the prior period to spot trends.\n\n## Output\nA concise summary: active users, top events, revenue, and notable trends versus the prior period.', + }, + { + name: 'lookup-user-activity', + description: + 'Find a user in Amplitude by ID and pull their recent event activity and profile properties.', + content: + '# Lookup User Activity\n\nInvestigate a single user in Amplitude for support or debugging.\n\n## Steps\n1. Search for the user by user ID, device ID, or Amplitude ID to resolve their Amplitude ID.\n2. Pull the user activity stream for that Amplitude ID, ordered latest first.\n3. Optionally fetch the user profile to see their current properties.\n\n## Output\nA timeline of the user recent events plus key profile properties. Note the time range covered.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/apify.ts b/apps/sim/blocks/blocks/apify.ts index 677e9ed791a..ac1e879a932 100644 --- a/apps/sim/blocks/blocks/apify.ts +++ b/apps/sim/blocks/blocks/apify.ts @@ -309,4 +309,34 @@ export const ApifyBlockMeta = { tags: ['sales', 'monitoring'], }, ], + skills: [ + { + name: 'scrape-site-to-table', + description: + 'Run an Apify actor to scrape a target website and write the extracted rows into a structured table. Use for one-off or recurring data extraction jobs.', + content: + '# Scrape Site to Table\n\nRun an Apify actor against a target site and load the results into a clean table.\n\n## Steps\n1. Pick the actor or saved task (e.g. a web scraper) and assemble its JSON input — start URLs, page or request limits, and proxy settings.\n2. Run the actor synchronously for small jobs, or asynchronously and poll Get Run for larger crawls.\n3. Once the run status is SUCCEEDED, fetch the dataset items, selecting only the fields you need.\n4. Normalize each item into consistent columns and write the rows to the destination table.\n\n## Output\nReport the run ID, final status, and row count. If the run failed, surface the error and the actor input that produced it so it can be retried.', + }, + { + name: 'monitor-prices', + description: + 'Use an Apify scraper to capture competitor or product prices on a schedule, track history, and alert on changes. Use for price and stock monitoring.', + content: + '# Monitor Prices\n\nTrack pricing on target product pages over time and flag meaningful changes.\n\n## Steps\n1. Run the scraping actor with the product or category URLs to watch.\n2. From the dataset, extract product name, price, currency, and stock status for each item.\n3. Compare each price against the last recorded value for that product.\n4. Append the new snapshot to a price-history table.\n\n## Output\nList any products whose price dropped, rose, or went out of stock, with old and new values. If nothing changed, say so briefly.', + }, + { + name: 'build-lead-list', + description: + 'Run an Apify directory or maps scraper to collect business listings and produce a deduplicated, CRM-ready lead list. Use for prospecting and lead generation.', + content: + '# Build Lead List\n\nCollect business listings from a directory and turn them into a usable prospect list.\n\n## Steps\n1. Run the directory or maps scraper actor with the search terms, location, and result limit.\n2. Fetch the dataset and pull company name, website, phone, email, and address for each listing.\n3. Drop entries missing the fields you require, then deduplicate by domain or phone.\n4. Write the cleaned rows to a lead table ready for enrichment or CRM import.\n\n## Output\nReport total listings scraped, how many passed filtering, and how many duplicates were removed.', + }, + { + name: 'collect-content-for-knowledge-base', + description: + 'Use an Apify crawler to extract article or documentation text from a site and prepare it for ingestion into a knowledge base or RAG pipeline.', + content: + '# Collect Content for Knowledge Base\n\nCrawl a content site and gather clean text for downstream ingestion.\n\n## Steps\n1. Run the crawler actor with the start URLs and a request limit, scoped to the relevant section of the site.\n2. Fetch dataset items and extract title, URL, and main body text for each page.\n3. Strip navigation, boilerplate, and empty pages.\n4. Hand the cleaned documents to the knowledge base for chunking and indexing.\n\n## Output\nReport the number of pages crawled and ingested, and list any URLs that failed or returned no usable text.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/apollo.ts b/apps/sim/blocks/blocks/apollo.ts index f953afab173..0e38394f5d4 100644 --- a/apps/sim/blocks/blocks/apollo.ts +++ b/apps/sim/blocks/blocks/apollo.ts @@ -1442,4 +1442,41 @@ export const ApolloBlockMeta = { tags: ['sales', 'crm', 'automation', 'enrichment'], }, ], + skills: [ + { + name: 'build-prospect-list', + description: + 'Search Apollo for people matching an ideal customer profile and produce a targeted prospect list. Use for outbound prospecting and territory building.', + content: + '# Build Prospect List\n\nFind decision-makers that match an ICP and assemble a clean prospect list.\n\n## Steps\n1. Translate the ICP into an Apollo people search — job titles, seniorities, locations, and company size or industry filters.\n2. Run the search, paging through results up to the requested count.\n3. For each person capture name, title, company, verified email status, and LinkedIn URL.\n4. Write the deduplicated prospects to a table for review or sequencing.\n\n## Output\nReport how many prospects matched and the filters used. Flag any with unverified or missing emails.', + }, + { + name: 'enrich-contacts', + description: + 'Enrich one or many contacts through Apollo to refresh titles, emails, phones, and company data. Use to keep CRM records accurate before outreach.', + content: + '# Enrich Contacts\n\nFill in or refresh missing contact data using Apollo enrichment.\n\n## Steps\n1. Gather the contacts to enrich — a single person, or a batch for bulk enrich.\n2. Provide the strongest identifiers available (email, name plus company domain).\n3. Run people enrich or bulk enrich, optionally revealing personal emails or phone numbers.\n4. Merge the returned fields back onto each record, keeping existing values when enrichment returns nothing.\n\n## Output\nReport how many records were enriched versus left unmatched, and which fields were newly filled. Note any credits consumed.', + }, + { + name: 'sync-leads-to-crm', + description: + 'Create or update Apollo contacts and accounts from an inbound lead, then map them into your CRM. Use to route new signups into pipeline.', + content: + '# Sync Leads to CRM\n\nTurn an inbound lead into structured Apollo records.\n\n## Steps\n1. Take the lead details and enrich the person and their company through Apollo.\n2. Create or update the matching Apollo account for the company.\n3. Create or update the contact, linking it to the account and setting owner and stage.\n4. Pass the enriched fields to the connected CRM to create or update the matching records.\n\n## Output\nReport whether each record was created or updated, with the resulting contact and account IDs.', + }, + { + name: 'add-prospects-to-sequence', + description: + 'Search for matching contacts and add them to an Apollo email sequence. Use to launch or top up outbound campaigns.', + content: + '# Add Prospects to Sequence\n\nEnroll the right contacts into an outbound sequence.\n\n## Steps\n1. Identify the target sequence by name or ID, and confirm the sending email account.\n2. Gather the contact IDs to enroll — from a prior search or a provided list.\n3. Add the contacts to the sequence with the chosen sending account and initial status.\n4. Review which contacts were added versus skipped.\n\n## Output\nReport totals added and skipped, and the reason for each skip (already enrolled, unverified, missing ownership).', + }, + { + name: 'pipeline-deal-digest', + description: + 'Search Apollo opportunities by stage and summarize new and at-risk deals into a digest. Use for recurring pipeline reviews.', + content: + '# Pipeline Deal Digest\n\nSummarize opportunity movement for a sales pipeline review.\n\n## Steps\n1. Search Apollo opportunities filtered by the stages you care about.\n2. For each deal capture name, amount, stage, owner, and close date.\n3. Group deals into new, advancing, and at-risk (stalled or past close date).\n4. Write a concise digest grouped by category.\n\n## Output\nA short digest: deal counts and total value per stage, with at-risk deals called out by name, owner, and reason.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/arxiv.ts b/apps/sim/blocks/blocks/arxiv.ts index c67393c97ac..37194610588 100644 --- a/apps/sim/blocks/blocks/arxiv.ts +++ b/apps/sim/blocks/blocks/arxiv.ts @@ -225,4 +225,34 @@ export const ArxivBlockMeta = { tags: ['research', 'content'], }, ], + skills: [ + { + name: 'search-recent-papers', + description: + 'Search ArXiv for the most relevant or most recent papers on a topic and return a ranked, summarized list. Use for literature discovery and topic scans.', + content: + '# Search Recent Papers\n\nFind the papers most worth reading on a given topic.\n\n## Steps\n1. Build the ArXiv query from the topic, choosing the search field (title, abstract, or all) and a result limit.\n2. Sort by relevance for a broad scan, or by submitted date to surface the newest work.\n3. For each result capture title, authors, ArXiv ID, publication date, and abstract.\n4. Write a one-line summary per paper highlighting the contribution.\n\n## Output\nA ranked list of papers with ID, title, authors, date, and a one-line takeaway each. Lead with the most relevant.', + }, + { + name: 'summarize-paper', + description: + 'Fetch a specific ArXiv paper by ID and produce a structured summary of its contribution, method, and results. Use to digest a single paper quickly.', + content: + '# Summarize Paper\n\nProduce a structured read of one ArXiv paper.\n\n## Steps\n1. Fetch the paper details using its ArXiv ID.\n2. Read the abstract and metadata to identify the problem, approach, and headline results.\n3. Note the authors, publication date, and primary category.\n4. Write a structured summary.\n\n## Output\nA brief covering: problem addressed, method, key results, and why it matters — plus the ArXiv ID and link. Keep it tight and skip filler.', + }, + { + name: 'track-author-publications', + description: + "Retrieve an author's recent ArXiv papers and report new work since the last check. Use to follow specific researchers or labs.", + content: + "# Track Author Publications\n\nMonitor a researcher for new ArXiv output.\n\n## Steps\n1. Fetch the author's papers by name, sorted by submitted date.\n2. Compare the results against the previously seen list to find new entries.\n3. For each new paper capture title, ID, date, and abstract.\n4. Summarize what is new since the last check.\n\n## Output\nList only the new papers with title, ID, date, and a one-line summary. If there is nothing new, say so.", + }, + { + name: 'build-literature-review', + description: + 'Search ArXiv on a topic, summarize the key papers, and assemble a themed literature review. Use to bootstrap research on a new area.', + content: + '# Build Literature Review\n\nAssemble a starting literature review for a research topic.\n\n## Steps\n1. Search ArXiv for the most relevant and most cited recent papers on the topic.\n2. Fetch details and summarize each selected paper.\n3. Cluster the papers into themes or sub-questions.\n4. Write a review that introduces the topic, walks through each theme citing the papers, and notes open gaps.\n\n## Output\nA structured review document with a theme-by-theme synthesis and a reference list of ArXiv IDs and titles.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/asana.ts b/apps/sim/blocks/blocks/asana.ts index d9f2868a9e9..c81902360e6 100644 --- a/apps/sim/blocks/blocks/asana.ts +++ b/apps/sim/blocks/blocks/asana.ts @@ -441,4 +441,27 @@ export const AsanaBlockMeta = { alsoIntegrations: ['github'], }, ], + skills: [ + { + name: 'create-task-from-request', + description: + 'Turn an incoming request or message into a well-formed Asana task in the right project with assignee and due date. Use for intake and ticket creation.', + content: + '# Create Task from Request\n\nConvert an incoming request into a structured Asana task.\n\n## Steps\n1. Extract the work to be done, the relevant project, an assignee if named, and any due date.\n2. If the project is referenced by name, list projects to resolve its ID.\n3. Create the task with a clear name, a description capturing the request details, the project, assignee, and due date.\n4. Add a comment with any links or source context if helpful.\n\n## Output\nReport the created task name, its URL or ID, project, assignee, and due date.', + }, + { + name: 'summarize-project-tasks', + description: + 'Search tasks in an Asana project and summarize status, overdue items, and who owns what. Use for standups and project status checks.', + content: + '# Summarize Project Tasks\n\nProduce a status snapshot of an Asana project.\n\n## Steps\n1. Resolve the project, then search its tasks.\n2. For each task capture name, assignee, due date, and completion state.\n3. Group into completed, in progress, and overdue or due soon.\n4. Note any unassigned tasks or tasks with no due date.\n\n## Output\nA concise status summary: counts per group, overdue tasks called out by name and owner, and any gaps to address.', + }, + { + name: 'update-task-status', + description: + 'Find an Asana task and update its fields — assignee, due date, completion, or add a progress comment. Use to keep tasks current from other systems.', + content: + '# Update Task Status\n\nKeep an Asana task in sync with the latest state.\n\n## Steps\n1. Identify the target task by ID, or search to find it by name.\n2. Read the current task to confirm it is the right one.\n3. Update the relevant fields — completion, assignee, or due date.\n4. Add a comment summarizing what changed and why.\n\n## Output\nReport which fields changed and confirm the task ID. If no matching task was found, say so.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/ashby.ts b/apps/sim/blocks/blocks/ashby.ts index b76689765b2..823057a2ee0 100644 --- a/apps/sim/blocks/blocks/ashby.ts +++ b/apps/sim/blocks/blocks/ashby.ts @@ -1040,4 +1040,27 @@ export const AshbyBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'add-candidate', + description: + 'Create a candidate in Ashby from an inbound application or referral and attach them to a job. Use for sourcing and referral intake.', + content: + '# Add Candidate\n\nCapture a new candidate into Ashby and link them to the right role.\n\n## Steps\n1. Gather the candidate name, email, source, and the target job.\n2. If the job is named, list jobs to resolve its ID.\n3. Create the candidate, then create an application linking them to the job with the correct source.\n4. Add a note with referral context or screening details, and apply any relevant tags.\n\n## Output\nReport the created candidate and application IDs, the linked job, and the source applied.', + }, + { + name: 'advance-candidate-stage', + description: + 'Move a candidate application to a new interview stage in Ashby and log the decision. Use to keep the pipeline moving after interviews.', + content: + '# Advance Candidate Stage\n\nProgress a candidate through the hiring pipeline.\n\n## Steps\n1. Find the application — by ID, or list applications for the candidate or job.\n2. Confirm the current stage by getting the application.\n3. Change the application stage to the target stage.\n4. Add a note capturing the rationale and any interview feedback.\n\n## Output\nConfirm the candidate, the stage moved from and to, and the note added.', + }, + { + name: 'pipeline-status-report', + description: + 'List candidates and applications by status or job in Ashby and summarize pipeline health. Use for recruiting standups and weekly reports.', + content: + '# Pipeline Status Report\n\nSummarize the state of an Ashby hiring pipeline.\n\n## Steps\n1. List the relevant jobs, or focus on one role.\n2. List applications, grouping candidates by current stage and status (active, hired, archived).\n3. Flag candidates stalled in a stage or awaiting feedback.\n4. Note new candidates added since the last report.\n\n## Output\nA pipeline summary: candidate counts per stage and status, stalled candidates called out by name and role, and recent additions.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/athena.ts b/apps/sim/blocks/blocks/athena.ts index 2b046a01ecd..afb2a563e25 100644 --- a/apps/sim/blocks/blocks/athena.ts +++ b/apps/sim/blocks/blocks/athena.ts @@ -542,4 +542,27 @@ export const AthenaBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'run-query', + description: + 'Run a SQL query against data in S3 via Athena, wait for completion, and return the results. Use for ad-hoc analysis and reporting over your data lake.', + content: + '# Run Query\n\nExecute a SQL query in Athena and return the results.\n\n## Steps\n1. Compose the SQL, naming the database and confirming the output location.\n2. Start the query to obtain a query execution ID.\n3. Poll get query execution until the state is SUCCEEDED, FAILED, or CANCELLED.\n4. On success, fetch the query results and shape the rows into a clean table.\n\n## Output\nReturn the result rows plus the execution ID, data scanned, and runtime. On failure, surface the Athena error message and the SQL that caused it.', + }, + { + name: 'scheduled-metrics-report', + description: + 'Run a saved or composed Athena query on a schedule to compute metrics and produce a report. Use for recurring KPI and usage reporting.', + content: + '# Scheduled Metrics Report\n\nCompute recurring metrics from data in S3.\n\n## Steps\n1. Use a named query, or compose the metrics SQL for the reporting period.\n2. Start the query and poll execution until it completes.\n3. Fetch the results and format the metrics for reporting.\n4. Compare against the prior period to highlight movement where relevant.\n\n## Output\nA metrics summary with current values, period-over-period change, and the execution ID for traceability.', + }, + { + name: 'manage-named-queries', + description: + 'Create, look up, and list saved (named) queries in Athena to standardize reusable SQL. Use to maintain a library of vetted analytics queries.', + content: + '# Manage Named Queries\n\nMaintain a library of reusable Athena queries.\n\n## Steps\n1. To save a query, create a named query with a clear name, description, database, and the SQL body.\n2. To reuse one, list named queries or get a named query by ID to retrieve its SQL.\n3. Run the retrieved SQL via start query when execution is needed.\n4. Keep names and descriptions accurate so the right query is easy to find.\n\n## Output\nReport the named query ID and name for creates, or the resolved SQL for lookups.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/attio.ts b/apps/sim/blocks/blocks/attio.ts index e57eb782f5d..4d7b81af753 100644 --- a/apps/sim/blocks/blocks/attio.ts +++ b/apps/sim/blocks/blocks/attio.ts @@ -1398,4 +1398,34 @@ export const AttioBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'upsert-record', + description: + 'Create or update a person, company, or deal record in Attio, matching on a key field to avoid duplicates. Use to sync external data into the CRM.', + content: + '# Upsert Record\n\nKeep an Attio record in sync without creating duplicates.\n\n## Steps\n1. Identify the target object (people, companies, or a custom object) and the matching attribute, such as email or domain.\n2. Assemble the record values to set.\n3. Use assert record to upsert on the matching attribute so an existing record is updated and a new one is created only when needed.\n4. Verify the resulting record by getting it back.\n\n## Output\nReport whether the record was created or updated and its record ID.', + }, + { + name: 'log-note-on-record', + description: + 'Attach a note to an Attio record capturing a call, meeting, or update. Use to keep CRM context current after interactions.', + content: + '# Log Note on Record\n\nRecord context against the right Attio record.\n\n## Steps\n1. Find the target record — by ID, or search records to locate it by name or domain.\n2. Compose the note title and body summarizing the interaction or update.\n3. Create the note on that record.\n4. Optionally create a follow-up task if next steps were agreed.\n\n## Output\nConfirm the record the note was attached to and the note ID, plus any follow-up task created.', + }, + { + name: 'create-followup-task', + description: + 'Create a task in Attio linked to a record with an owner and due date. Use to capture follow-ups and next steps from deals or conversations.', + content: + '# Create Follow-up Task\n\nTurn a next step into a tracked Attio task.\n\n## Steps\n1. Identify the related record and the work to be done.\n2. Determine the assignee and a due date.\n3. Create the task with a clear description, linked record, owner, and deadline.\n4. Confirm the task was created against the right record.\n\n## Output\nReport the created task ID, the linked record, assignee, and due date.', + }, + { + name: 'manage-list-pipeline', + description: + 'Query and update entries in an Attio list to move records through a pipeline or segment. Use for managing deal stages and curated segments.', + content: + '# Manage List Pipeline\n\nMove records through an Attio list-based pipeline.\n\n## Steps\n1. Resolve the target list, then query list entries to see current state.\n2. Identify which entries need to change stage or attributes.\n3. Create, update, or remove list entries as needed to reflect the new state.\n4. Summarize the pipeline distribution after the changes.\n\n## Output\nReport which entries moved and their new stage, plus the resulting count of records per stage.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/azure_devops.ts b/apps/sim/blocks/blocks/azure_devops.ts index 2187f03f778..84703f320b7 100644 --- a/apps/sim/blocks/blocks/azure_devops.ts +++ b/apps/sim/blocks/blocks/azure_devops.ts @@ -697,4 +697,34 @@ export const AzureDevOpsBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'triage-build-failure', + description: + 'Investigate a failed Azure DevOps build, pinpoint the failing stage, and summarize the root cause. Use when a pipeline run breaks.', + content: + '# Triage Build Failure\n\nDiagnose why an Azure DevOps build failed.\n\n## Steps\n1. Use Get Build Timeline for the build id to find which stage, job, or task failed.\n2. Use List Build Logs to locate the log id for the failing step, then Get Build Log to read its contents.\n3. Scan the log for the first error, the failing command, and the exit code; ignore noise after the initial failure.\n4. Optionally use Get Work Items Between Builds against the last successful build to see what changed.\n\n## Output\nReturn a concise root-cause summary: the failing stage/task, the key error line, the likely cause, and a suggested next action. Include a deep link to the run when available.', + }, + { + name: 'create-work-item', + description: + 'Create a new Azure DevOps work item (Issue, Task, or Epic) with the right fields. Use to file bugs, tasks, or features from another system.', + content: + '# Create Work Item\n\nFile a structured Azure DevOps work item.\n\n## Steps\n1. Choose the work item type: Issue, Task, or Epic, matching the request.\n2. Use Create Work Item with a clear title and an HTML or plain-text description.\n3. Set context fields where known: assignee, priority (1-4), area path, iteration path, and semicolon-separated tags.\n4. For a Task, set Activity, Remaining Work, and Completed Work; for an Epic, set Start Date and Target Date.\n\n## Output\nReturn the new work item id, type, title, state, and a link. Confirm the assignee and iteration. If a required field is missing, ask for it rather than guessing.', + }, + { + name: 'generate-release-notes', + description: + 'Compile release notes from the work items completed between two Azure DevOps builds. Use at release time to summarize what shipped.', + content: + '# Generate Release Notes\n\nProduce release notes for a build range.\n\n## Steps\n1. Identify the From Build ID (previous release) and To Build ID (current release).\n2. Use Get Work Items Between Builds to list the associated work items.\n3. For each work item, use Get Work Items Batch or Get Work Item to pull title, type, and state.\n4. Group items by type (Features/Epics, Tasks, Bugs/Issues) and write a one-line summary per item.\n\n## Output\nReturn formatted Markdown release notes grouped by category, each line linking the work item id and title. Add a short headline summary of the most user-facing changes at the top.', + }, + { + name: 'report-pipeline-health', + description: + 'Summarize recent Azure DevOps pipeline run results to surface pass rate and regressions. Use for daily or weekly engineering health reports.', + content: + '# Report Pipeline Health\n\nSummarize recent pipeline reliability.\n\n## Steps\n1. Use List Pipelines to enumerate the pipelines you care about.\n2. For each, use List Pipeline Runs to pull recent runs within your window.\n3. Compute pass rate (succeeded vs total), average duration, and the count of recent failures per pipeline.\n4. Flag pipelines whose pass rate dropped or whose duration increased noticeably versus prior runs.\n\n## Output\nReturn a per-pipeline summary table (name, pass rate, avg duration, recent failures) and a short narrative calling out regressions and any pipeline that is consistently red.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/box.ts b/apps/sim/blocks/blocks/box.ts index ef681776476..96a9e83c835 100644 --- a/apps/sim/blocks/blocks/box.ts +++ b/apps/sim/blocks/blocks/box.ts @@ -669,4 +669,34 @@ export const BoxBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'send-document-for-signature', + description: + 'Send a Box document for e-signature and confirm the request. Use for contracts, NDAs, and approval forms that need a signer.', + content: + '# Send Document For Signature\n\nKick off a Box Sign request for one or more documents.\n\n## Steps\n1. Identify the Box file id(s) to sign (use Search or List Folder Items if you only have a name).\n2. Use Create Sign Request with the source file ids and the primary signer email; set the signer role (signer, approver, or final copy reader).\n3. Add a clear email subject and message, and add any additional signers as a JSON array of email/role objects.\n4. Optionally set a destination folder for the signed copy, days valid, and reminders.\n\n## Output\nReturn the sign request id, status, signer list, and the prepare/sign URL. Tell the user the request was sent and how to track it. If a file id cannot be resolved, ask for clarification.', + }, + { + name: 'track-signature-status', + description: + 'Check the status of Box Sign requests and follow up on pending signers. Use to monitor outstanding e-signature requests.', + content: + '# Track Signature Status\n\nReport on outstanding and completed Box Sign requests.\n\n## Steps\n1. Use List Sign Requests to retrieve recent requests, paging with the marker when needed.\n2. For a specific request, use Get Sign Request with the sign request id to read per-signer status.\n3. Identify requests that are still pending versus signed, declined, or expired.\n4. For stalled requests, use Resend Sign Request to nudge signers, or Cancel Sign Request if it is no longer needed.\n\n## Output\nReturn a status summary per request: name, overall status, which signers have signed, and which are outstanding. Recommend resend or cancel actions for stale requests.', + }, + { + name: 'organize-files-into-folder', + description: + 'Upload files into a structured Box folder, creating folders as needed. Use to file documents into a standard organized layout.', + content: + '# Organize Files Into Folder\n\nPlace documents into the correct Box folder structure.\n\n## Steps\n1. Determine the destination. Use List Folder Items or Search to find an existing folder, or Create Folder under the right parent (use "0" for root) if it does not exist.\n2. Upload each file with Upload File, setting the parent folder id and an explicit file name when needed.\n3. To reorganize existing files, use Update File to rename, move (set Move to Folder ID), tag, or describe them.\n4. Use Copy File when a document must live in more than one folder.\n\n## Output\nReturn the created folder id (if any) and a list of the files placed, each with its id, name, and final folder. Confirm the resulting structure.', + }, + { + name: 'search-box-content', + description: + 'Find files and folders in Box matching a query and return their details. Use to locate documents before acting on them.', + content: + '# Search Box Content\n\nLocate documents in Box.\n\n## Steps\n1. Use Search with the query string. Narrow with optional filters: ancestor folder id, file extensions (e.g. pdf,docx), and content type (file, folder, or web link).\n2. Page through results with limit and offset if there are many matches.\n3. For promising hits, use Get File Info to confirm name, size, owner, and modified date.\n\n## Output\nReturn the matching items with id, name, type, owner, and last-modified date. If the query is ambiguous or returns too many results, suggest a tighter query or folder scope.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/brandfetch.ts b/apps/sim/blocks/blocks/brandfetch.ts index 9415383f8b7..48ba23ca9eb 100644 --- a/apps/sim/blocks/blocks/brandfetch.ts +++ b/apps/sim/blocks/blocks/brandfetch.ts @@ -169,4 +169,27 @@ export const BrandfetchBlockMeta = { alsoIntegrations: ['docusign'], }, ], + skills: [ + { + name: 'enrich-company-by-domain', + description: + 'Look up a company by domain and return its brand assets and firmographics. Use to enrich a CRM record, lead, or account with logo, colors, and company data.', + content: + '# Enrich Company By Domain\n\nFetch brand and company data for a known domain.\n\n## Steps\n1. Use Get Brand with the company domain as the identifier (e.g. nike.com). A stock ticker, ISIN, or crypto symbol also works.\n2. Read the returned logos, colors, fonts, links, description, and company firmographics.\n3. Pick the best logo for the use case (prefer a transparent or themed variant) and the primary brand color.\n\n## Output\nReturn a tidy record: company name, domain, description, primary logo URL, primary brand color hex, social links, and key firmographics. If the quality score is low or the brand is unclaimed, note that the data may be incomplete.', + }, + { + name: 'resolve-brand-by-name', + description: + 'Search for a brand by name to find its domain and logo when you only have the company name. Use to disambiguate or resolve a domain before deeper enrichment.', + content: + '# Resolve Brand By Name\n\nFind a brand when you only know its name.\n\n## Steps\n1. Use Search Brands with the company name (e.g. "Nike").\n2. Review the results array; each entry has a brand name, domain, and icon.\n3. Choose the best match by exact name and most likely official domain.\n4. Optionally follow up with Get Brand on the chosen domain for full assets and firmographics.\n\n## Output\nReturn the resolved brand name, domain, and icon URL. If several plausible matches exist, list the top candidates with their domains so the user can confirm.', + }, + { + name: 'collect-brand-assets-for-personalization', + description: + 'Gather a prospect or customer brand kit (logo, colors, fonts) for personalizing decks, emails, or portals. Use ahead of personalized outreach or design work.', + content: + '# Collect Brand Assets For Personalization\n\nBuild a usable brand kit for a target company.\n\n## Steps\n1. Resolve the company domain (use Search Brands first if you only have a name).\n2. Use Get Brand to retrieve logos, colors, and fonts.\n3. Select assets fit for purpose: a high-contrast logo for a deck cover, the primary and secondary colors, and the brand font names.\n\n## Output\nReturn a brand kit object: logo URLs by theme (light/dark), an ordered color palette with hex values, and font names. Note any missing asset so the design step can fall back to a neutral default.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/brightdata.ts b/apps/sim/blocks/blocks/brightdata.ts index 9c0ec3c3508..b9cbe04109a 100644 --- a/apps/sim/blocks/blocks/brightdata.ts +++ b/apps/sim/blocks/blocks/brightdata.ts @@ -414,4 +414,34 @@ export const BrightDataBlockMeta = { tags: ['ecommerce', 'research'], }, ], + skills: [ + { + name: 'scrape-page-content', + description: + 'Fetch the content of a single web page through Bright Data Web Unlocker, bypassing bot blocks and geo-restrictions. Use to read a page an agent cannot otherwise access.', + content: + '# Scrape Page Content\n\nRetrieve a page that is normally blocked or geo-restricted.\n\n## Steps\n1. Use Scrape URL with the target URL and your unlocker zone (e.g. web_unlocker1).\n2. Choose the format: Raw HTML for full markup, or JSON for a parsed response.\n3. Set the Country code when the page differs by region.\n4. Run it and read the returned content and HTTP status code.\n\n## Output\nReturn the cleaned page content (text or relevant HTML) and the status code. If the status indicates a block or error, report it and suggest a different zone or country rather than returning empty content.', + }, + { + name: 'search-the-web', + description: + 'Run a search-engine query through Bright Data SERP API and return ranked results. Use for keyword research, competitive monitoring, or grounding an answer in fresh results.', + content: + '# Search The Web\n\nGet structured search results for a query.\n\n## Steps\n1. Use SERP Search with the query and your SERP zone.\n2. Pick the search engine (Google, Bing, DuckDuckGo, or Yandex) and set country/language for localized results.\n3. Set the number of results to the amount you need.\n4. Read the results array (title, URL, snippet, rank).\n\n## Output\nReturn the ranked results as a list with title, URL, and snippet. Summarize the top findings for the user, and note the engine, country, and query used so the result is reproducible.', + }, + { + name: 'discover-pages-by-intent', + description: + 'Find web pages that match a described intent using Bright Data Discover, optionally pulling page content. Use to gather sources on a topic without crafting exact queries.', + content: + '# Discover Pages By Intent\n\nFind relevant pages from a natural-language description.\n\n## Steps\n1. Use Discover with a search query and an Intent describing what you actually want (e.g. "official pricing pages and recent change notes").\n2. Set the number of results, country, and language as needed.\n3. Enable Include Page Content and choose Markdown or JSON when you want the page bodies, not just links.\n\n## Output\nReturn the discovered pages ranked by relevance with URL, title, and (if requested) extracted content. Summarize what was found and flag any low-relevance results so they can be filtered out.', + }, + { + name: 'run-dataset-scraper', + description: + 'Trigger a Bright Data pre-built dataset scraper for structured extraction across many URLs and retrieve the results. Use for bulk structured data from sites like e-commerce or social.', + content: + '# Run Dataset Scraper\n\nExtract structured records across many URLs with a pre-built scraper.\n\n## Steps\n1. Identify the dataset scraper id for the target site (e.g. gd_...).\n2. For small batches (up to 20 URLs), use Sync Scrape to get results back inline; choose JSON, NDJSON, or CSV.\n3. For larger jobs, use Scrape Dataset, which returns a snapshot id.\n4. Poll Snapshot Status until it is ready, then use Download Snapshot to fetch the data. Use Cancel Snapshot to abort a job that is no longer needed.\n\n## Output\nReturn the structured records (or the snapshot id and status for async jobs). For async runs, report progress and only return data once the snapshot is complete.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/browser_use.ts b/apps/sim/blocks/blocks/browser_use.ts index 85e69bb8bf6..3aa06172335 100644 --- a/apps/sim/blocks/blocks/browser_use.ts +++ b/apps/sim/blocks/blocks/browser_use.ts @@ -283,4 +283,27 @@ export const BrowserUseBlockMeta = { tags: ['marketing', 'monitoring'], }, ], + skills: [ + { + name: 'automate-web-task', + description: + 'Drive a browser agent to complete a multi-step task on a website, like navigating, clicking, and submitting. Use when a site has no API and a human would normally do the clicks.', + content: + '# Automate Web Task\n\nHave the browser agent perform a goal-oriented task on the web.\n\n## Steps\n1. Write a clear, step-by-step Task describing the goal and any success condition (e.g. "log in, open Billing, download the latest invoice").\n2. Set the Start URL so the agent begins on the right page.\n3. Put any credentials or sensitive inputs in Variables (Secrets) and reference them in the task by name rather than pasting them inline.\n4. Restrict Allowed Domains to keep the agent on the intended site, and raise Max Steps for longer flows.\n\n## Output\nReturn whether the task succeeded, the final output, and the share URL for the recorded session so the run can be audited. If the agent gets stuck, report the last step and what blocked it.', + }, + { + name: 'extract-structured-data-from-site', + description: + 'Use a browser agent to navigate a site and return data in a defined JSON schema. Use to pull structured records (prices, listings, table rows) from pages without an API.', + content: + '# Extract Structured Data From Site\n\nNavigate a website and return structured data.\n\n## Steps\n1. Write a Task that tells the agent what to find and where (e.g. "go to the pricing page and collect every plan name and monthly price").\n2. Set the Start URL and limit Allowed Domains to the target site.\n3. Provide a Structured Output Schema (stringified JSON schema) describing the exact fields you want back.\n4. Run it; the agent fills the schema from what it observes on the page.\n\n## Output\nReturn the data as objects matching the provided schema. Confirm each field was actually found on the page; if a field could not be located, leave it null and note it rather than fabricating a value.', + }, + { + name: 'fill-and-submit-form', + description: + 'Have a browser agent fill out and submit a web form using supplied field values. Use for vendor portals, questionnaires, or applications that have no API.', + content: + '# Fill And Submit Form\n\nComplete a web form end to end.\n\n## Steps\n1. Describe the form and the mapping of values to fields in the Task (e.g. "fill the contact form: name, company, message, then submit").\n2. Set the Start URL to the form page and constrain Allowed Domains.\n3. Pass any private values through Variables (Secrets) so they are injected securely.\n4. Ask the agent to confirm the submission succeeded (look for a success message or confirmation page) before finishing.\n\n## Output\nReturn whether the form submitted successfully, any confirmation text or reference number shown, and the session share URL as an audit trail. If a required field was missing or validation failed, report which field and why.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/calcom.ts b/apps/sim/blocks/blocks/calcom.ts index 72735ce1531..3c63ad31e53 100644 --- a/apps/sim/blocks/blocks/calcom.ts +++ b/apps/sim/blocks/blocks/calcom.ts @@ -991,4 +991,34 @@ export const CalComBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'book-a-meeting', + description: + 'Create a Cal.com booking for an attendee on a chosen event type and time. Use to schedule a call once you know the slot and attendee details.', + content: + '# Book A Meeting\n\nCreate a confirmed Cal.com booking.\n\n## Steps\n1. Identify the event type to book (select it or pass its numeric event type id).\n2. Set the Start Time as an ISO 8601 UTC timestamp.\n3. Provide the attendee name, email, and IANA time zone (e.g. America/New_York). Add guests or a duration override if needed.\n4. Create the booking.\n\n## Output\nReturn the booking UID, start and end time, attendee, and the meeting URL. Confirm the booking to the user. If the slot is unavailable, suggest checking available slots first and propose alternatives.', + }, + { + name: 'find-available-slots', + description: + 'Look up open time slots for a Cal.com event type within a date range. Use before booking to offer the attendee valid times.', + content: + '# Find Available Slots\n\nRetrieve bookable time slots for an event type.\n\n## Steps\n1. Select the event type (or pass its id, or an event type slug plus username).\n2. Set the Start Time and End Time of the window to search (ISO 8601 UTC).\n3. Set the attendee time zone so slots are returned in their local time, and a duration if the event supports multiple lengths.\n4. Read the returned slots.\n\n## Output\nReturn the available slots as a clean list of start times in the requested time zone. Summarize the next few openings for the user; if none exist in the window, widen the range and retry.', + }, + { + name: 'reschedule-or-cancel-booking', + description: + 'Move a Cal.com booking to a new time or cancel it, with a reason. Use to handle change or cancellation requests for an existing booking.', + content: + '# Reschedule Or Cancel Booking\n\nChange or cancel an existing Cal.com booking.\n\n## Steps\n1. Identify the booking by its UID (use List Bookings to find it if you only have attendee or date details).\n2. To move it, use Reschedule Booking with the new Start Time (ISO 8601) and an optional rescheduling reason.\n3. To cancel, use Cancel Booking with an optional cancellation reason.\n4. For request-based event types, use Confirm Booking or Decline Booking instead.\n\n## Output\nReturn the booking UID and its new status (rescheduled, cancelled, confirmed, or declined) plus the updated time when applicable. Confirm the change to the user.', + }, + { + name: 'summarize-upcoming-bookings', + description: + 'List and summarize upcoming Cal.com bookings for a period. Use for a daily agenda or to brief a host on their schedule.', + content: + '# Summarize Upcoming Bookings\n\nProduce an agenda from Cal.com bookings.\n\n## Steps\n1. Use List Bookings with status Upcoming.\n2. For each booking, read the title, start/end time, attendees, and meeting URL.\n3. Sort chronologically and group by day if the range spans multiple days.\n\n## Output\nReturn an ordered agenda: each entry with time, title, attendee name, and join link. Add a short headline like the number of meetings and the first start time so the host gets a quick read on the day.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/calendly.ts b/apps/sim/blocks/blocks/calendly.ts index 7c6fbb0c1a8..1b85477515b 100644 --- a/apps/sim/blocks/blocks/calendly.ts +++ b/apps/sim/blocks/blocks/calendly.ts @@ -401,4 +401,27 @@ export const CalendlyBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'list-upcoming-meetings', + description: + 'Pull upcoming Calendly scheduled events for a date range and summarize them. Use to brief a host on their schedule or build a daily agenda.', + content: + '# List Upcoming Meetings\n\nSummarize upcoming Calendly events.\n\n## Steps\n1. Use List Scheduled Events. Filter to status active and set Min Start Time and Max Start Time (ISO 8601 UTC) for the window.\n2. Filter by user or organization URI when scoping to a specific host (Get Current User returns your URI if needed).\n3. For each event, read name, start_time, end_time, location, and scheduling_url; page with the page token if there are many.\n\n## Output\nReturn an ordered agenda: each meeting with time, name, location/join link, and the invitee. Add a one-line headline (count and first start time) for a quick read.', + }, + { + name: 'get-event-attendees', + description: + 'Retrieve the invitees for a Calendly scheduled event, including answers and contact info. Use to prep for a meeting or sync attendees to a CRM.', + content: + '# Get Event Attendees\n\nList who is attending a Calendly event.\n\n## Steps\n1. Identify the scheduled event by its UUID or URI (use List Scheduled Events to locate it).\n2. Use List Event Invitees for that event; optionally filter by email or status.\n3. Read each invitee record: name, email, status, and any questions and answers captured at booking.\n\n## Output\nReturn the invitees with name, email, status, and their intake answers. Flag canceled or no-show invitees so they can be handled differently from confirmed attendees.', + }, + { + name: 'cancel-scheduled-event', + description: + 'Cancel a Calendly scheduled event with an optional reason. Use to call off a meeting and notify the invitee through Calendly.', + content: + '# Cancel Scheduled Event\n\nCall off a Calendly meeting.\n\n## Steps\n1. Find the scheduled event UUID or URI (use List Scheduled Events filtered by invitee email or time if you only have those details).\n2. Use Cancel Event with the event UUID and a clear cancellation reason.\n3. Calendly notifies the invitee automatically.\n\n## Output\nReturn the event UUID and confirmation that it was canceled. Echo the reason. If the event is already canceled or cannot be found, report that instead of retrying.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/clay.ts b/apps/sim/blocks/blocks/clay.ts index 96e3b5c3ab2..e3e0e5df366 100644 --- a/apps/sim/blocks/blocks/clay.ts +++ b/apps/sim/blocks/blocks/clay.ts @@ -140,4 +140,20 @@ export const ClayBlockMeta = { tags: ['sales', 'automation', 'enrichment'], }, ], + skills: [ + { + name: 'push-record-to-clay', + description: + 'Send a single contact or account record to a Clay table via its populate webhook so Clay can enrich it. Use to hand a lead off to a Clay enrichment waterfall.', + content: + '# Push Record To Clay\n\nSend one record into a Clay table for enrichment.\n\n## Steps\n1. Get the Clay table populate webhook URL (Clay shows it on the table when you add a "Webhook" source).\n2. Build the record as a JSON object whose keys match the Clay table column names you want to populate (e.g. name, email, company, domain, linkedin_url).\n3. If the table has webhook authentication enabled, supply the auth token; it is sent in the x-clay-webhook-auth header.\n4. Populate the table with the record.\n\n## Output\nReturn the webhook response and metadata (status, timestamp). Confirm the record was accepted. Note that enrichment runs asynchronously inside Clay, so the enriched columns appear there, not in the immediate response.', + }, + { + name: 'bulk-load-list-into-clay', + description: + 'Push many prospect or account rows from a table into a Clay workbook for enrichment. Use to seed a lead list or sync a CRM segment into Clay.', + content: + '# Bulk Load List Into Clay\n\nLoad a list of records into a Clay table.\n\n## Steps\n1. Gather the source rows (e.g. from a Sim table or a CRM query).\n2. Get the Clay table populate webhook URL and any auth token.\n3. For each row, map your fields to the Clay column names and populate the table once per record. Keep the JSON keys consistent across all records so columns line up.\n4. Send the records, pacing them if the list is large.\n\n## Output\nReturn a count of records pushed and any that failed (with the error). Remind the user that Clay enriches the rows on its side, and suggest they verify the row count in the Clay table once ingestion completes.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/clerk.ts b/apps/sim/blocks/blocks/clerk.ts index 11ad630f83e..06529d41456 100644 --- a/apps/sim/blocks/blocks/clerk.ts +++ b/apps/sim/blocks/blocks/clerk.ts @@ -483,4 +483,34 @@ export const ClerkBlockMeta = { alsoIntegrations: ['s3'], }, ], + skills: [ + { + name: 'find-user', + description: + 'Look up a Clerk user by email, username, or name and return their profile. Use to resolve a user before acting on their account or syncing them elsewhere.', + content: + '# Find User\n\nLocate a Clerk user account.\n\n## Steps\n1. Use List Users with a Search Query (matches email, phone, username, or name), or the email/username filters for an exact match.\n2. If you already have the Clerk user id (user_...), use Get User instead for the full record.\n3. Review the returned profile: id, primary email, name, externalId, and flags like banned, locked, and twoFactorEnabled.\n\n## Output\nReturn the matched user id, primary email, name, and key status flags. If multiple users match, list the candidates with their emails so the right one can be confirmed; if none match, say so.', + }, + { + name: 'provision-user', + description: + 'Create or update a Clerk user with email, name, and metadata. Use to onboard a user or sync profile changes from another system into Clerk.', + content: + '# Provision User\n\nCreate or update a Clerk user.\n\n## Steps\n1. To create, use Create User with at least an email address (and optionally phone, username, password, first/last name).\n2. To set application roles or app data, pass Public Metadata (visible to the frontend) and Private Metadata (server-only) as JSON.\n3. Set External ID to link the Clerk user to your own system id.\n4. To modify an existing user, use Update User with the user id and only the fields that change.\n\n## Output\nReturn the user id, primary email, and the metadata that was set. Confirm whether the user was created or updated. If a required field is missing or the email already exists, report it clearly.', + }, + { + name: 'audit-user-sessions', + description: + 'List and inspect a Clerk user active sessions and revoke suspicious ones. Use for security review or forced sign-out.', + content: + '# Audit User Sessions\n\nReview and control Clerk sessions.\n\n## Steps\n1. Use List Sessions filtered by user id and status (e.g. active) to see current sessions.\n2. For a specific session, use Get Session to read its details: client, status, lastActiveAt.\n3. Identify sessions that look risky (stale, unexpected client, or flagged by your own logic).\n4. Use Revoke Session with the session id to force sign-out of any session that should not continue.\n\n## Output\nReturn the list of sessions reviewed with status and last-active time, and the ids of any sessions revoked. Summarize the action taken so the security trail is clear.', + }, + { + name: 'manage-organization', + description: + 'Create a Clerk organization or look up its details and membership. Use when provisioning a new team or tenant in a multi-tenant app.', + content: + '# Manage Organization\n\nCreate or inspect a Clerk organization.\n\n## Steps\n1. To create, use Create Organization with the organization name and the Creator User ID (that user becomes the admin); optionally set a slug and max members.\n2. To inspect, use Get Organization by org id or slug, or List Organizations with a search query and include members count.\n3. Read back the org id, slug, members count, and limits.\n\n## Output\nReturn the organization id, name, slug, and member count. When creating, confirm the admin user and echo the org id so it can be linked back to your billing or CRM record.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/clickhouse.ts b/apps/sim/blocks/blocks/clickhouse.ts index c153d8f0ee3..08ec36799e8 100644 --- a/apps/sim/blocks/blocks/clickhouse.ts +++ b/apps/sim/blocks/blocks/clickhouse.ts @@ -497,4 +497,27 @@ export const ClickHouseBlockMeta = { tags: ['data-analytics', 'data-warehouse'], }, ], + skills: [ + { + name: 'answer-question-with-sql', + description: + 'Translate a plain-English analytics question into ClickHouse SQL, run it, and return the answer. Use for ad-hoc data questions over a ClickHouse table.', + content: + '# Answer Question With SQL\n\nTurn a natural-language question into a ClickHouse query and report the result.\n\n## Steps\n1. If you do not know the schema, use Introspect Schema or Describe Table to learn the columns and types.\n2. Write a ClickHouse SELECT using ClickHouse functions (toDate, uniqExact, quantile, etc.). Filter on primary/sorting keys and add a LIMIT for exploratory queries.\n3. Run it with the Query (SELECT) operation against the connection (host, port, database, credentials).\n4. Inspect the returned rows and row count.\n\n## Output\nReturn the result as a small table plus a one-sentence answer to the original question. Include the SQL you ran so it is reproducible. If the query errors, report the message and adjust the SQL rather than guessing blindly.', + }, + { + name: 'summarize-metrics', + description: + 'Run aggregation queries against ClickHouse and summarize key metrics and trends. Use for a recurring metrics digest or dashboard refresh.', + content: + '# Summarize Metrics\n\nCompute and summarize metrics from ClickHouse.\n\n## Steps\n1. Confirm the relevant table and time column with Describe Table if needed.\n2. Write aggregation queries (e.g. daily uniqExact users, counts, quantiles over a time window) using Query (SELECT).\n3. Run each query against the connection and collect the results.\n4. Compare against the prior period to spot increases, drops, or anomalies.\n\n## Output\nReturn a concise digest: the headline numbers, period-over-period change, and any notable anomalies. Keep it readable, lead with the most important metric, and note the time window covered.', + }, + { + name: 'bulk-insert-events', + description: + 'Insert a batch of rows into a ClickHouse table after mapping them to the right columns. Use to ingest event or record payloads into ClickHouse.', + content: + '# Bulk Insert Events\n\nLoad a batch of records into a ClickHouse table.\n\n## Steps\n1. Use Describe Table to confirm the target column names and types.\n2. Map each incoming payload to those columns, coercing types (e.g. timestamps to DateTime format, numbers to the right width).\n3. Build a JSON array of row objects with consistent keys, then use Insert Rows (Bulk) against the table.\n4. Verify with Count Rows or a small SELECT.\n\n## Output\nReturn the number of rows inserted and any rows that were skipped or failed validation, with the reason. Confirm the new total row count so the caller knows ingestion succeeded.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/cloudflare.ts b/apps/sim/blocks/blocks/cloudflare.ts index 582e89ddb3f..0a15f70491a 100644 --- a/apps/sim/blocks/blocks/cloudflare.ts +++ b/apps/sim/blocks/blocks/cloudflare.ts @@ -1169,4 +1169,27 @@ export const CloudflareBlockMeta = { tags: ['devops', 'enterprise', 'monitoring'], }, ], + skills: [ + { + name: 'audit-dns-records', + description: + 'Pull all DNS records for a Cloudflare zone and report on misconfigurations, dangling records, and sensitive record changes.', + content: + '# Audit Cloudflare DNS Records\n\nExport and review the DNS configuration for a zone to catch misconfigurations and risky records.\n\n## Steps\n1. Resolve the zone ID for the target domain.\n2. List every DNS record (A, AAAA, CNAME, MX, TXT, NS) for the zone.\n3. Flag records that point to deprovisioned hosts, wildcard CNAMEs, missing SPF/DMARC TXT records, and proxied vs. unproxied mismatches.\n4. Group findings by record type and severity.\n\n## Output\nA prioritized list of DNS issues with the record name, type, current value, and recommended fix.', + }, + { + name: 'purge-cache', + description: + 'Purge Cloudflare cache for specific URLs or an entire zone after a deploy, then confirm what was cleared.', + content: + '# Purge Cloudflare Cache\n\nClear cached content so visitors see the latest deploy.\n\n## Steps\n1. Identify the affected zone and the paths or hostnames that changed.\n2. Purge by specific files when possible; only purge everything for the zone if the change is global.\n3. Confirm the purge succeeded and note the timestamp.\n\n## Output\nA short confirmation listing the zone, the purged URLs (or "full zone"), and the purge time.', + }, + { + name: 'check-ssl-and-zone-settings', + description: + 'Inspect SSL certificate status and security settings for Cloudflare zones and report drift from a desired baseline.', + content: + '# Check SSL and Zone Settings\n\nVerify SSL/TLS posture and key security settings across zones.\n\n## Steps\n1. List the target zones.\n2. For each zone read SSL mode, certificate status/expiry, minimum TLS version, and security level.\n3. Compare against the desired baseline (e.g. Full Strict, TLS 1.2+).\n4. Flag expiring certs and any setting weaker than the baseline.\n\n## Output\nA per-zone table of SSL status, settings, and any drift that needs remediation.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/cloudformation.ts b/apps/sim/blocks/blocks/cloudformation.ts index 7e33206442e..84cc442eab3 100644 --- a/apps/sim/blocks/blocks/cloudformation.ts +++ b/apps/sim/blocks/blocks/cloudformation.ts @@ -400,4 +400,27 @@ export const CloudFormationBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'detect-stack-drift', + description: + 'Run drift detection on CloudFormation stacks and summarize resources whose live config no longer matches the template.', + content: + '# Detect CloudFormation Stack Drift\n\nFind resources that have been changed outside of CloudFormation.\n\n## Steps\n1. List the target stacks (or accept a specific stack name).\n2. Initiate drift detection for each stack and poll until detection completes.\n3. Pull the drift results and isolate resources with status DRIFTED or DELETED.\n4. For each drifted resource, summarize the property differences.\n\n## Output\nA per-stack drift report listing each drifted resource, its type, and the specific properties that differ from the template.', + }, + { + name: 'inventory-stacks', + description: + 'List CloudFormation stacks with their status, region, and resources to build a single inventory of deployed infrastructure.', + content: + '# Inventory CloudFormation Stacks\n\nBuild a unified view of all deployed stacks.\n\n## Steps\n1. List every stack and capture name, status, creation/update time, and region.\n2. For each stack, describe its resources and count them by type.\n3. Highlight stacks in failed or rollback states.\n\n## Output\nA table of stacks with status, region, resource count, and any stacks needing attention.', + }, + { + name: 'investigate-stack-failure', + description: + 'Pull recent CloudFormation stack events to diagnose a failed create, update, or rollback and explain the root cause.', + content: + '# Investigate CloudFormation Stack Failure\n\nDiagnose why a stack operation failed.\n\n## Steps\n1. Describe the target stack and confirm its current status.\n2. Pull recent stack events, ordered newest first.\n3. Find the first FAILED event and read its resource status reason.\n4. Trace any dependent resource failures that cascaded from it.\n\n## Output\nA plain-English root-cause summary naming the failing resource, the error reason, and a suggested fix.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/cloudwatch.ts b/apps/sim/blocks/blocks/cloudwatch.ts index 309124d0e6a..7b5d80a8e82 100644 --- a/apps/sim/blocks/blocks/cloudwatch.ts +++ b/apps/sim/blocks/blocks/cloudwatch.ts @@ -950,4 +950,27 @@ export const CloudWatchBlockMeta = { alsoIntegrations: ['linear', 'slack'], }, ], + skills: [ + { + name: 'investigate-error-spike', + description: + 'Run a CloudWatch Logs Insights query to find and summarize error spikes in a log group over a time window.', + content: + '# Investigate CloudWatch Error Spike\n\nFind the cause of an error spike using Logs Insights.\n\n## Steps\n1. Identify the relevant log group and the time window to investigate.\n2. Run a Logs Insights query that filters for error or exception lines and aggregates by error type.\n3. Pull representative sample log events for the top error groups.\n4. Correlate timing with any recent deploys or traffic changes.\n\n## Output\nA summary of the top error types, their counts, sample messages, and the likely cause.', + }, + { + name: 'check-metric-health', + description: + 'Pull CloudWatch metric statistics for a resource and report whether key metrics are within healthy ranges.', + content: + '# Check CloudWatch Metric Health\n\nReview key metrics for a resource against expected thresholds.\n\n## Steps\n1. Identify the namespace, metric names, and dimensions for the resource (e.g. CPUUtilization, latency, error rate).\n2. Get metric statistics over the chosen window with an appropriate period and statistic (Average, p99, Sum).\n3. Compare values against healthy thresholds.\n\n## Output\nA per-metric summary with the current value, trend, and whether it is within a healthy range.', + }, + { + name: 'review-alarm-state', + description: + 'List CloudWatch alarms, report which are in ALARM or INSUFFICIENT_DATA, and optionally mute noisy alarms.', + content: + '# Review CloudWatch Alarm State\n\nGet a snapshot of alarm health across the account.\n\n## Steps\n1. Describe alarms and group them by state (OK, ALARM, INSUFFICIENT_DATA).\n2. For alarms in ALARM, capture the metric, threshold, and reason.\n3. If asked, mute alarms that are known-noisy during a maintenance window and note them.\n\n## Output\nA list of alarms currently firing or missing data, with the metric and threshold for each.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/confluence.ts b/apps/sim/blocks/blocks/confluence.ts index 6984a2cfbf5..53536f7c860 100644 --- a/apps/sim/blocks/blocks/confluence.ts +++ b/apps/sim/blocks/blocks/confluence.ts @@ -1675,4 +1675,34 @@ export const ConfluenceBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'publish-meeting-notes', + description: + 'Create a Confluence page with structured meeting notes including attendees, decisions, and action items in the right space.', + content: + '# Publish Meeting Notes to Confluence\n\nTurn raw meeting notes into a clean, structured Confluence page.\n\n## Steps\n1. Confirm the target space and any parent page.\n2. Structure the notes into sections: attendees, agenda, decisions, and action items with owners.\n3. Create the page with a clear, dated title.\n4. Return the page URL.\n\n## Output\nA confirmation with the new page title and link, plus the list of action items captured.', + }, + { + name: 'update-doc-page', + description: + 'Read an existing Confluence page, apply updates, and save it back, respecting version control to avoid conflicts.', + content: + '# Update a Confluence Page\n\nSafely edit an existing documentation page.\n\n## Steps\n1. Read the target page to get its current content and version number.\n2. Apply the requested changes to the body, preserving existing structure and formatting.\n3. Update the page, incrementing the version number by one to avoid optimistic-locking conflicts.\n4. If the update fails on a version conflict, re-read and retry.\n\n## Output\nA confirmation of the updated page with its new version number and link.', + }, + { + name: 'search-knowledge', + description: + 'Search Confluence content for a topic and summarize the most relevant pages with links for quick reference.', + content: + '# Search Confluence Knowledge\n\nFind and summarize documentation on a topic.\n\n## Steps\n1. Search content using the topic keywords, optionally scoped to a space.\n2. Read the top matching pages.\n3. Summarize what each page covers and how it relates to the question.\n\n## Output\nA short briefing answering the question, with links to the source pages cited.', + }, + { + name: 'collect-page-feedback', + description: + 'List and summarize comments on a Confluence page so you can triage feedback and open questions.', + content: + '# Collect Confluence Page Feedback\n\nGather and organize comments left on a page.\n\n## Steps\n1. Read the target page to confirm its identity.\n2. List all comments on the page.\n3. Group comments into themes: questions, corrections, and approvals.\n\n## Output\nA digest of comment themes with any unresolved questions flagged for follow-up.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/crowdstrike.ts b/apps/sim/blocks/blocks/crowdstrike.ts index d3d88d159c8..de4dda154e6 100644 --- a/apps/sim/blocks/blocks/crowdstrike.ts +++ b/apps/sim/blocks/blocks/crowdstrike.ts @@ -281,4 +281,20 @@ export const CrowdStrikeBlockMeta = { tags: ['enterprise', 'analysis'], }, ], + skills: [ + { + name: 'audit-identity-sensors', + description: + 'Query CrowdStrike Identity Protection sensors and report on coverage, status, and devices missing protection.', + content: + '# Audit CrowdStrike Identity Sensors\n\nReview Identity Protection sensor coverage across the fleet.\n\n## Steps\n1. Query sensors, optionally filtered by status or hostname.\n2. For sensors of interest, pull detailed attributes (version, last seen, assigned policy).\n3. Flag sensors that are offline, stale, or out of policy.\n\n## Output\nA coverage report listing healthy sensors, plus any that are offline, stale, or misconfigured for SOC review.', + }, + { + name: 'summarize-sensor-aggregates', + description: + 'Pull documented CrowdStrike sensor aggregates and summarize the fleet distribution by version, status, or platform.', + content: + '# Summarize CrowdStrike Sensor Aggregates\n\nBuild a high-level picture of the sensor fleet.\n\n## Steps\n1. Request the documented sensor aggregates (e.g. counts by version, status, or platform).\n2. Compute the distribution and identify outliers, such as a large share of outdated versions.\n3. Compare against the expected baseline.\n\n## Output\nA fleet summary with key counts and any segments that need attention (outdated, offline).', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/cursor.ts b/apps/sim/blocks/blocks/cursor.ts index 6971dddb1af..9b09fa2a352 100644 --- a/apps/sim/blocks/blocks/cursor.ts +++ b/apps/sim/blocks/blocks/cursor.ts @@ -351,4 +351,27 @@ export const CursorBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'launch-coding-agent', + description: + 'Launch a Cursor cloud agent on a GitHub repository with a clear task prompt and report the agent id and starting status.', + content: + '# Launch a Cursor Coding Agent\n\nKick off an autonomous Cursor agent to work on a repo.\n\n## Steps\n1. Confirm the target repository and the task to perform.\n2. Write a precise prompt: what to change, constraints, and acceptance criteria.\n3. Launch the agent with the chosen model and repository.\n4. Capture the agent id and initial status.\n\n## Output\nA confirmation with the agent id, repository, and the task prompt it was given.', + }, + { + name: 'track-agent-progress', + description: + 'Poll a Cursor agent for status and conversation updates and summarize what it has done so far.', + content: + '# Track Cursor Agent Progress\n\nMonitor a running Cursor agent.\n\n## Steps\n1. Get the agent status for the given agent id.\n2. Pull the conversation to see the latest actions and reasoning.\n3. If the agent is finished, list its artifacts; if blocked, identify why.\n\n## Output\nA status summary describing progress, current state, and any blockers or produced artifacts.', + }, + { + name: 'send-agent-followup', + description: + 'Send a follow-up instruction to an in-progress Cursor agent to refine or redirect its work.', + content: + '# Send a Cursor Agent Follow-up\n\nGuide an active agent with additional instructions.\n\n## Steps\n1. Confirm the agent id and review its recent conversation.\n2. Compose a clear follow-up message addressing what to change or add.\n3. Add the follow-up to the agent.\n4. Note that the agent has resumed work.\n\n## Output\nA confirmation that the follow-up was delivered, with the instruction sent.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/dagster.ts b/apps/sim/blocks/blocks/dagster.ts index a27d5e9b3c0..359eb67ebe6 100644 --- a/apps/sim/blocks/blocks/dagster.ts +++ b/apps/sim/blocks/blocks/dagster.ts @@ -741,4 +741,34 @@ export const DagsterBlockMeta = { alsoIntegrations: ['databricks'], }, ], + skills: [ + { + name: 'launch-pipeline-run', + description: + 'Launch a Dagster job run with the right config and report the run id and starting status.', + content: + '# Launch a Dagster Pipeline Run\n\nKick off a data pipeline job.\n\n## Steps\n1. List jobs to confirm the target job name.\n2. Assemble the run config (partitions, tags, resources) for the run.\n3. Launch the run and capture the run id.\n4. Confirm the run entered the queue or started.\n\n## Output\nA confirmation with the run id, job name, and initial status.', + }, + { + name: 'monitor-failed-runs', + description: + 'List recent Dagster runs, surface failures, and pull logs to diagnose why a run failed.', + content: + '# Monitor Failed Dagster Runs\n\nFind and diagnose pipeline failures.\n\n## Steps\n1. List recent runs and filter to those in a failed state.\n2. For each failed run, get the run details and pull its logs.\n3. Identify the failing step/op and the error message.\n4. Decide whether a re-execute of the failed steps is appropriate.\n\n## Output\nA per-run failure summary with the failing op, error, and a recommendation (retry or investigate).', + }, + { + name: 'reexecute-failed-run', + description: + 'Re-execute a failed Dagster run from the point of failure and confirm the new run started.', + content: + '# Re-execute a Failed Dagster Run\n\nRetry a pipeline from where it broke.\n\n## Steps\n1. Get the failed run to confirm its id and failure point.\n2. Re-execute the run, scoping to the failed and downstream steps when supported.\n3. Capture the new run id and status.\n\n## Output\nA confirmation with the original run id, the new run id, and the re-execution scope.', + }, + { + name: 'manage-schedules', + description: + 'List Dagster schedules and sensors and start or stop them to control automated pipeline execution.', + content: + '# Manage Dagster Schedules\n\nControl which automated triggers are running.\n\n## Steps\n1. List schedules and sensors with their current running state.\n2. Identify the schedule or sensor to change.\n3. Start or stop it as requested.\n4. Confirm the new state.\n\n## Output\nA confirmation of which schedules/sensors were started or stopped and their resulting state.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/databricks.ts b/apps/sim/blocks/blocks/databricks.ts index cb7fd8f0e91..e2fe34f045e 100644 --- a/apps/sim/blocks/blocks/databricks.ts +++ b/apps/sim/blocks/blocks/databricks.ts @@ -490,4 +490,27 @@ export const DatabricksBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'run-sql-query', + description: + 'Execute a SQL query against a Databricks SQL warehouse and return the results in a clean, summarized form.', + content: + '# Run a Databricks SQL Query\n\nQuery a table or view and summarize the result.\n\n## Steps\n1. Confirm the SQL warehouse and the query to run.\n2. Execute the SQL statement and wait for it to complete.\n3. Capture the returned rows and column schema.\n4. Summarize key findings (counts, totals, notable values).\n\n## Output\nThe query results plus a short plain-English summary of what they show.', + }, + { + name: 'trigger-job-run', + description: + 'Trigger a Databricks job, capture the run id, and confirm it started successfully.', + content: + '# Trigger a Databricks Job\n\nKick off a job and confirm it launched.\n\n## Steps\n1. List jobs to confirm the target job id and name.\n2. Run the job with any required parameters.\n3. Capture the run id and starting state.\n\n## Output\nA confirmation with the job name, run id, and initial status.', + }, + { + name: 'monitor-job-run', + description: + 'Check the status of a Databricks job run, pull its output, and diagnose failures.', + content: + '# Monitor a Databricks Job Run\n\nTrack a job run to completion and report results.\n\n## Steps\n1. Get the run for the given run id and read its lifecycle and result state.\n2. If still running, report progress; if finished, pull the run output.\n3. On failure, capture the error and the failing task.\n\n## Output\nA run summary with final state, key output, and (on failure) the error and failing task.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/datadog.ts b/apps/sim/blocks/blocks/datadog.ts index 3b226489f28..fbe6c0debb8 100644 --- a/apps/sim/blocks/blocks/datadog.ts +++ b/apps/sim/blocks/blocks/datadog.ts @@ -907,4 +907,34 @@ export const DatadogBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'triage-firing-monitors', + description: + 'List Datadog monitors, surface those in alert or warn state, and summarize what is firing and why.', + content: + '# Triage Firing Datadog Monitors\n\nGet a clear picture of what is alerting right now.\n\n## Steps\n1. List monitors and filter to those in Alert or Warn states.\n2. For each, get the monitor details: query, threshold, and current value.\n3. Group by service or tag to find common root causes.\n\n## Output\nA prioritized list of firing monitors with the metric, threshold, and likely affected service.', + }, + { + name: 'investigate-logs', + description: + 'Query Datadog logs for a service and time window to find errors and summarize patterns.', + content: + '# Investigate Datadog Logs\n\nSearch logs to diagnose an issue.\n\n## Steps\n1. Confirm the service, environment, and time window.\n2. Query logs filtering for error/critical status and the relevant service tag.\n3. Aggregate by error message or type to find the dominant patterns.\n4. Pull sample log lines for the top patterns.\n\n## Output\nA summary of the top error patterns with counts and sample log lines.', + }, + { + name: 'analyze-metric-trend', + description: + 'Query a Datadog timeseries metric over a window and report the trend, anomalies, and current value.', + content: + '# Analyze a Datadog Metric Trend\n\nUnderstand how a metric is behaving over time.\n\n## Steps\n1. Confirm the metric query and the time window.\n2. Query the timeseries and compute the trend (rising, flat, falling).\n3. Identify spikes, dips, or anomalies and when they occurred.\n\n## Output\nA short analysis with the current value, overall trend, and any notable anomalies with timestamps.', + }, + { + name: 'schedule-maintenance-downtime', + description: + 'Create a Datadog downtime to mute monitors during a maintenance window, then confirm the scope and timing.', + content: + '# Schedule Datadog Maintenance Downtime\n\nSuppress alerts during planned maintenance.\n\n## Steps\n1. Confirm the scope (tags/monitors) and the start and end times.\n2. Create the downtime with that scope and window.\n3. Verify it was created by listing active downtimes.\n\n## Output\nA confirmation of the downtime with its scope, start/end time, and id.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/devin.ts b/apps/sim/blocks/blocks/devin.ts index a021e11c092..68960114b80 100644 --- a/apps/sim/blocks/blocks/devin.ts +++ b/apps/sim/blocks/blocks/devin.ts @@ -389,4 +389,27 @@ export const DevinBlockMeta = { alsoIntegrations: ['linear'], }, ], + skills: [ + { + name: 'start-engineering-session', + description: + 'Create a Devin session with a clear engineering task prompt and report the session id and link.', + content: + '# Start a Devin Engineering Session\n\nKick off an autonomous engineering task with Devin.\n\n## Steps\n1. Confirm the repository and the task to perform.\n2. Write a precise prompt: the goal, constraints, and acceptance criteria.\n3. Create the session, optionally tagging it for tracking.\n4. Capture the session id and URL.\n\n## Output\nA confirmation with the session id, link, and the task prompt Devin was given.', + }, + { + name: 'check-session-progress', + description: + 'Get a Devin session status and recent messages and summarize what it has accomplished or where it is blocked.', + content: + '# Check Devin Session Progress\n\nMonitor a running Devin session.\n\n## Steps\n1. Get the session for the given session id and read its status.\n2. List recent session messages to see Devin actions and reasoning.\n3. Determine whether it is making progress, finished, or blocked needing input.\n\n## Output\nA status summary describing progress, current state, and any questions Devin is waiting on.', + }, + { + name: 'guide-session', + description: + 'Send a message to an active Devin session to answer a question or redirect its work.', + content: + '# Guide a Devin Session\n\nUnblock or steer an active session.\n\n## Steps\n1. Confirm the session id and review the latest messages.\n2. Compose a clear reply: answer the open question or give new direction.\n3. Send the message to the session.\n4. Confirm Devin has resumed.\n\n## Output\nA confirmation that the message was sent, with the guidance provided.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/discord.ts b/apps/sim/blocks/blocks/discord.ts index ba9ddf2088e..3b932679f0d 100644 --- a/apps/sim/blocks/blocks/discord.ts +++ b/apps/sim/blocks/blocks/discord.ts @@ -868,4 +868,34 @@ export const DiscordBlockMeta = { alsoIntegrations: ['luma', 'google_calendar'], }, ], + skills: [ + { + name: 'post-announcement', + description: + 'Post a formatted announcement message to a Discord channel and optionally pin it.', + content: + '# Post a Discord Announcement\n\nShare an announcement with a community channel.\n\n## Steps\n1. Confirm the target channel and the announcement content.\n2. Format the message clearly, using mentions or roles only if requested.\n3. Send the message to the channel.\n4. If it is important, pin the message.\n\n## Output\nA confirmation with the channel, message link or id, and whether it was pinned.', + }, + { + name: 'summarize-channel-activity', + description: + 'Read recent Discord channel messages and produce a summary of discussions, questions, and decisions.', + content: + '# Summarize Discord Channel Activity\n\nCatch up on what happened in a channel.\n\n## Steps\n1. Confirm the channel and how many recent messages to review.\n2. Get the channel messages.\n3. Group the conversation into themes: announcements, questions, and decisions.\n4. Flag unanswered questions that need a reply.\n\n## Output\nA concise digest of the discussion with unanswered questions called out.', + }, + { + name: 'open-discussion-thread', + description: + 'Create a Discord thread for a topic and post a kickoff message to organize community discussion.', + content: + '# Open a Discord Discussion Thread\n\nSpin up a focused thread for a topic.\n\n## Steps\n1. Confirm the parent channel and the thread topic.\n2. Create the thread with a clear name.\n3. Post a kickoff message framing the discussion and any prompts.\n\n## Output\nA confirmation with the thread name, link or id, and the kickoff message posted.', + }, + { + name: 'collect-reactions-feedback', + description: + 'Post a poll-style message in Discord, add reaction options, and read back the tally as feedback.', + content: + '# Collect Discord Reaction Feedback\n\nRun a lightweight reaction poll.\n\n## Steps\n1. Confirm the channel, the question, and the reaction options.\n2. Send the poll message.\n3. Add each reaction option to the message.\n4. After the polling window, read the message to tally the reaction counts.\n\n## Output\nThe poll question with the reaction tally and which option leads.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/docusign.ts b/apps/sim/blocks/blocks/docusign.ts index 49a66e57d93..de73c5d0f1c 100644 --- a/apps/sim/blocks/blocks/docusign.ts +++ b/apps/sim/blocks/blocks/docusign.ts @@ -446,4 +446,33 @@ export const DocuSignBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'send-contract-for-signature', + description: + 'Send a document to one or more signers for e-signature, using a DocuSign template or an uploaded file.', + content: + '# Send Contract for Signature\n\nSend a document out for e-signature through DocuSign and confirm it was delivered.\n\n## Steps\n1. Determine whether to send from a template (preferred for standard agreements) or from an uploaded document. If a template is named, use List Templates to resolve its ID.\n2. For a template, call Send from Template with the template ID and a template-roles JSON array mapping each role name to a signer name and email. For an ad-hoc document, call Send Envelope with the email subject, signer name, signer email, and the document file.\n3. Add any CC recipients and set the email subject to something the signer will recognize.\n4. Send immediately unless asked to save as a draft.\n\n## Output\nReport the envelope ID and status. List each signer and CC recipient with their email so the requester can confirm the right people were addressed.', + }, + { + name: 'track-pending-envelopes', + description: + 'List envelopes awaiting signature, identify ones stalled past a threshold, and surface who still needs to sign.', + content: + '# Track Pending Envelopes\n\nFind DocuSign envelopes that are sent but not yet completed so stalled signatures can be chased.\n\n## Steps\n1. Call List Envelopes filtered to sent and delivered status over a recent date window.\n2. For each envelope, use List Recipients to see which signers have signed and which are still outstanding.\n3. Compute how long each envelope has been waiting and flag any past the requested threshold (default 48 hours).\n\n## Output\nReturn a table of stalled envelopes: envelope ID, subject, days waiting, and the outstanding signer name and email. Sort by longest waiting first.', + }, + { + name: 'archive-completed-documents', + description: + 'Find completed envelopes, download the signed PDFs, and extract key metadata for archiving.', + content: + '# Archive Completed Documents\n\nCollect signed documents once an envelope is complete and capture their metadata.\n\n## Steps\n1. Call List Envelopes filtered to completed status over the requested date window.\n2. For each completed envelope, call Download Document with "combined" to get the full signed PDF.\n3. Record the envelope ID, subject, completed date, and signer list for each document.\n\n## Output\nReturn each completed envelope with its downloaded file, signers, and completed date. Note any envelope where the download failed so it can be retried.', + }, + { + name: 'void-stale-envelope', + description: 'Void an envelope that should no longer be signed and record the reason.', + content: + '# Void Stale Envelope\n\nCancel a DocuSign envelope that is no longer valid — wrong recipient, superseded terms, or expired offer.\n\n## Steps\n1. Confirm the envelope ID. If only a subject or signer is known, use List Envelopes to resolve it, and verify it is not already completed.\n2. Call Get Envelope to confirm the current status is still voidable (created, sent, or delivered).\n3. Call Void Envelope with a clear void reason describing why it is being cancelled.\n\n## Output\nConfirm the envelope ID, its new voided status, and the recorded reason. If the envelope was already completed or voided, report that instead of attempting to void it.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/dropbox.ts b/apps/sim/blocks/blocks/dropbox.ts index f39b101c4c4..8a43b8b8ebf 100644 --- a/apps/sim/blocks/blocks/dropbox.ts +++ b/apps/sim/blocks/blocks/dropbox.ts @@ -472,4 +472,33 @@ export const DropboxBlockMeta = { alsoIntegrations: ['docusign'], }, ], + skills: [ + { + name: 'upload-file-to-dropbox', + description: + 'Upload a file to a specific Dropbox path and optionally generate a shareable link.', + content: + '# Upload File to Dropbox\n\nSave a file into Dropbox at a chosen location and optionally share it.\n\n## Steps\n1. Determine the destination path, including the filename and extension (e.g., /reports/q3-summary.pdf).\n2. Call Upload File with the file and destination path. Use overwrite mode only if replacing an existing file; otherwise use add and enable auto-rename to avoid clobbering.\n3. If a shareable link is requested, call Create Shared Link on the uploaded path with the requested visibility (public, team-only, or password-protected).\n\n## Output\nReport the final stored path (after any auto-rename) and, if created, the shared link URL.', + }, + { + name: 'find-files-in-dropbox', + description: + 'Search Dropbox for files by query, extension, or folder, and return matching paths.', + content: + '# Find Files in Dropbox\n\nLocate files in Dropbox matching a search term or filter.\n\n## Steps\n1. Use Search Files with the query term. Scope to a folder path when the location is known, and pass file extensions (e.g., pdf,xlsx) to narrow results.\n2. If browsing a known folder instead of searching, use List Folder with the folder path; enable recursive listing to include subfolders.\n3. For any candidate match, use Get Metadata to confirm size, type, and last-modified time before acting on it.\n\n## Output\nReturn the matching files as a list of path, name, size, and last-modified. If nothing matches, say so and suggest a broader query.', + }, + { + name: 'organize-dropbox-folder', + description: 'List a folder and move, copy, or delete files to reorganize Dropbox contents.', + content: + '# Organize Dropbox Folder\n\nReorganize files in Dropbox by moving them into the right folders.\n\n## Steps\n1. Call List Folder on the source path to enumerate the files to process.\n2. Decide each file destination based on the requested rules (by type, date, campaign, or naming pattern). Create target folders with Create Folder if they do not exist.\n3. Use Move File/Folder to relocate each file, or Copy File/Folder when the original must stay in place. Enable auto-rename to avoid conflicts.\n\n## Output\nReturn a summary of every file moved or copied with its old and new path, and flag any operation that failed.', + }, + { + name: 'share-dropbox-link', + description: + 'Create a shared link for a Dropbox file or folder with controlled visibility and expiration.', + content: + '# Share Dropbox Link\n\nGenerate a shareable link for an existing Dropbox item with the right access controls.\n\n## Steps\n1. Confirm the exact path of the file or folder. Use Get Metadata to verify it exists.\n2. Call Create Shared Link with the path and the requested visibility — public for anyone, team-only for internal sharing, or password-protected with a supplied password.\n3. Set an expiration date if the link should not be permanent.\n\n## Output\nReturn the shared link URL, its visibility setting, and the expiration date if one was applied.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/dspy.ts b/apps/sim/blocks/blocks/dspy.ts index f589b1f9b3f..42d39250c16 100644 --- a/apps/sim/blocks/blocks/dspy.ts +++ b/apps/sim/blocks/blocks/dspy.ts @@ -244,4 +244,27 @@ export const DSPyBlockMeta = { tags: ['research', 'llm', 'agentic'], }, ], + skills: [ + { + name: 'run-dspy-prediction', + description: + 'Call a self-hosted DSPy Predict program to get a structured output from an input.', + content: + '# Run DSPy Prediction\n\nSend input to a self-hosted DSPy Predict program and return its structured answer.\n\n## Steps\n1. Confirm the DSPy server base URL and, if required, the API key.\n2. Choose the Predict operation and supply the input text. Set the input field name only if the program signature expects something other than the default.\n3. Pass any extra signature fields as an additional-inputs JSON object.\n\n## Output\nReturn the program answer and any structured fields it produced. If the server returns a non-success status, surface the status and the raw output for debugging.', + }, + { + name: 'reason-with-chain-of-thought', + description: + 'Use a DSPy Chain of Thought program to answer a question with explicit reasoning.', + content: + '# Reason with Chain of Thought\n\nAnswer a question through a self-hosted DSPy Chain of Thought program that exposes its reasoning.\n\n## Steps\n1. Confirm the DSPy server base URL and API key if needed.\n2. Choose the Chain of Thought operation and supply the question. Add any background as context.\n3. Run the program and capture both the answer and the reasoning trace.\n\n## Output\nReturn the final answer plus the reasoning rationale so the requester can audit how the conclusion was reached.', + }, + { + name: 'run-dspy-react-agent', + description: + 'Run a DSPy ReAct agent on a task that requires multi-step tool use, and capture its trajectory.', + content: + '# Run DSPy ReAct Agent\n\nExecute a task with a self-hosted DSPy ReAct agent that interleaves reasoning and actions.\n\n## Steps\n1. Confirm the DSPy server base URL and API key if needed.\n2. Choose the ReAct operation and describe the task clearly. Set a max-iterations cap to bound how many reasoning-action cycles run.\n3. Provide any needed context, then execute the agent.\n\n## Output\nReturn the final answer and the step-by-step trajectory (thoughts, actions, observations). If the agent hit the iteration cap without finishing, note that and summarize the last state.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/dub.ts b/apps/sim/blocks/blocks/dub.ts index 171df750d5e..9dcc902c80b 100644 --- a/apps/sim/blocks/blocks/dub.ts +++ b/apps/sim/blocks/blocks/dub.ts @@ -562,4 +562,34 @@ export const DubBlockMeta = { tags: ['marketing', 'analysis', 'reporting'], }, ], + skills: [ + { + name: 'create-tracked-short-link', + description: + 'Create a Dub short link for a destination URL with UTM parameters and an optional custom slug.', + content: + '# Create Tracked Short Link\n\nTurn a long destination URL into a branded, trackable Dub short link.\n\n## Steps\n1. Take the destination URL and any campaign metadata (source, medium, campaign name).\n2. Call Create Link with the URL. Set the UTM source, medium, and campaign fields so clicks attribute correctly, and set a custom slug when a memorable link is wanted.\n3. Add a custom domain, title, or tag IDs if the request specifies them.\n\n## Output\nReturn the full short link URL, its slug, the destination, and the QR code URL. Confirm which UTM parameters were applied.', + }, + { + name: 'report-link-analytics', + description: + 'Pull Dub click, lead, and sales analytics for a link or campaign over a time window.', + content: + '# Report Link Analytics\n\nSummarize how a Dub short link or campaign is performing.\n\n## Steps\n1. Choose the Get Analytics operation. Set the event type (clicks, leads, sales, or composite) the request cares about.\n2. Scope to a specific link via link ID or external ID, or to a domain for a whole campaign. Set the interval (e.g., 7d, 30d) or explicit start and end dates.\n3. Set group-by to break results down by country, device, referrer, or top links when a breakdown is asked for; otherwise use count for totals.\n\n## Output\nReport the headline metrics (clicks, leads, sales, revenue) and, when grouped, the top segments. Call out notable winners and decliners versus the prior period when comparison data is available.', + }, + { + name: 'batch-create-campaign-links', + description: + 'Upsert a Dub short link for each row in a list of destinations with consistent UTM tagging.', + content: + '# Batch Create Campaign Links\n\nGenerate consistent tracked links for many destinations at once.\n\n## Steps\n1. For each destination URL in the list, build the UTM parameters and slug from the row data so tagging is uniform across the batch.\n2. Use Upsert Link (keyed on external ID or slug) so re-runs refresh rather than duplicate existing links.\n3. Collect the resulting short link for each row.\n\n## Output\nReturn a table mapping each destination to its short link and external ID. Report how many links were created versus refreshed, and flag any rows that failed.', + }, + { + name: 'audit-existing-links', + description: + 'List Dub links and check each destination for broken or stale URLs to flag for cleanup.', + content: + '# Audit Existing Links\n\nReview existing Dub links to catch broken or outdated destinations.\n\n## Steps\n1. Call List Links, optionally filtered by domain or tag IDs, paginating until all links are retrieved.\n2. For each link, inspect the destination URL and check it for 4xx or 5xx responses or obviously stale targets.\n3. Note links with low or zero clicks over a long period as candidates for archiving.\n\n## Output\nReturn a remediation list: short link, destination, detected issue (broken, redirecting, stale), and a suggested action. Sort broken links first.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/duckduckgo.ts b/apps/sim/blocks/blocks/duckduckgo.ts index 5fecf1cddbd..314c3447d7f 100644 --- a/apps/sim/blocks/blocks/duckduckgo.ts +++ b/apps/sim/blocks/blocks/duckduckgo.ts @@ -130,4 +130,27 @@ export const DuckDuckGoBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'answer-with-duckduckgo', + description: + 'Search DuckDuckGo for a quick instant answer or abstract on a topic and return it with its source.', + content: + '# Answer with DuckDuckGo\n\nGet a fast, privacy-preserving answer to a factual question using DuckDuckGo Instant Answers.\n\n## Steps\n1. Form a concise query from the question. Enable Remove HTML so returned text is clean.\n2. Run the search and read the instant answer, abstract, and abstract source.\n3. If the result is a disambiguation page rather than a direct answer, refine the query to be more specific and search again.\n\n## Output\nReturn the answer or abstract text along with the source name and URL so the claim is attributable. If no instant answer exists, say so and surface the related topics instead.', + }, + { + name: 'gather-related-topics', + description: + 'Use DuckDuckGo to collect related topics and external links around a subject for research.', + content: + '# Gather Related Topics\n\nBuild a quick research starting point on a subject using DuckDuckGo.\n\n## Steps\n1. Search the subject with Remove HTML enabled.\n2. Collect the heading, abstract, related topics, and any external link results.\n3. Group the related topics into themes and pick the most authoritative links to explore further.\n\n## Output\nReturn the abstract summary plus a list of related topics and external links, each with its URL, organized by theme.', + }, + { + name: 'validate-claim-online', + description: + 'Check a stated claim against DuckDuckGo results to confirm or flag it as unsupported.', + content: + '# Validate Claim Online\n\nVerify whether a claim is supported by public web sources via DuckDuckGo.\n\n## Steps\n1. Turn the claim into a focused search query and run it with Remove HTML enabled.\n2. Compare the instant answer, abstract, and source against the claim.\n3. Decide whether the result supports, contradicts, or is silent on the claim.\n\n## Output\nReturn a verdict — supported, contradicted, or unverified — with the source name and URL. If unverified, recommend a more targeted query or a dedicated source.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/dynamodb.ts b/apps/sim/blocks/blocks/dynamodb.ts index e80eca1d9ea..3f997b655c2 100644 --- a/apps/sim/blocks/blocks/dynamodb.ts +++ b/apps/sim/blocks/blocks/dynamodb.ts @@ -901,4 +901,26 @@ export const DynamoDBBlockMeta = { alsoIntegrations: ['athena'], }, ], + skills: [ + { + name: 'lookup-item-by-key', + description: + 'Get a single DynamoDB item by its primary key and return the requested attributes.', + content: + '# Lookup Item by Key\n\nRetrieve one record from a DynamoDB table by its key.\n\n## Steps\n1. Identify the table and the partition key (and sort key if the table uses one).\n2. Get the item by its key.\n3. Return the requested attributes, or report that no item exists for that key.\n\n## Output\nThe item attributes if found, or a clear "not found" result. Do not fabricate values for missing attributes.', + }, + { + name: 'query-table-records', + description: + 'Query a DynamoDB table or index by partition key with optional filters and return the matching items.', + content: + '# Query Table Records\n\nFetch a set of related items from DynamoDB using a query.\n\n## Steps\n1. Determine the table or secondary index and the partition key value to query.\n2. Add a sort-key condition or filter expression if needed to narrow results.\n3. Run the query and collect the items, paginating if there are more.\n\n## Output\nThe matching items and a count. Note if results were truncated by a limit or pagination boundary.', + }, + { + name: 'upsert-item', + description: 'Create or update a DynamoDB item, setting attributes from provided values.', + content: + '# Upsert Item\n\nWrite a record into a DynamoDB table.\n\n## Steps\n1. Build the item with its primary key and the attributes to set.\n2. Put the item, or use an update expression to modify only specific attributes.\n3. Confirm the write succeeded.\n\n## Output\nConfirm the item key written and which attributes were set or updated.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/elasticsearch.ts b/apps/sim/blocks/blocks/elasticsearch.ts index 96b07be36bb..8ce1c513503 100644 --- a/apps/sim/blocks/blocks/elasticsearch.ts +++ b/apps/sim/blocks/blocks/elasticsearch.ts @@ -607,4 +607,31 @@ export const ElasticsearchBlockMeta = { alsoIntegrations: ['langsmith'], }, ], + skills: [ + { + name: 'search-elasticsearch-index', + description: 'Run a query against an Elasticsearch index and return the matching documents.', + content: + '# Search Elasticsearch Index\n\nQuery an index and return the relevant documents.\n\n## Steps\n1. Confirm the connection details (host or cloud ID and auth) and the target index name.\n2. Choose the Search operation and build the query DSL — match for full-text, term for exact values, range for numeric or date bounds, and bool to combine clauses.\n3. Set size and offset for paging, add a sort spec when ordering matters, and use source includes/excludes to trim returned fields.\n\n## Output\nReturn the matching hits with their _id, _score, and relevant _source fields, plus the total count and query time. If nothing matched, report zero hits and suggest loosening the query.', + }, + { + name: 'index-document', + description: 'Add or update a document in an Elasticsearch index.', + content: + '# Index Document\n\nWrite a document into an Elasticsearch index so it becomes searchable.\n\n## Steps\n1. Confirm the connection details and target index.\n2. Build the document as a JSON object with appropriate field types. Choose the Index Document operation; supply a document ID to upsert a known record, or omit it to let Elasticsearch auto-generate one.\n3. To change only specific fields of an existing document, use Update Document with a partial document and the document ID instead.\n4. Set the refresh policy to immediate or wait-for when the write must be searchable right away.\n\n## Output\nReturn the resulting _id, _version, and the operation result (created or updated).', + }, + { + name: 'bulk-load-documents', + description: + 'Index, update, or delete many Elasticsearch documents in a single bulk request.', + content: + '# Bulk Load Documents\n\nApply many document operations to Elasticsearch efficiently in one call.\n\n## Steps\n1. Confirm the connection details and target index.\n2. Assemble the operations as NDJSON: an action line (index, create, update, or delete) followed by the document line where required.\n3. Run the Bulk Operations call and set a refresh policy if the data must be immediately searchable.\n\n## Output\nReport whether any errors occurred and summarize the per-item results — how many succeeded versus failed and the reason for any failures.', + }, + { + name: 'check-cluster-health', + description: 'Report Elasticsearch cluster health and key index statistics.', + content: + '# Check Cluster Health\n\nAssess the health of an Elasticsearch deployment.\n\n## Steps\n1. Confirm the connection details.\n2. Call Cluster Health to get the overall status (green, yellow, red) and node count. Optionally wait for a target status.\n3. Use List Indices and Get Index Info to spot oversized, unassigned, or unhealthy indices, and Cluster Stats for storage and shard totals.\n\n## Output\nReport the cluster status, number of nodes, and any indices that look problematic. If status is yellow or red, explain the likely cause (e.g., unassigned replicas) and what to check next.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/elevenlabs.ts b/apps/sim/blocks/blocks/elevenlabs.ts index 2552ec4587a..e4ea293ebaa 100644 --- a/apps/sim/blocks/blocks/elevenlabs.ts +++ b/apps/sim/blocks/blocks/elevenlabs.ts @@ -175,4 +175,26 @@ export const ElevenLabsBlockMeta = { tags: ['support', 'communication', 'automation'], }, ], + skills: [ + { + name: 'narrate-text-to-speech', + description: + 'Convert a block of text into natural-sounding speech audio with a chosen ElevenLabs voice.', + content: + '# Narrate Text to Speech\n\nGenerate spoken audio from text using ElevenLabs.\n\n## Steps\n1. Take the text to narrate and confirm the target voice ID (ask for one if not provided).\n2. Pick a model — use a multilingual model for non-English or mixed-language text, or a turbo/flash model when low latency matters.\n3. For consistent delivery, set stability higher; for more expressive variation, set it lower. Raise similarity boost to stay closer to the reference voice.\n\n## Output\nReturn the generated audio file and its URL. Confirm the voice and model used so the requester can adjust if the delivery is not right.', + }, + { + name: 'narrate-article-as-audio', + description: 'Turn a long article or blog post into a podcast-style audio narration.', + content: + '# Narrate Article as Audio\n\nProduce a listenable audio version of written content.\n\n## Steps\n1. Clean the source text — strip markdown, navigation, and boilerplate so only the readable prose remains. Expand abbreviations the voice should speak in full.\n2. Choose a voice ID suited to the content and a high-quality multilingual model for natural delivery.\n3. Convert the cleaned text to speech, keeping stability moderate so the narration sounds engaging but consistent.\n\n## Output\nReturn the audio file and a player-ready URL, along with the voice used. If the text is very long, note any truncation and suggest splitting it into parts.', + }, + { + name: 'generate-voice-prompt', + description: + 'Generate a short branded voice clip such as an IVR prompt, greeting, or notification.', + content: + '# Generate Voice Prompt\n\nCreate a short, polished voice clip for things like phone menus, greetings, or alerts.\n\n## Steps\n1. Take the exact script for the prompt. Keep it concise and confirm pronunciation of any names or numbers.\n2. Select a consistent brand voice ID so every prompt sounds the same.\n3. Set stability high for a steady, professional delivery and convert the script to speech.\n\n## Output\nReturn the audio file and its URL. When generating a set of prompts, list each clip with its script so they can be wired into the phone tree or app.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/emailbison.ts b/apps/sim/blocks/blocks/emailbison.ts index 8e002b86e43..d8dae0f1524 100644 --- a/apps/sim/blocks/blocks/emailbison.ts +++ b/apps/sim/blocks/blocks/emailbison.ts @@ -697,4 +697,34 @@ export const EmailBisonBlockMeta = { tags: ['sales', 'automation', 'analysis'], }, ], + skills: [ + { + name: 'add-leads-to-campaign', + description: + 'Create leads in Email Bison and attach them to an outbound campaign with personalization variables.', + content: + '# Add Leads to Campaign\n\nLoad prospects into Email Bison and enroll them in a campaign.\n\n## Steps\n1. Confirm the instance URL and target campaign. If only a campaign name is known, use List Campaigns to resolve its ID.\n2. For each prospect, call Create Lead with first name, last name, email, and any title or company. Pass personalization fields as a custom-variables JSON array (e.g., linkedin_url, first_line).\n3. Collect the new lead IDs and call Attach Leads to Campaign with the campaign ID and those IDs.\n\n## Output\nReport how many leads were created and attached, list any duplicates or invalid emails that were skipped, and confirm the campaign they were added to.', + }, + { + name: 'triage-campaign-replies', + description: + 'Pull recent Email Bison replies, classify each by intent, and tag the lead accordingly.', + content: + '# Triage Campaign Replies\n\nProcess inbound replies to outbound campaigns and route them.\n\n## Steps\n1. Call List Replies, optionally scoped to a campaign, sender email, or the inbox folder, and filter to unread when only new replies matter.\n2. Classify each reply as interested, not interested, objection, out-of-office, or auto-reply based on its content.\n3. Resolve or create the matching tag with List Tags / Create Tag, then call Attach Tags to Leads to label the lead by intent.\n\n## Output\nReturn each reply with its lead, classification, and the tag applied. Highlight interested replies so a rep can follow up first.', + }, + { + name: 'manage-campaign-status', + description: + 'Pause, resume, or archive an Email Bison campaign and adjust its sending settings.', + content: + '# Manage Campaign Status\n\nControl whether an Email Bison campaign is actively sending and tune its limits.\n\n## Steps\n1. Confirm the campaign ID (resolve via List Campaigns if only a name is given).\n2. Call Update Campaign Status with pause, resume, or archive as requested.\n3. To adjust throughput or behavior, call Update Campaign to change max emails per day, max new leads per day, sequence prioritization, or tracking settings.\n\n## Output\nConfirm the campaign new status and any sending settings that changed. Note the prior values so the change can be reverted if needed.', + }, + { + name: 'report-campaign-performance', + description: + 'Summarize Email Bison campaign performance — sends, opens, replies, and positive reply rate.', + content: + '# Report Campaign Performance\n\nProduce a performance snapshot across Email Bison campaigns.\n\n## Steps\n1. Call List Campaigns to get the active campaigns and their stats.\n2. For reply-level detail, call List Replies per campaign and tally interested versus total to compute positive reply rate.\n3. Rank campaigns by reply rate and identify top and bottom performers.\n\n## Output\nReturn a digest: per-campaign sends, opens, replies, and positive reply rate, with the best and worst performers called out and a one-line takeaway for each.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/enrich.ts b/apps/sim/blocks/blocks/enrich.ts index 75098443497..aaf887d28b1 100644 --- a/apps/sim/blocks/blocks/enrich.ts +++ b/apps/sim/blocks/blocks/enrich.ts @@ -697,4 +697,34 @@ export const EnrichBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'enrich-contact-from-email', + description: + 'Enrich a person from their email address — name, role, company, social profiles, and more.', + content: + '# Enrich Contact from Email\n\nTurn an email address into a full contact profile using Enrich.so.\n\n## Steps\n1. Take the email address. Choose Email to Profile for a full enrichment, or Email to Person (Lite) for a fast, cheaper lookup.\n2. Enable fresh-data fetch when up-to-date info matters more than speed.\n3. Read back name, current title, company, location, and any LinkedIn or social URLs.\n\n## Output\nReturn the enriched fields in a clean object. Note which fields could not be resolved so downstream steps know what is missing, and report remaining credits if relevant.', + }, + { + name: 'find-and-verify-work-email', + description: + 'Find a prospect work email from a name and company or LinkedIn URL, then verify deliverability.', + content: + '# Find and Verify Work Email\n\nLocate a reliable work email for a prospect and confirm it is safe to send to.\n\n## Steps\n1. If you have a name and company domain, use Find Email. If you have a LinkedIn profile URL, use LinkedIn to Work Email instead.\n2. Run Verify Email on the returned address to check deliverability, and Disposable Email Check to rule out throwaway domains.\n3. If the work email cannot be found, optionally fall back to LinkedIn to Personal Email when appropriate.\n\n## Output\nReturn the discovered email, its verification status (valid, risky, invalid), and whether it is disposable. Recommend whether the address is safe to add to outreach.', + }, + { + name: 'enrich-company-firmographics', + description: + 'Look up firmographic data for a company — size, industry, funding, revenue, and traffic.', + content: + '# Enrich Company Firmographics\n\nBuild a firmographic profile for a target account using Enrich.so.\n\n## Steps\n1. Identify the company by name or domain. Use Company Lookup for core firmographics.\n2. Add Company Funding & Traffic and Company Revenue for deeper financial signals when account scoring needs them.\n3. If you only have a visitor IP, use IP to Company first to resolve the organization.\n\n## Output\nReturn a consolidated account brief: company name, domain, industry, employee count, funding, revenue, and traffic. Flag any data points that could not be resolved.', + }, + { + name: 'search-prospects', + description: + 'Search Enrich.so for people or companies matching an ideal-customer-profile filter.', + content: + '# Search Prospects\n\nFind people or companies that match a target profile.\n\n## Steps\n1. For people, use Search People with filters like job title, industry, location, and skills. For companies, use Search Company with industry, location, and employee-size bounds.\n2. To pull contacts at known accounts, use Search Company Employees with the company IDs and target job titles.\n3. Page through results using the page and page-size parameters until you have enough matches.\n\n## Output\nReturn the matching people or companies with their key identifying fields and any profile URLs, plus a count of total matches. Suggest tighter filters if too many or too few results come back.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/enrichment.ts b/apps/sim/blocks/blocks/enrichment.ts index f52337e8ac5..fea75a1937a 100644 --- a/apps/sim/blocks/blocks/enrichment.ts +++ b/apps/sim/blocks/blocks/enrichment.ts @@ -193,4 +193,27 @@ export const EnrichmentBlockMeta = { tags: ['sales', 'research', 'enrichment'], }, ], + skills: [ + { + name: 'find-work-email', + description: + 'Find a verified work email for a contact given their full name and company domain using the Work Email enrichment.', + content: + '# Find a Work Email\n\nResolve a verified work email for a prospect.\n\n## Steps\n1. Confirm you have the contact full name and the company domain (resolve the domain first if only a company name is given).\n2. Run the Work Email enrichment with name and domain.\n3. Capture the email and its verification confidence.\n\n## Output\nThe verified work email with its confidence level, or a clear note that no match was found.', + }, + { + name: 'enrich-company-profile', + description: + 'Pull firmographics (industry, headcount, founded year, description) for a company domain using the Company Info enrichment.', + content: + '# Enrich a Company Profile\n\nBuild a firmographic profile for an account.\n\n## Steps\n1. Confirm the company domain (resolve it with the Company Domain enrichment if you only have a name).\n2. Run the Company Info enrichment on the domain.\n3. Capture industry, employee count, founded year, and description.\n\n## Output\nA structured company profile with the key firmographics, ready to write into an accounts record.', + }, + { + name: 'build-full-contact', + description: + 'Take a prospect name and company, resolve the domain, then find the work email and phone to assemble a complete contact.', + content: + '# Build a Full Contact\n\nGo from a name and company to a complete, enriched contact.\n\n## Steps\n1. Run the Company Domain enrichment to resolve the company website domain.\n2. Run the Work Email enrichment using the name and resolved domain.\n3. Run the Phone Number enrichment for a direct phone.\n4. Assemble the results into one contact record.\n\n## Output\nA complete contact with name, company, domain, verified email, and phone, plus confidence for each field.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/evernote.ts b/apps/sim/blocks/blocks/evernote.ts index 3c66c19a323..624c18ef7bf 100644 --- a/apps/sim/blocks/blocks/evernote.ts +++ b/apps/sim/blocks/blocks/evernote.ts @@ -378,4 +378,31 @@ export const EvernoteBlockMeta = { tags: ['individual', 'research'], }, ], + skills: [ + { + name: 'create-evernote-note', + description: 'Create a new Evernote note with a title, content, tags, and target notebook.', + content: + '# Create Evernote Note\n\nSave new content as a note in Evernote.\n\n## Steps\n1. Confirm the note title and content. Plain text is fine; the content is stored as ENML.\n2. Choose the Create Note operation. To file it in a specific notebook, resolve the notebook GUID with List Notebooks and pass it.\n3. Add comma-separated tag names so the note is findable later.\n\n## Output\nReturn the new note GUID, its title, and the notebook and tags it was saved under.', + }, + { + name: 'search-evernote-notes', + description: + 'Search Evernote for notes matching a query and return their titles and metadata.', + content: + '# Search Evernote Notes\n\nFind notes across Evernote using its search grammar.\n\n## Steps\n1. Build a query using Evernote search syntax — e.g., tag:work, intitle:meeting, notebook scoping, or plain keywords.\n2. Run Search Notes. Scope to a notebook GUID when the location is known, and set max results and offset to page through matches.\n3. For any note you need the body of, call Get Note with its GUID and include content.\n\n## Output\nReturn the matching notes with title, GUID, and notebook, plus the total match count. If a note body is needed, include its retrieved content.', + }, + { + name: 'extract-note-action-items', + description: 'Read recent Evernote notes and extract action items, owners, and due dates.', + content: + '# Extract Note Action Items\n\nPull tasks out of meeting notes or research notes in Evernote.\n\n## Steps\n1. Use Search Notes to find the relevant recent notes (e.g., by tag or notebook).\n2. For each match, call Get Note with content to read the full body.\n3. Identify action items, the responsible owner, and any due dates mentioned in the text.\n\n## Output\nReturn a structured list of action items, each with its owner, due date if stated, and a link back to the source note GUID. Flag items with no clear owner.', + }, + { + name: 'organize-notes-with-tags', + description: 'Create tags and apply them to Evernote notes to keep them organized.', + content: + '# Organize Notes with Tags\n\nKeep Evernote notes structured by tagging them consistently.\n\n## Steps\n1. Call List Tags to see existing tags and avoid duplicates. Create any missing tag with Create Tag (optionally nested under a parent tag).\n2. For each note to organize, read it with Get Note if needed, decide the right tags from its content, and apply them via Update Note with the tag names.\n3. Keep tag names consistent in casing and wording across notes.\n\n## Output\nReturn each note GUID with the tags applied and note any new tags that were created.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/exa.ts b/apps/sim/blocks/blocks/exa.ts index 38f84a61148..f2489dd63a4 100644 --- a/apps/sim/blocks/blocks/exa.ts +++ b/apps/sim/blocks/blocks/exa.ts @@ -514,4 +514,31 @@ export const ExaBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'search-the-web-with-exa', + description: + 'Run an Exa neural or keyword search to find high-quality web sources on a topic.', + content: + '# Search the Web with Exa\n\nFind authoritative web pages on a topic using Exa AI search.\n\n## Steps\n1. Use the Search operation with a clear query. Pick the search type — neural for meaning-based discovery, keyword for exact terms, or auto to let Exa decide.\n2. Narrow results with include/exclude domains, a category filter (research paper, news article, company, GitHub), and published-date bounds for recency.\n3. Enable include-text or include-summary so each result comes back with usable content rather than just a link.\n\n## Output\nReturn the top results with title, URL, published date, and the text or summary. Note which filters were applied so the search can be tightened or broadened.', + }, + { + name: 'answer-question-with-citations', + description: 'Use Exa Answer to get a direct, sourced answer to a factual question.', + content: + '# Answer Question with Citations\n\nGet a grounded answer to a question with supporting sources via Exa.\n\n## Steps\n1. Use the Answer operation and pass the question in natural language.\n2. Enable include-text when you want the supporting passages, not just the citation URLs.\n3. Review the citations to confirm the answer is well-supported before relying on it.\n\n## Output\nReturn the answer text plus its citations (titles and URLs). If the citations are weak or conflicting, say so and recommend a follow-up search.', + }, + { + name: 'extract-page-contents', + description: 'Use Exa Get Contents to pull clean text and summaries from a set of URLs.', + content: + '# Extract Page Contents\n\nRetrieve readable content from specific web pages using Exa.\n\n## Steps\n1. Use the Get Contents operation with the target URLs (comma-separated).\n2. Enable include-text for full content, and supply a summary query to get a focused summary tailored to what you need.\n3. To pull deeper context from a site, set a subpage count and target keywords (e.g., docs, pricing, about).\n\n## Output\nReturn each URL with its extracted text or summary and any highlights. Flag any URL that could not be crawled.', + }, + { + name: 'find-similar-pages', + description: 'Use Exa Find Similar Links to discover pages related to a known URL.', + content: + '# Find Similar Pages\n\nDiscover sources similar to a reference page using Exa.\n\n## Steps\n1. Use the Find Similar Links operation with the source URL.\n2. Set the number of results and enable exclude-source-domain so you get genuinely new sources, not more pages from the same site.\n3. Apply a category filter or include/exclude domains to keep the discovery on-target, and enable include-text or include-summary for context.\n\n## Output\nReturn the similar pages with title, URL, and a snippet or summary, ordered by relevance. Note the filters used.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/extend.ts b/apps/sim/blocks/blocks/extend.ts index c5b8b44317c..4ed2a3f0123 100644 --- a/apps/sim/blocks/blocks/extend.ts +++ b/apps/sim/blocks/blocks/extend.ts @@ -280,4 +280,27 @@ export const ExtendBlockMeta = { tags: ['legal', 'document-processing', 'automation'], }, ], + skills: [ + { + name: 'extract-invoice-fields', + description: + 'Parse an uploaded invoice with Extend and return structured vendor, line item, and total fields.', + content: + '# Extract Invoice Fields\n\nUse Extend to turn an invoice PDF or image into structured, validated data.\n\n## Steps\n1. Take the uploaded invoice document (file upload or URL).\n2. Run the Extend parser to produce structured chunks and blocks.\n3. Pull the key fields: vendor name, invoice number, invoice date, due date, line items (description, quantity, unit price), subtotal, tax, and total.\n4. Validate that totals add up and that required fields are present; flag any that are missing or inconsistent.\n\n## Output\nReturn a clean JSON object with the extracted fields plus a list of any validation warnings. Note the page count and credits used so cost can be tracked.', + }, + { + name: 'parse-document-to-markdown', + description: + 'Convert a scanned or complex document into clean, LLM-ready markdown using Extend.', + content: + '# Parse Document to Markdown\n\nUse Extend to convert any supported document (PDF, image, or Office file) into clean markdown an agent can reason over.\n\n## Steps\n1. Take the source document and choose a chunking strategy (page, section, or document) based on how the content will be consumed.\n2. Run the Extend parser with markdown output.\n3. Stitch the returned chunks into a single ordered markdown document, preserving headings, tables, and lists.\n\n## Output\nReturn the full markdown text plus the page count. If the document was chunked, also return the per-chunk markdown so downstream steps can process sections independently.', + }, + { + name: 'classify-and-route-document', + description: + 'Parse an uploaded document with Extend, identify its type, and route it to the right downstream handler.', + content: + '# Classify and Route Document\n\nUse Extend to read an incoming document and decide where it should go.\n\n## Steps\n1. Run the Extend parser on the uploaded document to get its text content.\n2. Inspect the parsed content to classify the document type (e.g. invoice, contract, claim form, purchase order, KYC document).\n3. Pull the few identifying fields needed for routing (such as document type, reference number, and amount).\n4. Decide the destination queue, table, or channel based on the classification and any thresholds.\n\n## Output\nReturn the detected document type, the routing decision, and the extracted routing fields. Note any document that could not be confidently classified for manual review.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/fathom.ts b/apps/sim/blocks/blocks/fathom.ts index 20be7e7f1d4..ea84489503d 100644 --- a/apps/sim/blocks/blocks/fathom.ts +++ b/apps/sim/blocks/blocks/fathom.ts @@ -283,4 +283,27 @@ export const FathomBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'summarize-recent-meetings', + description: + 'List recent Fathom meetings and produce a concise digest of decisions, owners, and action items.', + content: + '# Summarize Recent Meetings\n\nUse Fathom to pull recent meetings and turn them into a readable digest.\n\n## Steps\n1. List Fathom meetings, filtering by a date range (createdAfter / createdBefore) and optionally by team or recorder.\n2. Request summaries and action items in the response so each meeting comes back with its recap.\n3. Across the meetings, group the key decisions, commitments, and open action items by topic or owner.\n\n## Output\nReturn a digest with one short section per meeting (title, date, attendees, key points) followed by a consolidated action-item list with owners. Use the pagination cursor to cover the full range if there are many meetings.', + }, + { + name: 'extract-meeting-action-items', + description: + 'Pull a specific Fathom meeting summary and extract a clean list of action items with owners.', + content: + '# Extract Meeting Action Items\n\nUse Fathom to turn a single meeting into a tracked task list.\n\n## Steps\n1. Get the meeting summary for the given recording ID.\n2. Identify every commitment or next step mentioned, with the responsible owner and any stated due date.\n3. If owners are unclear, fall back to the transcript to find who made each commitment.\n\n## Output\nReturn a structured list of action items, each with the task description, owner, and due date (or null). Include a one-line meeting recap at the top for context.', + }, + { + name: 'log-sales-call-to-crm', + description: + 'Pull a Fathom call summary and CRM matches, then format a CRM-ready note with next steps.', + content: + '# Log Sales Call to CRM\n\nUse Fathom to capture a sales call and prepare it for the CRM.\n\n## Steps\n1. Get the summary for the meeting recording ID, including CRM matches so the linked contact or deal is known.\n2. Extract the customer pain points, objections, commitments, and agreed next steps.\n3. Format a concise call note suitable for logging against the matched CRM record.\n\n## Output\nReturn the matched CRM contact or deal identifier, a formatted call note, and a list of follow-up next steps with owners and dates so they can be written into the CRM.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/findymail.ts b/apps/sim/blocks/blocks/findymail.ts index 8d0e2fa27e1..e2d2daafbc1 100644 --- a/apps/sim/blocks/blocks/findymail.ts +++ b/apps/sim/blocks/blocks/findymail.ts @@ -501,4 +501,34 @@ export const FindymailBlockMeta = { tags: ['sales', 'research', 'enrichment'], }, ], + skills: [ + { + name: 'find-verified-email', + description: + 'Find a prospect verified work email from their name and company, or from a LinkedIn URL.', + content: + '# Find Verified Email\n\nUse Findymail to discover a deliverable work email for a prospect.\n\n## Steps\n1. If you have a name plus company domain, use Find Email From Name. If you have a LinkedIn profile URL, use Find Email From LinkedIn.\n2. Findymail verifies the email at discovery time, so the returned address is already checked for deliverability.\n3. Capture the contact name, email, and domain from the response.\n\n## Output\nReturn the verified email, the matched contact name, and the source company domain. If no email was found, say so clearly rather than guessing an address.', + }, + { + name: 'verify-email-list', + description: + 'Run a list of email addresses through Findymail verification and split into deliverable and undeliverable.', + content: + '# Verify Email List\n\nUse Findymail to clean an email list before an outbound send.\n\n## Steps\n1. For each email address, run Verify Email.\n2. Read the verified flag and the detected provider for each result.\n3. Partition the list into deliverable addresses and undeliverable ones.\n\n## Output\nReturn two lists: deliverable emails (with provider) and undeliverable emails. Include a short summary count so the caller knows how many were removed.', + }, + { + name: 'map-company-team', + description: + 'Given a company domain, find employees by job title and enrich the company profile into a team map.', + content: + '# Map Company Team\n\nUse Findymail to build an org map for a target account.\n\n## Steps\n1. Use Get Company Info on the domain to pull industry, size, and description.\n2. Use Find Employees with the company website and a list of target job titles to pull matching people.\n3. Optionally find each contact verified email or phone for the highest-priority roles.\n\n## Output\nReturn the company profile plus a list of employees (name, job title, LinkedIn URL, and email where available), grouped by function so the account team can see the buying committee.', + }, + { + name: 'enrich-from-email', + description: + 'Reverse-lookup an email address with Findymail to recover the full LinkedIn profile and current company.', + content: + '# Enrich From Email\n\nUse Findymail to turn a bare email address into a full contact record.\n\n## Steps\n1. Run Reverse Email Lookup on the email, requesting the full profile.\n2. Pull the full name, headline, job title, location, current company, and profile details.\n3. Optionally call Get Company Info on the recovered company domain for firmographics.\n\n## Output\nReturn a structured contact record: name, title, company, location, LinkedIn URL, and the original email. Note any fields the lookup could not resolve.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/firecrawl.ts b/apps/sim/blocks/blocks/firecrawl.ts index e5cf4cfa470..104fc6e9fe1 100644 --- a/apps/sim/blocks/blocks/firecrawl.ts +++ b/apps/sim/blocks/blocks/firecrawl.ts @@ -729,4 +729,34 @@ export const FirecrawlBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'scrape-page-to-markdown', + description: + 'Scrape a single URL with Firecrawl and return clean main-content markdown for an agent to read.', + content: + '# Scrape Page to Markdown\n\nUse Firecrawl to fetch a web page as clean, LLM-ready markdown.\n\n## Steps\n1. Use the Scrape operation on the target URL.\n2. Enable Only Main Content to strip navigation, ads, and footers; set a Wait For delay if the page renders content with JavaScript.\n3. Return the markdown output and capture page metadata (title, description).\n\n## Output\nReturn the page markdown plus key metadata. If the page failed to load or returned empty content, report that instead of fabricating text.', + }, + { + name: 'extract-structured-data', + description: + 'Pull structured fields from one or more URLs using Firecrawl Extract with a prompt or schema.', + content: + '# Extract Structured Data\n\nUse Firecrawl to extract specific fields from web pages.\n\n## Steps\n1. Use the Extract operation with the list of target URLs.\n2. Provide a clear extraction prompt describing exactly what to pull (for example product name, price, and description).\n3. Run the extraction and read the structured data from the response.\n\n## Output\nReturn the extracted records as structured JSON. List the source URLs and flag any URL that yielded no data.', + }, + { + name: 'crawl-site', + description: + 'Crawl an entire site or section with Firecrawl and return the page content for indexing or analysis.', + content: + '# Crawl Site\n\nUse Firecrawl to traverse a site and collect its pages.\n\n## Steps\n1. Use the Crawl operation on the root URL, setting a sensible page Limit to control cost.\n2. Enable Only Main Content so each page comes back as clean markdown.\n3. Collect the crawled pages and their URLs from the response.\n\n## Output\nReturn the list of crawled pages with their URL and markdown content, plus the total page count. This output is ready to chunk and embed into a knowledge base.', + }, + { + name: 'research-with-search', + description: + 'Run a web search with Firecrawl, then scrape the top results into a cited research brief.', + content: + '# Research With Search\n\nUse Firecrawl to gather and synthesize web sources on a topic.\n\n## Steps\n1. Use the Search operation with the research query and a result Limit.\n2. For the most relevant results, use Scrape to pull the full page markdown.\n3. Synthesize the findings into a brief, attributing each claim to its source URL.\n\n## Output\nReturn a structured research brief with key findings and a Sources list of the URLs used. Keep claims grounded in the scraped content.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/fireflies.ts b/apps/sim/blocks/blocks/fireflies.ts index fbb1b4b5b54..674058943ba 100644 --- a/apps/sim/blocks/blocks/fireflies.ts +++ b/apps/sim/blocks/blocks/fireflies.ts @@ -732,6 +732,29 @@ export const FirefliesBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'summarize-meeting-transcript', + description: + 'Fetch a Fireflies transcript and produce a structured recap with decisions, action items, and owners.', + content: + '# Summarize Meeting Transcript\n\nUse Fireflies to turn a recorded meeting into a clean recap.\n\n## Steps\n1. Get the transcript for the given transcript ID (or pick the latest from List Transcripts).\n2. Read the sentences and any provided summary to identify the main topics discussed.\n3. Extract key decisions, action items with owners, and notable questions or risks.\n\n## Output\nReturn a structured recap: a short overview, a bulleted list of decisions, and an action-item table (task, owner, due date). Keep it grounded in the transcript content.', + }, + { + name: 'extract-action-items', + description: + 'Pull a Fireflies transcript and extract a clean list of action items with owners and due dates.', + content: + '# Extract Action Items\n\nUse Fireflies to capture follow-ups from a meeting.\n\n## Steps\n1. Get the transcript for the meeting by its transcript ID.\n2. Scan the sentences for commitments, assignments, and next steps.\n3. Attribute each item to the speaker who owns it and capture any stated deadline.\n\n## Output\nReturn a list of action items, each with the task, owner, and due date (or null). Add a one-line meeting summary at the top for context.', + }, + { + name: 'create-meeting-soundbite', + description: + 'Create a Fireflies soundbite (bite) clipping a key moment from a transcript for sharing.', + content: + '# Create Meeting Soundbite\n\nUse Fireflies to clip and share a highlight from a recorded meeting.\n\n## Steps\n1. Get the transcript and find the start and end timestamps of the moment to clip.\n2. Use Create Bite with the transcript ID and the chosen time range.\n3. Confirm the bite was created and capture its identifier or link.\n\n## Output\nReturn the soundbite identifier or shareable link plus a short caption describing the clipped moment.', + }, + ], } as const satisfies BlockMeta export const FirefliesV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/gamma.ts b/apps/sim/blocks/blocks/gamma.ts index 5a69795bb94..ada93081b37 100644 --- a/apps/sim/blocks/blocks/gamma.ts +++ b/apps/sim/blocks/blocks/gamma.ts @@ -413,4 +413,32 @@ export const GammaBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'generate-presentation', + description: 'Generate a polished presentation deck from a topic or outline using Gamma.', + content: + '# Generate Presentation\n\nUse Gamma to turn a topic or outline into a finished presentation.\n\n## Steps\n1. Gather the source content: a topic, a brief, or a structured outline of the points to cover.\n2. Call Gamma to generate a presentation, choosing the number of cards and a theme that fits the audience.\n3. Request an export format (such as PDF or PPTX) if a downloadable file is needed.\n\n## Output\nReturn the link to the generated Gamma and, if requested, the export file URL. Summarize the deck structure (titles per card) so the requester can review before sharing.', + }, + { + name: 'generate-document', + description: 'Generate a structured document or webpage from input text using Gamma.', + content: + '# Generate Document\n\nUse Gamma to produce a formatted document or webpage from raw input.\n\n## Steps\n1. Provide the input text and choose the output format (document or webpage).\n2. Call Gamma to generate the content, setting a theme and the desired length or number of cards.\n3. Capture the resulting Gamma URL and any export URL.\n\n## Output\nReturn the generated Gamma link plus a short outline of the sections it produced. Include the export file URL if one was requested.', + }, + { + name: 'personalize-deck-from-template', + description: + 'Adapt an existing Gamma template into a prospect or client-specific deck with Generate from Template.', + content: + '# Personalize Deck From Template\n\nUse Gamma to scale on-brand, personalized decks from a proven template.\n\n## Steps\n1. Identify the template gamma ID to adapt (a master pitch or proposal deck) and collect the recipient details and the angle to tailor for.\n2. Use Generate from Template with that template gamma ID and a prompt that retargets the audience, swaps in the recipient name and use case, and adjusts emphasis (for example highlight compliance for a healthcare buyer). The template structure is preserved by default.\n3. Request an export (PDF or PPTX) if a downloadable file is needed.\n\n## Output\nReturn the generated Gamma link and any export URL. Note the recipient it was generated for so it can be attached to the right CRM record or email.', + }, + { + name: 'check-generation-status', + description: + 'Poll a Gamma generation job by its generation ID and return the final deck link once ready.', + content: + '# Check Generation Status\n\nGamma generation is asynchronous, so use this to wait for a deck to finish.\n\n## Steps\n1. Take the generation ID returned when the deck was requested.\n2. Use Check Status to read the current status of the job.\n3. Repeat until the status is completed (or failed), respecting a sensible polling interval.\n\n## Output\nReturn the final status and, on success, the Gamma URL and any export URL. On failure, return the error details so the caller can retry or adjust the request.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/github.ts b/apps/sim/blocks/blocks/github.ts index eff309271c4..4caa13560b7 100644 --- a/apps/sim/blocks/blocks/github.ts +++ b/apps/sim/blocks/blocks/github.ts @@ -2157,6 +2157,36 @@ export const GitHubBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'review-pull-request', + description: + 'Fetch a GitHub PR, its changed files, and diff, then post a structured review comment.', + content: + '# Review Pull Request\n\nUse GitHub to read a pull request and leave a useful review.\n\n## Steps\n1. Get PR details for the given owner, repo, and PR number to read the title, description, and status.\n2. Get the PR files to see the changed paths and diffs.\n3. Assess the changes for correctness, missing tests, and risky edits.\n4. Post a PR comment summarizing the review with specific, actionable feedback.\n\n## Output\nConfirm the comment was posted and return a short summary of the findings: what looks good, what needs changes, and any blocking concerns.', + }, + { + name: 'triage-new-issue', + description: + 'Read a GitHub issue, classify it, apply labels, and assign it to the right owner.', + content: + '# Triage New Issue\n\nUse GitHub to triage an incoming issue.\n\n## Steps\n1. Get the issue by owner, repo, and issue number to read its title and body.\n2. Classify it (bug, feature, question, docs) and judge its severity.\n3. Add the appropriate labels with Add issue labels.\n4. Assign the issue to the relevant owner with Add issue assignees.\n\n## Output\nReturn the applied labels, the assignee, and a one-line triage summary. If the issue lacks reproduction details, note what information is missing.', + }, + { + name: 'summarize-repo-activity', + description: + 'Pull recent GitHub PRs, commits, and issues for a repo and produce a concise activity digest.', + content: + '# Summarize Repo Activity\n\nUse GitHub to build a status digest for a repository.\n\n## Steps\n1. List open pull requests and recent issues for the owner and repo.\n2. Get the latest commit to anchor the digest in time.\n3. Group activity into in-progress work, newly opened items, and anything stalled or awaiting review.\n\n## Output\nReturn a digest with three sections: open PRs (title, author, status), notable issues, and the latest commit. Keep it short enough to drop into a standup or Slack channel.', + }, + { + name: 'open-pull-request-with-changes', + description: + 'Create a branch, commit a file change, and open a GitHub pull request for review.', + content: + '# Open Pull Request With Changes\n\nUse GitHub to land a change as a reviewable PR.\n\n## Steps\n1. Create a new branch off the default branch with Create branch.\n2. Create or update the target file on that branch with Create file or Update file, including a clear commit message.\n3. Open a pull request from the new branch with Create pull request, writing a descriptive title and body.\n4. Optionally request reviewers with Request PR reviewers.\n\n## Output\nReturn the new PR number and URL, the branch name, and the files changed so the requester can track it to merge.', + }, + ], } as const satisfies BlockMeta export const GitHubV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/gitlab.ts b/apps/sim/blocks/blocks/gitlab.ts index 7283f6bcd24..f8c37fd3fe0 100644 --- a/apps/sim/blocks/blocks/gitlab.ts +++ b/apps/sim/blocks/blocks/gitlab.ts @@ -819,4 +819,27 @@ export const GitLabBlockMeta = { tags: ['engineering', 'research', 'devops'], }, ], + skills: [ + { + name: 'review-merge-request', + description: + 'Fetch a GitLab merge request and post a structured review comment with actionable feedback.', + content: + '# Review Merge Request\n\nUse GitLab to read a merge request and leave a useful review.\n\n## Steps\n1. Get the merge request by project ID and MR IID to read its title, description, and changes.\n2. Assess the change for correctness, missing tests, and risky edits.\n3. Post a review note on the MR with Add MR Comment, summarizing the feedback.\n\n## Output\nConfirm the comment was posted and return a short summary: what looks good, what needs changes, and any blocking concerns.', + }, + { + name: 'triage-gitlab-issue', + description: + 'Read a GitLab issue, classify it, and post a triage comment or update its fields.', + content: + '# Triage GitLab Issue\n\nUse GitLab to triage an incoming issue.\n\n## Steps\n1. Get the issue by project ID and issue IID to read its title and description.\n2. Classify it (bug, feature, question) and judge severity.\n3. Update the issue with the right labels and assignee using Update Issue, and add a triage note with Add Issue Comment.\n\n## Output\nReturn the classification, applied labels, assignee, and a one-line triage summary. Note any missing reproduction details.', + }, + { + name: 'monitor-pipeline-status', + description: + 'Check GitLab pipeline status for a project and report failures, optionally retrying a failed pipeline.', + content: + '# Monitor Pipeline Status\n\nUse GitLab to keep an eye on CI pipelines.\n\n## Steps\n1. List pipelines for the project and identify the most recent runs.\n2. Get the pipeline details for any that failed to read the status and reason.\n3. If a failure looks transient, use Retry Pipeline to re-run it.\n\n## Output\nReturn a summary of recent pipeline runs (ref, status, when) and call out any failures. If a retry was triggered, include the retried pipeline ID.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/gmail.ts b/apps/sim/blocks/blocks/gmail.ts index e55c528303a..6fb8d4ca126 100644 --- a/apps/sim/blocks/blocks/gmail.ts +++ b/apps/sim/blocks/blocks/gmail.ts @@ -728,6 +728,33 @@ export const GmailBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'triage-inbox', + description: + 'Sort unread email by urgency and draft replies for the most important messages.', + content: + '# Triage Inbox\n\nReview unread Gmail messages and bring order to the inbox.\n\n## Steps\n1. Read unread messages from the relevant time window.\n2. Classify each as Urgent, Today, This week, or FYI based on sender, subject, and content.\n3. For Urgent and Today items, draft a concise reply.\n4. Flag anything that needs a meeting or a decision from someone else.\n\n## Output\nReturn a prioritized list: each message with its sender, a one-line summary, the assigned priority, and the draft reply where one was written. Do not send anything without confirmation.', + }, + { + name: 'summarize-email-thread', + description: 'Condense a long email thread into the key points, decisions, and action items.', + content: + '# Summarize Email Thread\n\nGiven a Gmail thread, produce a tight summary.\n\n## Steps\n1. Read every message in the thread in order.\n2. Identify the core topic, what was decided, and what is still open.\n3. Pull out action items and who owns each.\n\n## Output\n- A one-sentence TL;DR.\n- Key decisions as bullets.\n- Action items with owners.\n- Open questions that still need an answer.', + }, + { + name: 'draft-reply-from-context', + description: 'Draft a contextual reply to an email in the right tone, ready for review.', + content: + '# Draft Reply From Context\n\nWrite a reply to an incoming email that is ready to send after a quick review.\n\n## Steps\n1. Read the email and any prior thread context.\n2. Determine what the sender is asking for and the appropriate tone (formal, friendly, brief).\n3. Draft a reply that answers every question and proposes clear next steps.\n\n## Output\nA complete draft reply with subject and body. Keep it concise, match the sender style, and leave placeholders in brackets for any detail you cannot infer. Do not send without confirmation.', + }, + { + name: 'find-and-extract-emails', + description: 'Search Gmail for messages matching a query and extract the details you need.', + content: + '# Find And Extract Emails\n\nLocate specific emails and pull structured information from them.\n\n## Steps\n1. Build a Gmail search query from the request (sender, subject keywords, date range, label, has attachment).\n2. Retrieve matching messages.\n3. Extract the requested fields from each, for example invoice amounts, order numbers, contact details, or attachment names.\n\n## Output\nA structured list of the matching emails with the extracted fields, plus a link or message id for each so the source can be opened.', + }, + ], } as const satisfies BlockMeta export const GmailV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/gong.ts b/apps/sim/blocks/blocks/gong.ts index 3a4f30f6072..223f7883210 100644 --- a/apps/sim/blocks/blocks/gong.ts +++ b/apps/sim/blocks/blocks/gong.ts @@ -784,4 +784,27 @@ export const GongBlockMeta = { tags: ['sales', 'research'], }, ], + skills: [ + { + name: 'summarize-call', + description: + 'Pull a Gong call transcript and produce a structured recap with topics, objections, and next steps.', + content: + '# Summarize Call\n\nUse Gong to turn a recorded call into a clean recap.\n\n## Steps\n1. Get the call by its call ID to read the metadata (participants, duration, account).\n2. Get the call transcript for the same call ID.\n3. Identify the main topics, customer objections, and agreed next steps from the transcript.\n\n## Output\nReturn a recap: a short overview, key topics discussed, objections raised, and a list of next steps with owners. Keep it grounded in the transcript.', + }, + { + name: 'extract-deal-signals', + description: + 'Read a Gong call transcript and extract CRM-ready deal signals like decision-maker, competitor, and next step.', + content: + '# Extract Deal Signals\n\nUse Gong to turn conversation content into structured deal attributes.\n\n## Steps\n1. Get the call transcript for the given call ID.\n2. Scan for high-value signals: decision-maker, budget, timeline, competitor mentions, use case, and the agreed next step with its date.\n3. Normalize each signal into a structured field.\n\n## Output\nReturn a structured object of deal attributes (decision_maker, competitor, next_step, next_step_date, use_case, and any others found). Leave fields null when not mentioned rather than guessing, so they can be written to CRM.', + }, + { + name: 'review-recent-calls', + description: + 'List recent Gong calls in a date range and produce a digest of themes and follow-ups across them.', + content: + '# Review Recent Calls\n\nUse Gong to summarize a batch of recent calls.\n\n## Steps\n1. List calls (or use Get Extensive Calls) filtered by a date range and optionally by user or workspace.\n2. For the most relevant calls, get the transcript to pull themes and outcomes.\n3. Roll the findings up into recurring themes, common objections, and open follow-ups across the calls.\n\n## Output\nReturn a digest: a per-call one-liner, the cross-call themes, and a consolidated follow-up list. Note any call missing a clear next step.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google.ts b/apps/sim/blocks/blocks/google.ts index 38f6960709c..80d04ba82b5 100644 --- a/apps/sim/blocks/blocks/google.ts +++ b/apps/sim/blocks/blocks/google.ts @@ -162,4 +162,27 @@ export const GoogleSearchBlockMeta = { tags: ['support', 'research', 'automation'], }, ], + skills: [ + { + name: 'search-the-web', + description: + 'Run a Google web search and return the most relevant results with titles and links.', + content: + '# Search the Web\n\nFind current information with Google Custom Search.\n\n## Steps\n1. Turn the request into an effective query. Use operators when helpful: "exact phrase", `site:domain.com`, `-exclude`, `OR`, `filetype:pdf`.\n2. Set Number of Results to a sensible value (e.g., 10).\n3. Run the search with the API key and Custom Search Engine ID.\n4. Read the result items: title, link, and snippet.\n\n## Output\nA ranked list of results, each with title, URL, and a one-line snippet. Drop low-relevance hits and note if the query returned little so it can be broadened.', + }, + { + name: 'research-and-summarize', + description: + 'Search Google for a topic, gather the best sources, and synthesize a cited answer.', + content: + '# Research and Summarize\n\nAnswer a question from fresh web sources.\n\n## Steps\n1. Break the question into 1-3 focused search queries.\n2. Run each search and collect the most relevant result items (title, link, snippet).\n3. Synthesize a concise answer grounded in the snippets; do not assert facts the sources do not support.\n4. Attribute each claim to its source link.\n\n## Output\nA short, sourced answer followed by a list of the sources used (title + URL). If sources conflict, say so rather than guessing.', + }, + { + name: 'monitor-mentions', + description: + 'Search Google for recent mentions of a brand, person, or keyword and surface notable hits.', + content: + '# Monitor Mentions\n\nFind recent web mentions of a target term.\n\n## Steps\n1. Build queries for the brand/person/keyword, optionally scoped with `site:` for specific outlets or quotes for exact names.\n2. Run the searches and collect result items.\n3. Filter out irrelevant or stale hits and dedupe near-identical results.\n4. Classify each remaining mention (e.g., news, review, social) and gauge tone where possible.\n\n## Output\nA list of notable mentions: title, source URL, a one-line summary, and a tone tag. Lead with the most significant items.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_ads.ts b/apps/sim/blocks/blocks/google_ads.ts index cee652c7ec0..f64578b2f4a 100644 --- a/apps/sim/blocks/blocks/google_ads.ts +++ b/apps/sim/blocks/blocks/google_ads.ts @@ -364,4 +364,27 @@ export const GoogleAdsBlockMeta = { tags: ['marketing', 'analysis'], }, ], + skills: [ + { + name: 'report-campaign-performance', + description: + 'Pull Google Ads campaign performance for a date range and produce a clear metrics report.', + content: + '# Report Campaign Performance\n\nUse Google Ads to summarize how campaigns are performing.\n\n## Steps\n1. List campaigns for the customer to know what is active.\n2. Use Campaign Performance over the chosen date range to pull impressions, clicks, cost, conversions, CTR, CPC, and ROAS.\n3. Rank campaigns by spend and by efficiency to surface what is working and what is not.\n\n## Output\nReturn a per-campaign metrics table plus a short narrative: top performers, underperformers, and where spend is being wasted. Note the date range used.', + }, + { + name: 'analyze-ad-performance', + description: + 'Pull ad-level Google Ads performance and identify the best and worst creatives in each ad group.', + content: + '# Analyze Ad Performance\n\nUse Google Ads to compare creatives within campaigns.\n\n## Steps\n1. List ad groups for the target campaign or customer.\n2. Use Ad Performance over the date range to pull per-ad clicks, conversions, CTR, and cost.\n3. Within each ad group, identify the strongest and weakest ads.\n\n## Output\nReturn, per ad group, the best and worst performing ads with their key metrics, plus a recommendation (scale, pause, or rewrite). Keep recommendations tied to the data.', + }, + { + name: 'run-gaql-query', + description: + 'Run a custom GAQL query against Google Ads to answer a specific reporting question.', + content: + '# Run GAQL Query\n\nUse Google Ads to answer an ad-hoc reporting question with GAQL.\n\n## Steps\n1. Clarify the metrics, dimensions, and segments the question needs.\n2. Write a valid GAQL query (SELECT fields FROM resource WHERE conditions) scoped to the customer and date range.\n3. Use the Custom Query operation to run it and read the rows.\n\n## Output\nReturn the result rows as a clean table along with the GAQL query that produced them, so the analysis is reproducible.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_bigquery.ts b/apps/sim/blocks/blocks/google_bigquery.ts index 94d5ad72ecf..40836c732ba 100644 --- a/apps/sim/blocks/blocks/google_bigquery.ts +++ b/apps/sim/blocks/blocks/google_bigquery.ts @@ -359,4 +359,26 @@ export const GoogleBigQueryBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'answer-question-with-sql', + description: + 'Inspect BigQuery schema, translate a natural-language question into safe SQL, run it, and return results.', + content: + '# Answer Question With SQL\n\nUse BigQuery to answer a data question from plain English.\n\n## Steps\n1. List datasets and tables, and Get Table on the relevant ones to understand the schema and column types.\n2. Translate the question into a single read-only BigQuery Standard SQL query, scoping it with filters and a LIMIT to control cost.\n3. Use Run Query to execute it.\n\n## Output\nReturn the result rows as a table plus the exact SQL query used, so the answer is verifiable. If the schema cannot support the question, say what is missing.', + }, + { + name: 'explore-dataset-schema', + description: + 'List BigQuery datasets and tables and summarize the schema of a dataset for an analyst.', + content: + '# Explore Dataset Schema\n\nUse BigQuery to map out what data is available.\n\n## Steps\n1. List datasets in the project.\n2. List tables in the target dataset.\n3. Get Table on each relevant table to read its columns, types, and descriptions.\n\n## Output\nReturn a structured schema summary: each table with its columns, types, and a one-line purpose. Highlight likely join keys so an analyst can plan queries.', + }, + { + name: 'load-rows-to-table', + description: 'Insert structured rows into a BigQuery table for logging or pipeline output.', + content: + '# Load Rows to Table\n\nUse BigQuery to write structured records into a table.\n\n## Steps\n1. Confirm the target dataset and table, and Get Table to verify the expected columns and types.\n2. Shape the incoming records to match the table schema exactly.\n3. Use Insert Rows to write the batch.\n\n## Output\nReturn the count of rows inserted and any rows rejected with their error. If types did not match the schema, report which fields failed rather than silently dropping data.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_books.ts b/apps/sim/blocks/blocks/google_books.ts index 0470fe3b50f..a78f2f52eff 100644 --- a/apps/sim/blocks/blocks/google_books.ts +++ b/apps/sim/blocks/blocks/google_books.ts @@ -271,4 +271,27 @@ export const GoogleBooksBlockMeta = { tags: ['research'], }, ], + skills: [ + { + name: 'find-books-on-topic', + description: + 'Search Google Books for the most relevant titles on a topic and return a ranked, summarized list.', + content: + '# Find Books on a Topic\n\nUse Google Books to discover authoritative titles for a subject and present a clean shortlist.\n\n## Steps\n1. Take the topic or question from the request.\n2. Run a Search Volumes operation with a focused query. Use field operators when helpful: `intitle:`, `inauthor:`, `subject:`. Set Order By to `relevance` (or `newest` for recent works).\n3. Set Max Results (1-40) and optionally filter by Print Type (books) or eBook availability.\n4. For the top hits, read title, authors, publisher, published date, average rating, and a short description.\n5. Rank by relevance and rating; drop clearly off-topic results.\n\n## Output\nA numbered list of up to 10 books, each with title, author(s), year, rating (if present), one-line summary, and the preview/info link. Note if a result set is thin so the requester can broaden the query.', + }, + { + name: 'lookup-book-by-isbn', + description: + 'Resolve an ISBN or title into a single canonical book record with full metadata.', + content: + '# Look Up a Book by ISBN or Title\n\nResolve a specific book to its canonical Google Books record.\n\n## Steps\n1. If you have an ISBN, run Search Volumes with query `isbn:`. Otherwise search by `intitle:` plus `inauthor:` to disambiguate.\n2. Pick the best-matching volume and capture its volume ID.\n3. Run Get Volume Details on that volume ID for the fullest metadata.\n4. Collect title, subtitle, authors, publisher, published date, page count, categories, language, ISBN-10/13, and description.\n\n## Output\nA single structured record: title, authors, publisher, year, ISBNs, page count, categories, and the info link. If multiple editions match, list them and flag which is most likely intended.', + }, + { + name: 'build-reading-list', + description: + 'Assemble a curated, themed reading list with summaries from Google Books search results.', + content: + '# Build a Reading List\n\nTurn a topic into a curated reading list a person can act on.\n\n## Steps\n1. Identify the theme and any constraints (level, recency, language) from the request.\n2. Run one or more Search Volumes queries covering the main subtopics; use `langRestrict` and `orderBy` as needed.\n3. For each candidate, capture authors, year, rating, and description.\n4. Deduplicate editions of the same work and keep the best edition.\n5. Group the final picks into 2-4 logical sections (e.g., foundational, advanced, recent).\n\n## Output\nA grouped reading list. Each entry: title, author(s), year, a one-sentence reason it is included, and the preview link. Keep it to 8-15 titles unless asked otherwise.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_calendar.ts b/apps/sim/blocks/blocks/google_calendar.ts index d21ff59062f..9bbc46f8729 100644 --- a/apps/sim/blocks/blocks/google_calendar.ts +++ b/apps/sim/blocks/blocks/google_calendar.ts @@ -782,6 +782,34 @@ export const GoogleCalendarBlockMeta = { tags: ['sales', 'research', 'automation'], }, ], + skills: [ + { + name: 'schedule-meeting', + description: + 'Create a Google Calendar event with the right time, attendees, and details, sending invites.', + content: + '# Schedule a Meeting\n\nCreate a calendar event and invite attendees.\n\n## Steps\n1. Determine the calendar (default to `primary`), title, start and end times, location, and description from the request.\n2. Convert times to ISO 8601 with the correct timezone offset (e.g., `2025-06-03T10:00:00-08:00`).\n3. If the request is conversational (e.g., "lunch with John tomorrow at noon"), use Quick Add instead of building each field by hand.\n4. Run Create Event (or Quick Add) with the attendee emails as a comma-separated list.\n5. Set Send Email Notifications to `all` so attendees are invited.\n\n## Output\nConfirm the created event: title, start/end in a readable format, attendees, and the event link (htmlLink). If a conflict is likely, note it.', + }, + { + name: 'summarize-daily-agenda', + description: + "List today's Google Calendar events and produce a clean, ordered agenda summary.", + content: + '# Summarize the Daily Agenda\n\nProduce a readable agenda for a day or window.\n\n## Steps\n1. Resolve the target window into UTC ISO timestamps for Start Time Filter (timeMin) and End Time Filter (timeMax). For "today", use 00:00:00Z to 23:59:59Z.\n2. Run List Events on the chosen calendar with those filters and a reasonable Max Results.\n3. Sort events chronologically and read summary, start/end, location, and attendees for each.\n4. Flag back-to-back meetings and any event with no agenda or description.\n\n## Output\nA chronological agenda. Each line: time range, title, location (if any), and attendee count. Add a short header with total meetings and total meeting hours.', + }, + { + name: 'find-and-reschedule-event', + description: 'Locate an existing event and update its time, attendees, or details.', + content: + '# Find and Reschedule an Event\n\nUpdate an existing calendar event.\n\n## Steps\n1. If you do not have the event ID, run List Events over a suitable window and match by title/attendees to find the event ID.\n2. Run Get Event to read the current details and confirm it is the right one.\n3. Run Update Event with only the changed fields (new start/end in ISO 8601 with offset, new attendees, new location, or title).\n4. Set Send Email Notifications to `all` so attendees see the change.\n\n## Output\nConfirm what changed (old vs new time/attendees) and return the event link. If multiple events matched, list them and ask which to update before changing anything destructive.', + }, + { + name: 'invite-attendees-to-event', + description: 'Add attendees to an existing Google Calendar event and notify them.', + content: + '# Invite Attendees to an Event\n\nAdd people to an event without recreating it.\n\n## Steps\n1. Obtain the event ID (use List Events to find it if needed).\n2. Collect the attendee emails to add as a comma-separated list.\n3. Run Invite Attendees with Replace Existing set to `Add to existing attendees` (unless asked to replace the whole list).\n4. Set Send Email Notifications to `all`.\n\n## Output\nConfirm the added attendees and the resulting full attendee list, with the event link.', + }, + ], } as const satisfies BlockMeta export const GoogleCalendarV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/google_contacts.ts b/apps/sim/blocks/blocks/google_contacts.ts index a9f38d337d3..7e3190509b1 100644 --- a/apps/sim/blocks/blocks/google_contacts.ts +++ b/apps/sim/blocks/blocks/google_contacts.ts @@ -347,4 +347,26 @@ export const GoogleContactsBlockMeta = { alsoIntegrations: ['workday'], }, ], + skills: [ + { + name: 'add-contact', + description: 'Create a new Google Contact with name, email, phone, and organization details.', + content: + '# Add a Contact\n\nCreate a new entry in Google Contacts.\n\n## Steps\n1. Gather the contact fields from the request: first name (required), last name, email, phone, organization, job title, and notes.\n2. Before creating, run Search Contacts on the email or full name to avoid duplicates.\n3. If no match exists, run Create Contact with the gathered fields and the appropriate email/phone types (work, home, mobile).\n4. Capture the new resource name from the response.\n\n## Output\nConfirm the created contact with name, email, organization, and the resource name. If a likely duplicate was found, surface it and ask before creating.', + }, + { + name: 'find-contact', + description: + 'Search Google Contacts by name, email, phone, or organization and return matches.', + content: + '# Find a Contact\n\nLook up someone in Google Contacts.\n\n## Steps\n1. Build a query from whatever identifier you have (name, email, phone, or organization).\n2. Run Search Contacts with that query and a sensible Page Size.\n3. If you need full details for one match, take its resource name and run Get Contact.\n\n## Output\nA list of matching contacts with name, email, phone, organization, and resource name. If exactly one matches, return its full record; if several match, list them so the requester can disambiguate.', + }, + { + name: 'update-contact-details', + description: + 'Update fields on an existing Google Contact such as email, phone, or job title.', + content: + '# Update Contact Details\n\nModify an existing Google Contact safely.\n\n## Steps\n1. If you do not have the resource name, run Search Contacts to find it.\n2. Run Get Contact to read the current values and capture the ETag (required for updates).\n3. Run Update Contact with the resource name, the ETag, and the changed fields only.\n4. If the update fails on a stale ETag, re-run Get Contact and retry with the fresh ETag.\n\n## Output\nConfirm which fields changed (old vs new) and return the updated record. Never update without first fetching the current ETag.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_docs.ts b/apps/sim/blocks/blocks/google_docs.ts index 7a0220abd97..6c3231e81bc 100644 --- a/apps/sim/blocks/blocks/google_docs.ts +++ b/apps/sim/blocks/blocks/google_docs.ts @@ -284,4 +284,26 @@ export const GoogleDocsBlockMeta = { tags: ['team', 'research', 'sync'], }, ], + skills: [ + { + name: 'create-document-from-content', + description: 'Create a new Google Doc with a title and formatted content in a chosen folder.', + content: + '# Create a Document from Content\n\nGenerate a new Google Doc from supplied or drafted content.\n\n## Steps\n1. Determine the document title and the body content from the request.\n2. If the content uses headings, bold, lists, tables, or links, enable the Markdown option so it renders as formatted Doc content; otherwise leave it off for plain text.\n3. Optionally set the parent folder ID to file the doc in the right place.\n4. Run the Create Document operation with the title, content, and folder.\n\n## Output\nConfirm creation and return the document ID and link. If a folder was specified, confirm it was placed there.', + }, + { + name: 'summarize-document', + description: + 'Read a Google Doc and produce a concise summary with key points and action items.', + content: + '# Summarize a Document\n\nRead a Doc and distill it.\n\n## Steps\n1. Obtain the document ID (select the doc or pass its ID).\n2. Run the Read Document operation to pull the full text.\n3. Identify the main thesis, key points, decisions, and any action items or owners.\n4. Keep the summary faithful to the source; do not invent details not present.\n\n## Output\nA short summary: a one-line gist, 3-6 bullet key points, and an Action Items section (owner + task) if any exist. Reference the doc link.', + }, + { + name: 'append-to-document', + description: + 'Write additional content into an existing Google Doc, such as a running log or report section.', + content: + '# Append to a Document\n\nAdd a new section to an existing Doc.\n\n## Steps\n1. Obtain the target document ID.\n2. Draft the content to add, clearly delimited (e.g., a dated heading for a running log).\n3. Run the Write to Document operation with the document ID and the new content.\n4. For recurring updates, prefix each entry with a date or section header so the doc stays organized.\n\n## Output\nConfirm the content was written and return the document link. Summarize in one line what was appended.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_drive.ts b/apps/sim/blocks/blocks/google_drive.ts index fae933d38a2..972aa1901de 100644 --- a/apps/sim/blocks/blocks/google_drive.ts +++ b/apps/sim/blocks/blocks/google_drive.ts @@ -1281,4 +1281,34 @@ export const GoogleDriveBlockMeta = { tags: ['team', 'research', 'sync'], }, ], + skills: [ + { + name: 'find-file-in-drive', + description: + 'Search Google Drive with query syntax to locate files by name, type, content, or date.', + content: + "# Find a File in Drive\n\nLocate files using Drive query syntax.\n\n## Steps\n1. Translate the request into a Drive query. Common clauses: `name contains 'term'`, `fullText contains 'term'`, `mimeType = 'application/pdf'`, `modifiedTime > '2024-01-01T00:00:00'`, `'email' in owners`, `trashed = false`.\n2. Run the Search Files operation with that query and a Results Per Page value.\n3. If results are too broad, add `and` clauses (file type, owner, date) to narrow.\n4. For a chosen result, run Get File Info for full metadata.\n\n## Output\nA list of matching files: name, type, owner, modified date, and the file ID. Highlight the single best match if the intent was specific.", + }, + { + name: 'organize-files-into-folders', + description: + 'Create folders and move or copy files in Google Drive to keep storage organized.', + content: + '# Organize Files into Folders\n\nFile and tidy Drive content.\n\n## Steps\n1. Identify the target structure: which folder should exist and what goes in it.\n2. If the destination folder does not exist, run Create Folder (set its parent if needed) and capture the new folder ID.\n3. For each file to relocate, run Move File with the destination folder ID. Use Copy File instead when the original must stay in place.\n4. Optionally run Update File to rename files to a consistent convention.\n\n## Output\nA summary of what was created and moved: destination folder link, count of files relocated, and any renames applied.', + }, + { + name: 'share-file-with-people', + description: + 'Grant access to a Google Drive file for users, groups, a domain, or anyone with the link.', + content: + '# Share a File\n\nGrant access to a Drive file with the right permission level.\n\n## Steps\n1. Obtain the file ID (select it or run Search Files).\n2. Decide the share target: a specific user/group email, an entire domain, or anyone with the link.\n3. Choose the permission level: Viewer (reader), Commenter, or Editor (writer).\n4. Run the Share File operation with the target and role. For user/group shares, optionally include a notification message.\n\n## Output\nConfirm who now has access and at what level, plus the file link. Avoid `anyone` unless explicitly requested.', + }, + { + name: 'read-file-content', + description: + 'Extract the text content of a Google Drive file, exporting Workspace files to a usable format.', + content: + '# Read File Content\n\nPull the text out of a Drive file for downstream use.\n\n## Steps\n1. Obtain the file ID.\n2. Run the Get File Content operation. For Google Docs/Sheets/Slides, set Export Format (Auto picks the best, or choose Plain Text / PDF / DOCX explicitly).\n3. For non-Workspace files (PDF, TXT), the content is returned directly.\n4. Use the returned text for summarization, extraction, or indexing.\n\n## Output\nReturn the extracted content (or a summary of it if large), noting the file name and the export format used.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_forms.ts b/apps/sim/blocks/blocks/google_forms.ts index 8fc38934013..59e57c500b1 100644 --- a/apps/sim/blocks/blocks/google_forms.ts +++ b/apps/sim/blocks/blocks/google_forms.ts @@ -543,4 +543,25 @@ export const GoogleFormsBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'collect-form-responses', + description: 'Retrieve and structure responses from a Google Form for analysis or routing.', + content: + '# Collect Form Responses\n\nPull submissions from a Google Form.\n\n## Steps\n1. Select the form (or pass its form ID).\n2. Run the Get Responses operation; set Page Size to cover the expected volume. Leave Response ID empty to fetch all, or set it to fetch one specific submission.\n3. To map answers to questions, run Get Form once and use the item titles to label each answer.\n4. Normalize each response into clean rows keyed by question.\n\n## Output\nA structured list of responses with respondent answers labeled by question. Include the total count and the time range covered.', + }, + { + name: 'analyze-survey-results', + description: + 'Read Google Form responses and summarize trends, sentiment, and notable findings.', + content: + '# Analyze Survey Results\n\nTurn raw form responses into insight.\n\n## Steps\n1. Run Get Form to learn the questions and their types (choice, scale, text).\n2. Run Get Responses to pull all submissions.\n3. For choice/scale questions, compute distributions and averages. For free-text, cluster into themes and gauge sentiment.\n4. Surface the strongest signals and any outliers or recurring complaints.\n\n## Output\nA digest: response count, per-question breakdown (top choices, averages), 3-5 key themes from free text, and notable verbatim quotes. Keep numbers accurate to the data.', + }, + { + name: 'create-form', + description: 'Create a new Google Form and add questions via batch update.', + content: + '# Create a Form\n\nBuild a new Google Form with questions.\n\n## Steps\n1. Run Create Form with the form title (and optional document title). Capture the returned form ID.\n2. Build a Batch Update requests array to add questions. Use `createItem` with `choiceQuestion` (RADIO/CHECKBOX/DROP_DOWN), `textQuestion`, or `scaleQuestion`, each at a `location.index`.\n3. Run Batch Update on the form ID with that requests array.\n4. If the form should accept submissions, run Set Publish Settings with Published on.\n\n## Output\nConfirm the form was created, list the questions added, and return the responder URL and form ID.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_groups.ts b/apps/sim/blocks/blocks/google_groups.ts index 25f59a9402e..752ed242702 100644 --- a/apps/sim/blocks/blocks/google_groups.ts +++ b/apps/sim/blocks/blocks/google_groups.ts @@ -530,4 +530,31 @@ export const GoogleGroupsBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'add-member-to-group', + description: + 'Add a user to a Google Workspace group with a chosen role and confirm membership.', + content: + '# Add a Member to a Group\n\nGrant someone membership in a Workspace group.\n\n## Steps\n1. Identify the group email or ID and the member email.\n2. Run Check Membership first to see if the user is already a member; skip the add if so.\n3. Run Add Member with the member email and the desired role (MEMBER, MANAGER, or OWNER; default MEMBER).\n4. Optionally run Check Membership again to confirm the add succeeded.\n\n## Output\nConfirm the user was added (or already present), the role granted, and the group. Note if the operation requires admin privileges that were missing.', + }, + { + name: 'audit-group-membership', + description: 'List the members and roles of a Google Group for access review or compliance.', + content: + '# Audit Group Membership\n\nProduce a membership roster for a group.\n\n## Steps\n1. Identify the group email or ID.\n2. Run List Members with a Max Results value; optionally filter by roles (OWNER, MANAGER, MEMBER).\n3. Page through results using the next page token until all members are collected.\n4. Separate owners/managers from regular members and flag any external-domain addresses.\n\n## Output\nA roster grouped by role: owners, managers, members. Include total counts and a list of any external members for review.', + }, + { + name: 'create-group', + description: 'Create a new Google Workspace group with an email, name, and description.', + content: + '# Create a Group\n\nStand up a new Workspace group.\n\n## Steps\n1. Decide the group email address, display name, and a clear description of its purpose.\n2. Run List Groups (filter by the intended email/name) to confirm it does not already exist.\n3. Run Create Group with the email, name, and description.\n4. Optionally run Add Member to seed initial owners/managers.\n\n## Output\nConfirm the created group with its email, name, and description. List any initial members added. Note that this requires Workspace admin access.', + }, + { + name: 'remove-member-from-group', + description: 'Remove a user from a Google Group, useful for offboarding and access cleanup.', + content: + "# Remove a Member from a Group\n\nRevoke a user's group membership.\n\n## Steps\n1. Identify the group email/ID and the member email or ID.\n2. Run Check Membership to confirm the user is actually a member.\n3. If present, run Remove Member with the group and member keys.\n4. For offboarding across many groups, run List Groups filtered by `memberKey:` first to find every group the user belongs to, then remove from each.\n\n## Output\nConfirm the removal per group, and for offboarding list every group the user was removed from. Note any failures for manual follow-up.", + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_maps.ts b/apps/sim/blocks/blocks/google_maps.ts index 46bae8152fa..f3cc6ffaffd 100644 --- a/apps/sim/blocks/blocks/google_maps.ts +++ b/apps/sim/blocks/blocks/google_maps.ts @@ -712,4 +712,32 @@ export const GoogleMapsBlockMeta = { alsoIntegrations: ['hunter', 'hubspot'], }, ], + skills: [ + { + name: 'geocode-address', + description: + 'Convert an address into latitude/longitude coordinates with a normalized formatted address.', + content: + '# Geocode an Address\n\nTurn a street address into coordinates.\n\n## Steps\n1. Take the address string from the request.\n2. Run the Geocode Address operation; optionally set a Region Bias (country code) to disambiguate.\n3. Read the returned lat, lng, formatted address, place ID, and location type.\n4. If multiple candidates are likely, note the accuracy/location type so the requester can confirm.\n\n## Output\nReturn the formatted address, latitude, longitude, and place ID. To go the other way (coordinates to address), use Reverse Geocode instead.', + }, + { + name: 'get-directions', + description: + 'Compute a route between two locations with distance, duration, and turn-by-turn steps.', + content: + '# Get Directions\n\nRoute between an origin and a destination.\n\n## Steps\n1. Capture origin and destination (addresses or `lat,lng`).\n2. Choose Travel Mode (driving, walking, bicycling, transit) and optionally features to Avoid (tolls, highways, ferries).\n3. Add Waypoints (pipe-separated) for intermediate stops if requested, and pick Units (metric/imperial).\n4. Run the Get Directions operation.\n\n## Output\nReturn total distance and duration (as text and numeric), start/end addresses, and a concise turn-by-turn step list. Mention the travel mode used.', + }, + { + name: 'find-nearby-places', + description: 'Search for places matching a query near a location and return ranked results.', + content: + '# Find Nearby Places\n\nDiscover places (restaurants, hotels, etc.) near a spot.\n\n## Steps\n1. Build the Search Query (e.g., "coffee near Times Square") and set a Location Bias (`lat,lng`) and Radius if known.\n2. Optionally constrain by Place Type (restaurant, hotel, gas_station, etc.).\n3. Run the Search Places operation.\n4. For a chosen result, run Place Details with its Place ID to get rating, hours, phone, and website.\n\n## Output\nA ranked list of places: name, address, rating and number of ratings, open-now status, and place ID. Include phone/website for the top pick when details were fetched.', + }, + { + name: 'calculate-travel-distances', + description: 'Compute distances and travel times from one origin to many destinations.', + content: + '# Calculate Travel Distances\n\nGet a distance matrix from an origin to multiple destinations.\n\n## Steps\n1. Set the Origin and provide Destinations as a pipe-separated list (e.g., "New York, NY|Boston, MA").\n2. Choose Travel Mode and Units; optionally set features to Avoid.\n3. Run the Distance Matrix operation.\n4. Read each row for distance and duration to each destination.\n\n## Output\nA table of destinations sorted by travel time or distance, each with distance text and duration text. Useful for picking the nearest option or planning routes.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_meet.ts b/apps/sim/blocks/blocks/google_meet.ts index 55b9940e4a4..1acb4407ed1 100644 --- a/apps/sim/blocks/blocks/google_meet.ts +++ b/apps/sim/blocks/blocks/google_meet.ts @@ -254,4 +254,25 @@ export const GoogleMeetBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'create-meeting-space', + description: 'Create a Google Meet space and return its join link and meeting code.', + content: + '# Create a Meeting Space\n\nSpin up a Google Meet space to share.\n\n## Steps\n1. Decide the Access Type: Open (anyone with link), Trusted (organization members), or Restricted (invited only).\n2. Optionally set Entry Point Access if the space should only be joinable from the creating app.\n3. Run the Create Space operation.\n4. Capture the meeting URI and meeting code from the response.\n\n## Output\nReturn the meeting link (meetingUri), the meeting code, the access type, and the space resource name so it can be referenced or shared.', + }, + { + name: 'summarize-meeting-attendance', + description: + 'Pull a Google Meet conference record and its participants to report who attended.', + content: + '# Summarize Meeting Attendance\n\nReport attendance for a finished meeting.\n\n## Steps\n1. If you only have the space, run List Conference Records (filter by `space.name = "spaces/..."`) to find the conference record name.\n2. Run Get Conference Record to read start time, end time, and duration.\n3. Run List Participants on that conference record name, paging through results.\n4. Build the attendee list and compute meeting duration.\n\n## Output\nAn attendance summary: meeting start/end and duration, total participant count, and the list of participants. Flag the meeting if no participants are recorded.', + }, + { + name: 'list-recent-conferences', + description: 'List recent Google Meet conference records for reporting or archival.', + content: + '# List Recent Conferences\n\nEnumerate past Meet conferences.\n\n## Steps\n1. Run List Conference Records with a Page Size; optionally apply a Filter (e.g., by space name or time).\n2. Page through using the next page token until you have the needed window.\n3. For each record capture the conference record name, associated space, start time, and end time.\n4. Optionally fetch participants per record (List Participants) when attendance is needed.\n\n## Output\nA list of conferences sorted by start time, each with space, start/end, and duration. Include the conference record name so any record can be drilled into.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_pagespeed.ts b/apps/sim/blocks/blocks/google_pagespeed.ts index 26923b307ae..48d7d04a893 100644 --- a/apps/sim/blocks/blocks/google_pagespeed.ts +++ b/apps/sim/blocks/blocks/google_pagespeed.ts @@ -150,4 +150,25 @@ export const GooglePagespeedBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'audit-page-performance', + description: + 'Run a PageSpeed Insights analysis on a URL and report scores and Core Web Vitals.', + content: + '# Audit Page Performance\n\nMeasure a page with PageSpeed Insights (Lighthouse).\n\n## Steps\n1. Take the page URL.\n2. Choose the Strategy: mobile (recommended for ranking) or desktop. Run once per strategy if both are needed.\n3. Optionally set Categories (performance, accessibility, best-practices, seo) and Locale.\n4. Run the analysis and read the category scores plus Core Web Vitals (LCP, FCP, CLS, TBT, Speed Index, TTI).\n\n## Output\nA report: per-category scores (0-100), Core Web Vitals with their display values, and the final URL analyzed. Call out any metric in the poor range and the strategy used.', + }, + { + name: 'compare-mobile-vs-desktop', + description: 'Analyze a page on both mobile and desktop and contrast the scores and vitals.', + content: + "# Compare Mobile vs Desktop\n\nContrast a page's performance across form factors.\n\n## Steps\n1. Run the analysis on the URL with Strategy = mobile.\n2. Run it again with Strategy = desktop.\n3. Line up the category scores and Core Web Vitals from each run.\n4. Identify the biggest gaps (typically LCP/TBT on mobile).\n\n## Output\nA side-by-side comparison table of mobile vs desktop scores and key vitals, plus a short note on where mobile lags and what likely causes it.", + }, + { + name: 'track-core-web-vitals', + description: 'Capture Core Web Vitals for one or more pages to feed a monitoring history.', + content: + '# Track Core Web Vitals\n\nCapture CWV metrics for trend tracking.\n\n## Steps\n1. For each target URL, run the analysis (usually Strategy = mobile) limiting Categories to performance for speed.\n2. Extract LCP, CLS, TBT, FCP, Speed Index, and TTI numeric values plus the performance score.\n3. Stamp each row with the URL and analysis timestamp.\n4. Compare against any prior baseline to detect regressions.\n\n## Output\nOne row per URL with the performance score and CWV numeric values, ready to append to a history table. Flag any metric that regressed beyond a threshold versus the baseline.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_sheets.ts b/apps/sim/blocks/blocks/google_sheets.ts index ed5678b5413..f61dc2d35a0 100644 --- a/apps/sim/blocks/blocks/google_sheets.ts +++ b/apps/sim/blocks/blocks/google_sheets.ts @@ -1176,6 +1176,32 @@ export const GoogleSheetsBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'read-sheet-data', + description: 'Read rows from a Google Sheet, optionally filtering by a column value.', + content: + '# Read Sheet Data\n\nPull data out of a spreadsheet tab.\n\n## Steps\n1. Select the spreadsheet and the Sheet (tab) to read.\n2. Optionally set a Cell Range (e.g., A1:D100); leave blank to read the used range.\n3. To narrow rows, set Filter Column (a header name), Filter Value, and Match Type (contains, exact, gt, etc.).\n4. Run the Read Data operation and treat the first row as headers if present.\n\n## Output\nReturn the rows (as a 2D array or labeled objects keyed by header), the range read, and a filter summary if a filter was applied. Note the row count.', + }, + { + name: 'append-rows-to-sheet', + description: 'Add new rows to the end of a Google Sheet without overwriting existing data.', + content: + '# Append Rows to a Sheet\n\nAdd records to the bottom of a tab.\n\n## Steps\n1. Select the spreadsheet and Sheet (tab).\n2. Build the Values as a JSON array of arrays (each inner array is a row) or array of objects keyed by column.\n3. Set Insert Data Option to Insert Rows so existing data is not overwritten.\n4. Choose Value Input Option: User Entered (parses formulas/dates) or Raw.\n5. Run the Append Data operation.\n\n## Output\nConfirm the append: updated range, rows added, and the table range. Ensure column order matches the sheet headers.', + }, + { + name: 'update-cells', + description: 'Write or update values in a specific range of a Google Sheet.', + content: + '# Update Cells\n\nWrite values into a targeted range.\n\n## Steps\n1. Select the spreadsheet and Sheet (tab) and set the Cell Range to write (e.g., B2:D2).\n2. Build the Values JSON so its dimensions match the range.\n3. Pick Value Input Option: User Entered to evaluate formulas, or Raw to store literal text.\n4. Run the Update Data operation (use Write Data to set a fresh block).\n\n## Output\nConfirm updated range and the count of updated cells/rows/columns. If writing formulas, confirm User Entered was used so they evaluate.', + }, + { + name: 'create-spreadsheet', + description: 'Create a new Google Sheets spreadsheet with named tabs and return its link.', + content: + '# Create a Spreadsheet\n\nStand up a new spreadsheet.\n\n## Steps\n1. Set the Spreadsheet Title.\n2. Optionally provide Sheet Names as a comma-separated list (e.g., "Data, Summary").\n3. Run the Create Spreadsheet operation and capture the spreadsheet ID and URL.\n4. Follow up with Write or Append operations to populate the tabs.\n\n## Output\nReturn the new spreadsheet title, ID, URL, and the list of sheets created. Hand back the ID so subsequent steps can write to it.', + }, + ], } as const satisfies BlockMeta export const GoogleSheetsV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/google_slides.ts b/apps/sim/blocks/blocks/google_slides.ts index 803c4cf2de7..a431591827f 100644 --- a/apps/sim/blocks/blocks/google_slides.ts +++ b/apps/sim/blocks/blocks/google_slides.ts @@ -3567,6 +3567,36 @@ export const GoogleSlidesBlockMeta = { alsoIntegrations: ['salesforce', 'gmail'], }, ], + skills: [ + { + name: 'generate-deck-from-template', + description: + 'Copy a Google Slides template and replace placeholder text and images with data to produce a finished deck.', + content: + '# Generate Deck From Template\n\nProduce a finished presentation by copying a template deck and filling in dynamic values.\n\n## Steps\n1. Create a copy of the template presentation, or create a new presentation, and capture its presentationId.\n2. For each placeholder token (e.g. {{company}}, {{date}}, {{metric}}), call replace all text to substitute the real value across every slide.\n3. Replace placeholder images by adding images to the relevant slides, sizing and positioning them on the page.\n4. Add or duplicate slides for repeating sections (one per item) so the deck length matches the data.\n5. Read the presentation back to confirm every placeholder was resolved.\n\n## Output\nReturn the presentationId and the shareable link. Note any placeholders that had no matching data so they can be reviewed.', + }, + { + name: 'build-metrics-slide', + description: + 'Add a slide with a table and shapes that summarizes KPIs or metrics into a Google Slides deck.', + content: + '# Build Metrics Slide\n\nInsert a clean, data-driven metrics slide into an existing presentation.\n\n## Steps\n1. Add a new slide to the target presentation and capture the new slide objectId.\n2. Create a table on the slide sized to the number of metrics (rows) and columns needed.\n3. Insert text into each cell with the metric name, current value, and change vs prior period.\n4. Optionally create shape callouts for headline numbers and apply text and paragraph styles for emphasis.\n5. Get a thumbnail to verify layout and readability.\n\n## Output\nReturn the slide objectId and a thumbnail link. Summarize which metrics were added.', + }, + { + name: 'extract-deck-content', + description: + 'Read a Google Slides presentation and extract all slide text into a structured outline.', + content: + '# Extract Deck Content\n\nPull the full text of a presentation into a structured outline for summarization or repurposing.\n\n## Steps\n1. Read the presentation by ID to get all slides and page elements.\n2. For each slide, collect title text, body text, table cell text, and speaker notes if present.\n3. Preserve slide order and group text under each slide number.\n4. Skip purely decorative elements with no text.\n\n## Output\nReturn a numbered outline (one section per slide) with the extracted text. Useful as input for a summary, recap email, or knowledge base entry.', + }, + { + name: 'rebrand-deck', + description: + 'Roll out a brand or naming change across an entire deck by swapping text and logo images everywhere.', + content: + '# Rebrand Deck\n\nApply a consistent brand or naming change across every slide in one pass.\n\n## Steps\n1. Read the presentation by ID to confirm which terms and logo placeholders appear.\n2. For each old-to-new term (product name, tagline, company name), call replace all text so it updates across every slide at once.\n3. Replace the old logo by calling replace all shapes with image, or replace image on each logo element, with the new asset URL.\n4. Optionally update shape or page properties to match new brand colors.\n5. Read the presentation back to confirm no stale terms or logos remain.\n\n## Output\nReturn the presentationId and a list of the terms and images that were replaced, flagging any old references that still appear.', + }, + ], } as const satisfies BlockMeta export const GoogleSlidesV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/google_tasks.ts b/apps/sim/blocks/blocks/google_tasks.ts index 6a871eb1ad0..80d8a9b335f 100644 --- a/apps/sim/blocks/blocks/google_tasks.ts +++ b/apps/sim/blocks/blocks/google_tasks.ts @@ -354,4 +354,26 @@ export const GoogleTasksBlockMeta = { alsoIntegrations: ['google_calendar'], }, ], + skills: [ + { + name: 'capture-action-items', + description: + 'Turn a list of action items into Google Tasks with titles, notes, and due dates in the right task list.', + content: + '# Capture Action Items\n\nConvert extracted action items into well-formed Google Tasks.\n\n## Steps\n1. List the available task lists and pick the target list (default to the primary list if none specified).\n2. For each action item, create a task with a concise title, detailed notes for context, and a due date if one was given.\n3. Avoid duplicates by skipping items whose title already exists in the list.\n\n## Output\nReturn the created task IDs and titles, grouped by task list. Note any items skipped as duplicates.', + }, + { + name: 'list-due-and-overdue', + description: + 'List open Google Tasks that are due soon or overdue across a task list for a daily review.', + content: + '# List Due and Overdue Tasks\n\nSurface tasks that need attention for a daily or weekly review.\n\n## Steps\n1. List the task lists, or use a specified list.\n2. List tasks in the list, including completed status and due dates.\n3. Filter to incomplete tasks and split into Overdue (due before today) and Due Soon (due within the next few days).\n4. Sort each group by due date ascending.\n\n## Output\nReturn two sections, Overdue and Due Soon, each with task title, due date, and task ID. Useful for posting a standup or reminder digest.', + }, + { + name: 'complete-task-by-title', + description: 'Find a Google Task by its title and mark it completed.', + content: + '# Complete Task By Title\n\nMark a task done when given a title rather than an ID.\n\n## Steps\n1. List tasks in the relevant task list and match the requested title (case-insensitive, allow partial match).\n2. If multiple match, prefer the incomplete one; if still ambiguous, return the candidates and ask for clarification.\n3. Update the matched task to set its status to completed.\n4. Confirm the update by reading the task back.\n\n## Output\nReturn the completed task title and ID, or the list of ambiguous candidates if no single match was found.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_translate.ts b/apps/sim/blocks/blocks/google_translate.ts index 23b7a44ae55..6dc24ab90cc 100644 --- a/apps/sim/blocks/blocks/google_translate.ts +++ b/apps/sim/blocks/blocks/google_translate.ts @@ -289,4 +289,26 @@ export const GoogleTranslateBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'translate-to-language', + description: + 'Translate a block of text into a target language using Google Cloud Translation.', + content: + '# Translate To Language\n\nTranslate text into a specified target language.\n\n## Steps\n1. Take the source text and the target language code (e.g. es, fr, ja).\n2. If the source language is unknown, detect it first; otherwise pass it explicitly for accuracy.\n3. Call translate text with the target language and capture the translated output.\n4. For long content, split into paragraph-sized chunks and translate each to preserve formatting.\n\n## Output\nReturn the translated text along with the detected or supplied source language and the target language. Preserve line breaks from the original.', + }, + { + name: 'detect-and-route-language', + description: 'Detect the language of incoming text and route or label it accordingly.', + content: + '# Detect and Route Language\n\nIdentify the language of a message so it can be routed, labeled, or translated.\n\n## Steps\n1. Call detect language on the input text and capture the language code and confidence.\n2. If confidence is low, fall back to detecting on a longer sample or flag as uncertain.\n3. Decide the route: if the detected language differs from the team language, translate it; otherwise pass through unchanged.\n\n## Output\nReturn the detected language code, confidence, and a recommended action (translate or pass-through). Include the translated text when translation was performed.', + }, + { + name: 'localize-message-set', + description: + 'Translate one source message into several target languages for multilingual delivery.', + content: + '# Localize Message Set\n\nProduce localized versions of a single message for multiple audiences.\n\n## Steps\n1. Take the source text and the list of target language codes.\n2. For each target language, call translate text with the source language set explicitly for consistency.\n3. Keep placeholders, names, and URLs intact across all translations.\n\n## Output\nReturn a mapping of language code to translated text. Note any target language where translation appeared incomplete or unchanged.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/google_vault.ts b/apps/sim/blocks/blocks/google_vault.ts index f059fc55cec..464e7aff972 100644 --- a/apps/sim/blocks/blocks/google_vault.ts +++ b/apps/sim/blocks/blocks/google_vault.ts @@ -616,4 +616,27 @@ export const GoogleVaultBlockMeta = { tags: ['legal', 'enterprise'], }, ], + skills: [ + { + name: 'open-legal-hold', + description: + 'Create a Vault matter and place a legal hold on custodians for an investigation or litigation.', + content: + '# Open Legal Hold\n\nStand up a Vault matter and preserve data for the relevant custodians.\n\n## Steps\n1. Create a matter with a clear name and description tied to the case or investigation.\n2. List existing matters first to avoid creating a duplicate for the same case.\n3. Create a hold on the matter for the named custodians and the relevant service (mail, Drive, etc.).\n4. List holds on the matter to confirm the custodians were preserved.\n\n## Output\nReturn the matterId, the holdId, and the list of custodians now under hold. Note any custodian that could not be added.', + }, + { + name: 'run-discovery-export', + description: + 'Create a Vault export for a matter using a search query, then retrieve the export files.', + content: + '# Run Discovery Export\n\nProduce an export of matching data for eDiscovery or compliance review.\n\n## Steps\n1. Identify or create the matter for the export.\n2. Create an export with the search query, date range, and target accounts/org unit scoped as narrowly as possible.\n3. List exports on the matter and poll until the new export status is completed.\n4. Download the export files once the export is ready.\n\n## Output\nReturn the exportId, its status, and the downloaded file references. Summarize the query and scope used so the export is auditable.', + }, + { + name: 'audit-active-holds', + description: + 'List Vault matters and their holds to produce a custodian preservation status report.', + content: + '# Audit Active Holds\n\nGenerate a status report of which matters and custodians are currently preserved.\n\n## Steps\n1. List all matters and capture their IDs, names, and states.\n2. For each open matter, list its holds and the custodians and services covered.\n3. Flag matters with no holds and custodians that appear across multiple matters.\n\n## Output\nReturn a per-matter summary listing holds, services, and custodians, plus a flagged section for matters missing holds. Suitable for a monthly legal review.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/grafana.ts b/apps/sim/blocks/blocks/grafana.ts index 07acbfab6ae..fa126244835 100644 --- a/apps/sim/blocks/blocks/grafana.ts +++ b/apps/sim/blocks/blocks/grafana.ts @@ -987,4 +987,33 @@ export const GrafanaBlockMeta = { alsoIntegrations: ['linear', 'slack'], }, ], + skills: [ + { + name: 'annotate-deploy', + description: + 'Create a Grafana annotation marking a deploy or incident so it shows on dashboards.', + content: + '# Annotate Deploy\n\nMark a deploy, release, or incident on Grafana dashboards for correlation.\n\n## Steps\n1. Build the annotation text (e.g. version, PR link, who triggered it) and tags for filtering.\n2. Create an annotation with the event time, or a time range for incidents with a start and end.\n3. Optionally scope the annotation to a specific dashboard so it appears only there.\n4. List annotations for the window to confirm it was recorded.\n\n## Output\nReturn the annotation ID, time, and tags. Useful for correlating metric changes with deploys later.', + }, + { + name: 'review-firing-alerts', + description: + 'List Grafana alert rules and surface those currently firing with their contact points.', + content: + '# Review Firing Alerts\n\nProduce a snapshot of alerting health for an on-call handoff or incident triage.\n\n## Steps\n1. List alert rules and capture each rule name, condition, and current state.\n2. Get details on rules that are firing or in a pending state.\n3. List contact points so each firing rule can be mapped to who gets notified.\n4. Group findings by severity or folder.\n\n## Output\nReturn a list of firing and pending alerts with rule name, state, and notification target, plus a count of healthy rules. Suitable for an on-call digest.', + }, + { + name: 'audit-dashboards', + description: 'List Grafana dashboards and folders and report data sources each depends on.', + content: + '# Audit Dashboards\n\nInventory dashboards and the data sources they rely on.\n\n## Steps\n1. List folders and dashboards to build the full inventory.\n2. Get details for each dashboard of interest to read its panels and referenced data sources.\n3. List data sources and cross-reference to flag dashboards pointing at missing or deprecated sources.\n\n## Output\nReturn an inventory grouped by folder, each dashboard with its UID and the data sources it uses, plus a flagged list of dashboards with broken or unknown data source references.', + }, + { + name: 'provision-monitoring-folder', + description: + 'Create a Grafana folder and seed it with a starter dashboard for a new service or team.', + content: + '# Provision Monitoring Folder\n\nSet up an organized monitoring home for a new service or team.\n\n## Steps\n1. Create a folder with a descriptive title for the service or team.\n2. List data sources and pick the one the new dashboard should query.\n3. Create a dashboard inside the folder with starter panels for the key metrics.\n4. Get the dashboard back to confirm it was created in the right folder.\n\n## Output\nReturn the folder UID and the new dashboard UID and link. Note the data source the dashboard was wired to.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/grain.ts b/apps/sim/blocks/blocks/grain.ts index 14102e48fe3..99f25ff965c 100644 --- a/apps/sim/blocks/blocks/grain.ts +++ b/apps/sim/blocks/blocks/grain.ts @@ -534,4 +534,26 @@ export const GrainBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'summarize-recent-calls', + description: + 'Pull recent Grain recordings and produce a digest of key takeaways and action items per call.', + content: + '# Summarize Recent Calls\n\nTurn recent meeting recordings into a readable digest.\n\n## Steps\n1. List recordings, optionally filtered by a before/after datetime window, and paginate with the cursor if needed.\n2. For each recording, get the recording details and the transcript.\n3. From each transcript, extract the main topic, key takeaways, decisions, and action items with owners.\n4. Keep the per-call summary concise and consistent in structure.\n\n## Output\nReturn a digest with one section per call: title, date, participants, takeaways, and action items. Suitable for a daily or weekly recap.', + }, + { + name: 'extract-deal-signals', + description: + 'Scan Grain sales-call transcripts for buying signals, objections, and competitor mentions.', + content: + '# Extract Deal Signals\n\nMine sales transcripts for signals that move a deal forward.\n\n## Steps\n1. List recordings for the target time window, or filter by a view that holds sales calls.\n2. Get the transcript for each recording.\n3. Classify mentions into buying signals, objections/risks, competitor mentions, and next steps, capturing the verbatim quote and context.\n4. Apply a framework (e.g. MEDDIC or SPICED) if one is specified to tag each insight.\n\n## Output\nReturn a structured list of signals grouped by category, each with the quote, the call it came from, and a suggested follow-up. Useful for CRM notes or a deal review.', + }, + { + name: 'pull-transcript', + description: 'Retrieve a specific Grain recording and its full transcript by ID.', + content: + '# Pull Transcript\n\nFetch a single recording and its transcript for downstream use.\n\n## Steps\n1. If only a title or date is known, list recordings and match to find the recording ID.\n2. Get the recording details for metadata (title, participants, duration, date).\n3. Get the transcript for the recording.\n4. Clean the transcript into readable speaker-labeled turns.\n\n## Output\nReturn the recording metadata plus the formatted transcript. This is the building block for summaries, follow-up emails, or knowledge base ingestion.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/granola.ts b/apps/sim/blocks/blocks/granola.ts index 8c0614577a6..dc5f1c3ded6 100644 --- a/apps/sim/blocks/blocks/granola.ts +++ b/apps/sim/blocks/blocks/granola.ts @@ -249,4 +249,26 @@ export const GranolaBlockMeta = { tags: ['team', 'reporting'], }, ], + skills: [ + { + name: 'digest-meeting-notes', + description: + 'List recent Granola notes and produce a structured digest of takeaways and action items.', + content: + '# Digest Meeting Notes\n\nTurn recent Granola meeting notes into a concise digest.\n\n## Steps\n1. List notes, optionally limited to a recent time window.\n2. For each note, get the full note content.\n3. Extract the meeting title, key decisions, takeaways, and action items with owners and due dates if present.\n4. Keep each meeting summary short and uniformly structured.\n\n## Output\nReturn a digest with one section per meeting: title, date, decisions, takeaways, and action items. Suitable for a team recap or daily summary.', + }, + { + name: 'extract-action-items', + description: 'Read a Granola note and pull out a clean list of action items with owners.', + content: + '# Extract Action Items\n\nIsolate the follow-ups from a single meeting note.\n\n## Steps\n1. If only a title or date is known, list notes and match to find the note ID.\n2. Get the note content.\n3. Identify every action item, normalizing each into a clear task with an owner and due date when stated.\n4. Drop duplicates and merge near-identical items.\n\n## Output\nReturn a list of action items, each with the task, owner, and due date. Ready to push into a task manager or tracking table.', + }, + { + name: 'log-decisions', + description: + 'Scan Granola notes for decisions made and compile them into a dated decision log.', + content: + '# Log Decisions\n\nBuild an auditable record of decisions captured in meetings.\n\n## Steps\n1. List notes across the target window.\n2. Get each note and identify explicit decisions, the rationale, and who made them.\n3. Normalize each into a row with date, decision, owner, and context.\n\n## Output\nReturn a chronological decision log, each entry with date, decision, owner, and supporting context. Useful for writing to a decision-tracking table.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/greenhouse.ts b/apps/sim/blocks/blocks/greenhouse.ts index 1ee594986fc..aaead11dd15 100644 --- a/apps/sim/blocks/blocks/greenhouse.ts +++ b/apps/sim/blocks/blocks/greenhouse.ts @@ -495,4 +495,26 @@ export const GreenhouseBlockMeta = { alsoIntegrations: ['gmail', 'slack'], }, ], + skills: [ + { + name: 'build-pipeline-report', + description: + 'Summarize Greenhouse applications per job by stage to produce a hiring pipeline report.', + content: + '# Build Pipeline Report\n\nReport how candidates are progressing through each open job.\n\n## Steps\n1. List jobs and filter to open requisitions, capturing job IDs and titles.\n2. List job stages so application counts can be bucketed correctly.\n3. List applications, optionally filtered by status, and group them by job and current stage.\n4. Compute counts per stage and flag jobs with no recent movement.\n\n## Output\nReturn a per-job breakdown showing candidate counts by stage, total active candidates, and a flagged list of stalled requisitions. Suitable for a weekly recruiting standup.', + }, + { + name: 'assemble-candidate-brief', + description: + 'Pull a Greenhouse candidate and their application details into a one-page interviewer brief.', + content: + '# Assemble Candidate Brief\n\nCompile everything an interviewer needs about a candidate.\n\n## Steps\n1. Find the candidate by listing candidates and matching name, or use a known candidate ID.\n2. Get the candidate to retrieve profile details and attachments.\n3. Get the application to read the job applied for, current stage, and source.\n4. Get the job for the role context and requirements.\n\n## Output\nReturn a one-page brief: candidate summary, role and current stage, key background points, and any notes. Ready to email or DM to the interviewer before the slot.', + }, + { + name: 'audit-open-roles', + description: 'List open Greenhouse jobs with their departments, offices, and hiring teams.', + content: + '# Audit Open Roles\n\nInventory active requisitions and who owns them.\n\n## Steps\n1. List jobs and filter to open status.\n2. List departments and offices to resolve the names referenced on each job.\n3. List users to map hiring team members and recruiters to each role.\n4. Assemble each job with its department, office, and owning team.\n\n## Output\nReturn an inventory of open roles, each with title, department, office, and hiring team. Flag any role missing a recruiter or hiring manager.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/greptile.ts b/apps/sim/blocks/blocks/greptile.ts index 3d360414c48..208f43eba7d 100644 --- a/apps/sim/blocks/blocks/greptile.ts +++ b/apps/sim/blocks/blocks/greptile.ts @@ -231,4 +231,27 @@ export const GreptileBlockMeta = { alsoIntegrations: ['github'], }, ], + skills: [ + { + name: 'answer-codebase-question', + description: + 'Ask Greptile a natural-language question about an indexed repository and return a cited answer.', + content: + '# Answer Codebase Question\n\nGet an accurate, source-cited answer about how a codebase works.\n\n## Steps\n1. Confirm the repository is indexed by checking its index status; if not ready, index it first and wait.\n2. Query Greptile with the natural-language question (e.g. how authentication flows, where payments are processed).\n3. Capture the answer along with the file and function references it cites.\n4. If the answer is vague, refine the question with more specifics and re-query.\n\n## Output\nReturn the answer plus a list of cited files and symbols. Useful for onboarding, debugging, and understanding unfamiliar code.', + }, + { + name: 'review-pull-request', + description: + 'Use Greptile to assess how a PR diff interacts with the rest of the repo and draft review notes.', + content: + '# Review Pull Request\n\nProduce a codebase-aware review of a set of changes.\n\n## Steps\n1. Ensure the repository is indexed (check status, index if needed).\n2. Query Greptile describing the changed files and ask how they interact with the rest of the codebase, what might break, and what edge cases to test.\n3. Collect the impact analysis and the cited files affected beyond the diff.\n4. Organize findings into bugs/risks, style/consistency, and suggested tests.\n\n## Output\nReturn structured review notes grouped by severity, each with the cited file and a concrete suggestion. Ready to post as a PR comment.', + }, + { + name: 'index-and-verify-repo', + description: + 'Trigger Greptile indexing for a repository and poll until it is ready to query.', + content: + '# Index and Verify Repo\n\nMake a repository queryable in Greptile.\n\n## Steps\n1. Start indexing for the repository, specifying the remote, owner/repo, and branch.\n2. Poll the index status until it reports completed or fails.\n3. On failure, report the error and the branch/remote used so it can be corrected.\n4. On success, run a quick sanity query to confirm answers come back with citations.\n\n## Output\nReturn the final index status, the branch indexed, and the result of the sanity query. Confirms the repo is ready for codebase questions and reviews.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/hex.ts b/apps/sim/blocks/blocks/hex.ts index d770e897cf9..516b3bad272 100644 --- a/apps/sim/blocks/blocks/hex.ts +++ b/apps/sim/blocks/blocks/hex.ts @@ -520,4 +520,30 @@ export const HexBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'run-project-with-params', + description: 'Trigger a Hex project run with input parameters and poll until it completes.', + content: + '# Run Project With Params\n\nKick off a Hex project and wait for the result.\n\n## Steps\n1. If only a project name is known, list projects to resolve the project ID.\n2. Run the project, passing any input parameters the project expects.\n3. Capture the run ID and poll the run status until it reaches a terminal state (completed, errored, or killed).\n4. If it is still pending after a reasonable timeout, report the current status rather than blocking indefinitely.\n\n## Output\nReturn the run ID, final status, and any output or result link. On error, include the failure reason.', + }, + { + name: 'monitor-recent-runs', + description: 'List recent Hex project runs, check their statuses, and surface failures.', + content: + '# Monitor Recent Runs\n\nWatch project runs and flag the ones that failed.\n\n## Steps\n1. List project runs for the relevant project or projects.\n2. Get the run status for each recent run.\n3. Filter to runs that errored or were killed and capture the error detail.\n4. Group successes and failures with timestamps.\n\n## Output\nReturn a summary of recent runs with status and timing, plus a flagged failures section with run IDs, error messages, and links. Suitable for an hourly monitoring digest.', + }, + { + name: 'cancel-stuck-run', + description: 'Find a long-running or stuck Hex run and cancel it.', + content: + '# Cancel Stuck Run\n\nStop a run that is hung or no longer needed.\n\n## Steps\n1. List project runs and get the status of in-progress runs.\n2. Identify runs exceeding an expected duration or explicitly targeted for cancellation.\n3. Cancel the run by its run ID.\n4. Re-check the status to confirm cancellation took effect.\n\n## Output\nReturn the cancelled run ID and its confirmed final status. Note any run that could not be cancelled.', + }, + { + name: 'inventory-projects', + description: 'List Hex projects, collections, and data connections to map analytics assets.', + content: + '# Inventory Projects\n\nMap what projects and data sources exist in the workspace.\n\n## Steps\n1. List projects and capture IDs, names, and owners.\n2. List collections and get details to see how projects are grouped.\n3. List data connections to map which sources power the projects.\n4. Cross-reference projects to their collections and data connections.\n\n## Output\nReturn an inventory of projects grouped by collection, each annotated with its data connections. Useful for governance and cleanup.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/hubspot.ts b/apps/sim/blocks/blocks/hubspot.ts index 42b59b9e160..1c5e27c8341 100644 --- a/apps/sim/blocks/blocks/hubspot.ts +++ b/apps/sim/blocks/blocks/hubspot.ts @@ -1331,4 +1331,38 @@ export const HubSpotBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'upsert-contact', + description: + 'Find a HubSpot contact by email and update it, or create it if it does not exist.', + content: + '# Upsert Contact\n\nKeep a contact record current without creating duplicates.\n\n## Steps\n1. Search contacts by the email address to check if the person already exists.\n2. If a match is found, update the contact with the new property values.\n3. If no match exists, create a new contact with the email and known properties.\n4. Read the contact back to confirm the final property values.\n\n## Output\nReturn the contact ID and whether it was created or updated, along with the properties that were set.', + }, + { + name: 'create-deal-for-account', + description: 'Create a HubSpot deal and associate it with the right company and contact.', + content: + '# Create Deal For Account\n\nLog a new opportunity tied to the correct account.\n\n## Steps\n1. Search companies to resolve the company by name or domain; create it if missing.\n2. Search contacts to find the primary contact for the deal.\n3. Create the deal with name, amount, pipeline, and stage, associating it with the company and contact.\n4. Read the deal back to confirm associations and stage.\n\n## Output\nReturn the deal ID, its stage and amount, and the associated company and contact IDs.', + }, + { + name: 'triage-support-ticket', + description: + 'Classify a HubSpot ticket, set priority, and associate it with the correct company.', + content: + '# Triage Support Ticket\n\nRoute and prioritize an incoming support ticket.\n\n## Steps\n1. Get the ticket to read its subject and content.\n2. Classify topic and priority from the content.\n3. Update the ticket with the priority and any pipeline stage change.\n4. Search companies to find the requesting account and associate the ticket with it.\n\n## Output\nReturn the ticket ID, assigned priority and topic, and the associated company. Flag high-priority tickets for escalation.', + }, + { + name: 'summarize-open-deals', + description: 'Search HubSpot deals by stage and produce a pipeline summary with totals.', + content: + '# Summarize Open Deals\n\nReport on the active sales pipeline.\n\n## Steps\n1. Search deals filtered to open stages, paginating through all results.\n2. Group deals by pipeline stage and capture amount and close date.\n3. Sum amounts per stage and overall, and flag deals with a close date in the past.\n4. Identify the largest deals and any missing key properties.\n\n## Output\nReturn a per-stage breakdown with deal counts and total value, a grand total, and a flagged list of overdue or incomplete deals. Suitable for a sales pipeline review.', + }, + { + name: 'build-quote-from-deal', + description: 'Gather a HubSpot deal and its line items to assemble a quote summary.', + content: + '# Build Quote From Deal\n\nCompile the commercial details needed to quote a deal.\n\n## Steps\n1. Get the deal by ID for its name, amount, and stage.\n2. List line items and get details to capture product, quantity, and price for each.\n3. Get the associated quote if one exists, or summarize the line items into a draft quote.\n4. Total the line items and compare against the deal amount, flagging mismatches.\n\n## Output\nReturn the deal summary, an itemized line-item list with totals, and any existing quote reference. Flag discrepancies between the line-item total and the deal amount.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/huggingface.ts b/apps/sim/blocks/blocks/huggingface.ts index d3d4cedc103..6093ce1f6db 100644 --- a/apps/sim/blocks/blocks/huggingface.ts +++ b/apps/sim/blocks/blocks/huggingface.ts @@ -190,4 +190,26 @@ export const HuggingFaceBlockMeta = { tags: ['llm', 'engineering', 'analysis'], }, ], + skills: [ + { + name: 'run-chat-completion', + description: + 'Send a prompt to a Hugging Face chat model via the Inference API and return the response.', + content: + '# Run Chat Completion\n\nGenerate a completion from an open chat model.\n\n## Steps\n1. Choose the model (e.g. an instruct or chat-tuned model available via the Inference API).\n2. Build the messages with a clear system instruction and the user prompt.\n3. Call chat with the model and messages, setting temperature and max tokens appropriate to the task.\n4. Capture the assistant response and any token usage returned.\n\n## Output\nReturn the model output and the model name used. Note token usage when available for cost tracking.', + }, + { + name: 'extract-structured-data', + description: + 'Use a Hugging Face chat model to extract fields from unstructured text into a structured object.', + content: + '# Extract Structured Data\n\nPull named fields out of free text using an open model.\n\n## Steps\n1. Define the exact fields to extract and their types.\n2. Build a system message instructing the model to return only valid JSON matching the schema, with nulls for missing fields.\n3. Call chat with the source text as the user message and a low temperature for determinism.\n4. Parse the response and validate it against the expected fields; retry once with a stricter instruction if parsing fails.\n\n## Output\nReturn the parsed structured object. On repeated parse failure, return the raw model text and an error note.', + }, + { + name: 'compare-model-outputs', + description: 'Run the same prompt through two Hugging Face models and compare their outputs.', + content: + '# Compare Model Outputs\n\nEvaluate how two open models handle the same task.\n\n## Steps\n1. Define the shared prompt and the two model identifiers to compare.\n2. Call chat once per model with identical messages and generation settings.\n3. Capture each output along with latency and token usage.\n4. Score the outputs against the task criteria (accuracy, format, completeness).\n\n## Output\nReturn both responses side by side with their latency, token usage, and a brief quality comparison. Suitable for logging to an evaluation table.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/hunter.ts b/apps/sim/blocks/blocks/hunter.ts index da5705d2090..35f4c956764 100644 --- a/apps/sim/blocks/blocks/hunter.ts +++ b/apps/sim/blocks/blocks/hunter.ts @@ -480,4 +480,26 @@ export const HunterBlockMeta = { alsoIntegrations: ['apollo'], }, ], + skills: [ + { + name: 'find-decision-maker-emails', + description: + 'Find verified email addresses for key roles at a target company using domain search.', + content: + '# Find Decision-Maker Emails\n\nGiven a company domain, find verified professional email addresses for the people who matter.\n\n## Steps\n1. Run a domain search for the target domain (e.g. example.com).\n2. Filter results by department or seniority (executive, sales, IT) to surface decision-makers.\n3. For each candidate, capture the full name, role, email, and confidence score.\n4. Drop any result below your confidence threshold (e.g. < 80).\n\n## Output\nReturn a list of contacts with name, title, email, and confidence score, sorted by seniority. Note the total emails available on the domain so the user knows coverage.', + }, + { + name: 'verify-email-list', + description: + 'Verify a batch of email addresses and flag undeliverable or risky ones before sending.', + content: + '# Verify Email List\n\nClean a list of email addresses so a campaign only sends to deliverable inboxes.\n\n## Steps\n1. For each address, run the email verifier.\n2. Record the verification status (valid, invalid, accept-all, disposable, webmail) and the deliverability score.\n3. Bucket addresses into deliverable, risky, and undeliverable.\n\n## Output\nReturn the three buckets with counts, and a recommended clean list containing only deliverable addresses.', + }, + { + name: 'find-person-email', + description: 'Find the most likely email address for a named person at a specific company.', + content: + '# Find a Person Email\n\nGiven a first name, last name, and company domain, find that person email address.\n\n## Steps\n1. Run the email finder with the full name and domain.\n2. Capture the returned email, confidence score, and the sources Hunter used.\n3. If confidence is low, optionally run a domain search to confirm the pattern.\n\n## Output\nReturn the email, confidence score, and supporting sources. State clearly when no confident match was found.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/iam.ts b/apps/sim/blocks/blocks/iam.ts index 86bebd43d47..39f2b023021 100644 --- a/apps/sim/blocks/blocks/iam.ts +++ b/apps/sim/blocks/blocks/iam.ts @@ -738,4 +738,34 @@ export const IAMBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'audit-iam-permissions', + description: + 'List IAM users, roles, and their attached policies to produce an access audit. Use for security reviews and least-privilege checks.', + content: + '# Audit IAM Permissions\n\nReport who and what has access in IAM.\n\n## Steps\n1. List users and roles to establish the inventory.\n2. For each principal of interest, list attached user or role policies.\n3. Optionally simulate principal policy to confirm whether a principal can perform sensitive actions.\n4. Flag overly broad policies, unused principals, or access keys that should be rotated.\n\n## Output\nAn audit summary: principals and their attached policies, with risky or excessive grants called out. Do not expose secret values.', + }, + { + name: 'check-effective-permissions', + description: + 'Use IAM policy simulation to verify whether a user or role can perform specific actions on resources. Use for troubleshooting access and validating changes.', + content: + '# Check Effective Permissions\n\nDetermine whether a principal is actually allowed to do something.\n\n## Steps\n1. Identify the principal (user or role) and the actions and resource ARNs to test.\n2. Run simulate principal policy for those actions against the resources.\n3. Read the allowed or denied decision for each action, noting which statement governs it.\n4. If denied unexpectedly, inspect the attached policies to explain why.\n\n## Output\nA per-action allow/deny verdict with the governing policy, and a plain-language explanation of any denial.', + }, + { + name: 'provision-iam-principal', + description: + 'Create an IAM user or role, attach managed policies, and place users into groups to grant scoped access. Use for onboarding and standing up service roles.', + content: + '# Provision IAM Principal\n\nStand up a new IAM user or role with the right permissions.\n\n## Steps\n1. Decide whether to create a user (for a person or app) or a role (for a service or cross-account access).\n2. For a user, create the user, then add them to the relevant groups or attach the needed managed policy ARNs. For a role, create the role with a trust policy that names the allowed principal, then attach the policy ARNs.\n3. Prefer attaching existing managed policies over broad wildcards; grant only the actions required.\n4. Confirm the result by listing the attached user or role policies.\n\n## Output\nReport the created principal name and ARN and the policies now attached. Do not print any generated secret values.', + }, + { + name: 'rotate-access-keys', + description: + 'Create a fresh IAM access key for a user and delete the old one to complete a safe rotation. Use for scheduled key rotation and remediating aged keys.', + content: + '# Rotate Access Keys\n\nReplace a user’s access key following the two-step rotation pattern.\n\n## Steps\n1. Create a new access key for the target user so two keys exist briefly.\n2. Hand the new key to its consumer securely and let dependents switch over and verify they still work.\n3. Once the new key is confirmed in use, delete the old access key by its ID.\n4. Confirm only the intended key remains for the user.\n\n## Output\nReport the user, that a new key was issued, and the old key ID that was deleted. Never print the secret access key value — reference keys only by their access key ID.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/identity_center.ts b/apps/sim/blocks/blocks/identity_center.ts index beb8b587e6b..12868f58ce3 100644 --- a/apps/sim/blocks/blocks/identity_center.ts +++ b/apps/sim/blocks/blocks/identity_center.ts @@ -509,4 +509,27 @@ export const IdentityCenterBlockMeta = { tags: ['legal', 'enterprise'], }, ], + skills: [ + { + name: 'grant-temporary-access', + description: + 'Assign a permission set to a user or group on an AWS account through Identity Center and confirm the assignment completes. Use for just-in-time elevated access.', + content: + '# Grant Temporary Access\n\nProvision elevated access via an Identity Center account assignment.\n\n## Steps\n1. Resolve the Identity Center instance, target account, and permission set.\n2. Resolve the principal — get the user or group to confirm the correct ID and type.\n3. Create the account assignment for that principal, permission set, and account.\n4. Poll check assignment status until it reports SUCCEEDED.\n\n## Output\nConfirm the principal, account, permission set, and final assignment status. If it failed, surface the failure reason.', + }, + { + name: 'revoke-access', + description: + 'Remove a permission set assignment from a user or group in Identity Center and confirm deletion. Use to wind down temporary or expired access.', + content: + '# Revoke Access\n\nRemove an account assignment to revoke access.\n\n## Steps\n1. List account assignments to confirm the principal currently holds the permission set on the account.\n2. Delete the account assignment for that principal, permission set, and account.\n3. Poll check assignment deletion status until it reports SUCCEEDED.\n4. Re-list assignments to verify the grant is gone.\n\n## Output\nConfirm what was revoked and the final deletion status. Note if the assignment did not exist.', + }, + { + name: 'access-audit-report', + description: + 'Enumerate permission sets, group memberships, and account assignments in Identity Center to produce an access report. Use for compliance and periodic reviews.', + content: + '# Access Audit Report\n\nReport who has access to what across accounts.\n\n## Steps\n1. List instances and accounts to scope the report.\n2. List permission sets and, per account, list account assignments.\n3. Resolve users and groups behind each assignment with get user and get group.\n4. Compile assignments grouped by account and permission set.\n\n## Output\nAn access report: per account, which principals hold which permission sets, with anything unexpected flagged for review.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/incidentio.ts b/apps/sim/blocks/blocks/incidentio.ts index 766bf1b8b41..8737a74795c 100644 --- a/apps/sim/blocks/blocks/incidentio.ts +++ b/apps/sim/blocks/blocks/incidentio.ts @@ -1297,4 +1297,33 @@ export const IncidentioBlockMeta = { tags: ['devops', 'monitoring'], }, ], + skills: [ + { + name: 'declare-incident-from-alert', + description: + 'Open an incident.io incident from an inbound alert with the right severity and summary.', + content: + '# Declare an Incident From an Alert\n\nTurn a monitoring alert into a structured incident.io incident so responders can act fast.\n\n## Steps\n1. Look up available severities and pick the one matching the alert impact.\n2. Create the incident with a clear name, a summary describing impact and affected service, and the chosen severity.\n3. Set incident type and any required custom fields from the alert payload.\n4. Capture the new incident reference and link.\n\n## Output\nReturn the incident ID, reference, severity, and link. Confirm the responder channel was created so the team can jump in.', + }, + { + name: 'post-incident-update', + description: + 'Update an active incident with current status and a progress note for stakeholders.', + content: + '# Post an Incident Update\n\nKeep stakeholders informed by moving an active incident through its lifecycle.\n\n## Steps\n1. Look up the incident by reference or ID to confirm its current status.\n2. List valid incident statuses and choose the next one (investigating, identified, monitoring, resolved).\n3. Update the incident with the new status and a concise progress message.\n\n## Output\nReturn the incident reference, the new status, and a one-line summary of what changed and when.', + }, + { + name: 'on-call-handoff-report', + description: 'Summarize who is on call and recent open incidents for an on-call handoff.', + content: + '# On-Call Handoff Report\n\nBuild a clean handoff so the next on-call engineer knows the state of the world.\n\n## Steps\n1. List current schedules and active escalation paths to determine who is on call.\n2. List recent incidents and filter to those that are open or recently resolved.\n3. For each open incident, capture severity, status, and outstanding follow-ups.\n\n## Output\nReturn a handoff brief: who is on call now, open incidents with severity and status, and follow-ups that still need owners.', + }, + { + name: 'export-incident-followups', + description: + 'Pull follow-ups from recent incidents into an actionable list for post-incident review.', + content: + '# Export Incident Follow-Ups\n\nGather the action items that came out of recent incidents so none slip through.\n\n## Steps\n1. List incidents within the target time window.\n2. For each, list its follow-ups and capture title, owner, status, and linked incident.\n3. Group follow-ups by owner and by open vs completed.\n\n## Output\nReturn a table of follow-ups grouped by owner with status and source incident, highlighting overdue or unassigned items.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/infisical.ts b/apps/sim/blocks/blocks/infisical.ts index f1ce706557e..d03c1e27816 100644 --- a/apps/sim/blocks/blocks/infisical.ts +++ b/apps/sim/blocks/blocks/infisical.ts @@ -304,4 +304,26 @@ export const InfisicalBlockMeta = { alsoIntegrations: ['s3'], }, ], + skills: [ + { + name: 'fetch-secret-for-run', + description: + 'Retrieve a named secret from Infisical to use as a credential during a workflow run.', + content: + '# Fetch a Secret for a Run\n\nPull a single secret from Infisical so a downstream step can authenticate without hardcoding credentials.\n\n## Steps\n1. Identify the project, environment (e.g. dev, staging, prod), and secret path.\n2. Get the secret by name from that scope.\n3. Pass the value to the consuming step. Never echo the raw secret into logs or output.\n\n## Output\nConfirm the secret was retrieved (by name and environment) and that it was used. Do not print the secret value itself.', + }, + { + name: 'rotate-secret', + description: 'Update an existing secret in Infisical with a new value as part of a rotation.', + content: + '# Rotate a Secret\n\nReplace a secret value in Infisical during a credential rotation.\n\n## Steps\n1. Confirm the project, environment, and secret name to rotate.\n2. Update the secret with the new value at that path.\n3. Optionally read the secret back by name to confirm it now exists (without printing the value).\n\n## Output\nConfirm the secret name and environment that was rotated and the timestamp. Never expose the old or new value.', + }, + { + name: 'audit-environment-secrets', + description: + 'List the secret names present in an Infisical environment for an inventory or audit.', + content: + '# Audit Environment Secrets\n\nProduce an inventory of which secrets exist in an Infisical environment without exposing their values.\n\n## Steps\n1. Choose the project, environment, and path to audit.\n2. List secrets at that scope and collect only the keys and metadata.\n3. Compare against the expected set if one is provided and flag missing or unexpected keys.\n\n## Output\nReturn a list of secret names (keys only) with count, and any discrepancies versus the expected set. Never include secret values.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/instantly.ts b/apps/sim/blocks/blocks/instantly.ts index 30e40ff1837..2e75f80f46a 100644 --- a/apps/sim/blocks/blocks/instantly.ts +++ b/apps/sim/blocks/blocks/instantly.ts @@ -1325,4 +1325,32 @@ export const InstantlyBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'add-leads-to-campaign', + description: + 'Push a batch of prospects into an Instantly campaign as new leads with personalization fields.', + content: + '# Add Leads to a Campaign\n\nLoad a set of prospects into an Instantly cold-email campaign so they enter the sending sequence.\n\n## Steps\n1. List campaigns and identify the target campaign by name.\n2. For each prospect, create a lead with email, first name, last name, company, and any custom personalization variables.\n3. Attach each lead to the chosen campaign.\n\n## Output\nReturn how many leads were added, the campaign name, and any rows skipped for missing or invalid emails.', + }, + { + name: 'launch-outreach-campaign', + description: 'Create a cold-email campaign, load a lead list, and activate it for sending.', + content: + '# Launch an Outreach Campaign\n\nStand up a new Instantly campaign end to end and start sending.\n\n## Steps\n1. Create a lead list and add the target prospects to it.\n2. Create the campaign with its sending sequence and schedule.\n3. Add the leads to the campaign.\n4. Activate the campaign so sending begins.\n\n## Output\nReturn the campaign name, lead count, and activation status. Confirm the campaign is live.', + }, + { + name: 'triage-campaign-replies', + description: 'Review recent campaign email replies and update each lead interest status.', + content: + '# Triage Campaign Replies\n\nProcess inbound replies on a campaign and route each lead by interest.\n\n## Steps\n1. List recent emails for the campaign and identify replies from leads.\n2. Read each reply and classify intent (interested, not interested, out of office, wrong person).\n3. Update the matching lead interest status to reflect the classification.\n4. For interested leads, draft a reply to the email.\n\n## Output\nReturn a summary of replies by category, the leads marked interested, and any drafted responses for review.', + }, + { + name: 'campaign-performance-snapshot', + description: + 'Summarize active campaigns and their leads into a quick outreach performance snapshot.', + content: + '# Campaign Performance Snapshot\n\nGive a quick read on how outreach is going across campaigns.\n\n## Steps\n1. List campaigns and note which are active.\n2. For each active campaign, list leads and tally counts by interest status.\n3. Pull recent emails to gauge reply volume.\n\n## Output\nReturn a per-campaign snapshot: total leads, breakdown by interest status, and reply activity, highlighting the top-performing campaign.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/intercom.ts b/apps/sim/blocks/blocks/intercom.ts index 13124540316..67906026320 100644 --- a/apps/sim/blocks/blocks/intercom.ts +++ b/apps/sim/blocks/blocks/intercom.ts @@ -1810,6 +1810,36 @@ export const IntercomBlockMeta = { alsoIntegrations: ['zendesk'], }, ], + skills: [ + { + name: 'triage-open-conversations', + description: + 'Review open Intercom conversations and assign each to the right teammate with a priority.', + content: + '# Triage Open Conversations\n\nKeep the inbox moving by routing open Intercom conversations to the right people.\n\n## Steps\n1. List or search open conversations.\n2. Read each conversation to understand the customer issue and urgency.\n3. List admins to find the right owner, then assign the conversation.\n4. Tag the conversation by topic (billing, bug, onboarding) and add an internal note summarizing next steps.\n\n## Output\nReturn each conversation with its assigned owner, applied tags, and a one-line summary. Flag anything that looks urgent.', + }, + { + name: 'reply-and-resolve', + description: + 'Draft a reply to a customer conversation, send it, and close the conversation when resolved.', + content: + '# Reply and Resolve\n\nRespond to a customer in Intercom and wrap up the conversation.\n\n## Steps\n1. Get the conversation and read the full thread for context.\n2. Draft a helpful, on-brand reply that addresses the customer question.\n3. Reply to the conversation with the message.\n4. If the issue is fully handled, close the conversation; otherwise snooze it until a follow-up time.\n\n## Output\nReturn the reply that was sent and the final conversation state (closed or snoozed).', + }, + { + name: 'enrich-contact-record', + description: + 'Create or update an Intercom contact and link it to its company with current details.', + content: + '# Enrich a Contact Record\n\nKeep contact data accurate by creating or updating an Intercom contact.\n\n## Steps\n1. Search contacts by email to see if the person already exists.\n2. Create the contact if missing, or update the existing record with name, role, and attributes.\n3. Find or create the company and attach the contact to it.\n4. Tag the contact to reflect segment or lifecycle stage.\n\n## Output\nReturn the contact ID, the linked company, and the fields that were created or changed.', + }, + { + name: 'open-support-ticket', + description: + 'Create an Intercom ticket from a conversation and capture the key issue details.', + content: + '# Open a Support Ticket\n\nEscalate a customer issue into a tracked Intercom ticket.\n\n## Steps\n1. Get the source conversation and summarize the issue, impact, and steps to reproduce.\n2. Create a ticket with a clear title, the summary, and the linked contact.\n3. Add a note to the conversation referencing the new ticket so context is preserved.\n\n## Output\nReturn the ticket ID, title, linked contact, and the conversation it came from.', + }, + ], } as const satisfies BlockMeta export const IntercomV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/jina.ts b/apps/sim/blocks/blocks/jina.ts index d8a941c97fe..37514f0653e 100644 --- a/apps/sim/blocks/blocks/jina.ts +++ b/apps/sim/blocks/blocks/jina.ts @@ -265,4 +265,24 @@ export const JinaBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'extract-article-content', + description: 'Read a URL and return clean, LLM-ready text stripped of navigation and ads.', + content: + '# Extract Article Content\n\nTurn a messy web page into clean, readable text an agent can reason over.\n\n## Steps\n1. Take the target URL.\n2. Read the URL to get the parsed main content as markdown or text.\n3. Strip boilerplate (nav, footers, ads) if any remains and keep the core article body.\n\n## Output\nReturn the page title and the cleaned content, plus the source URL. Note if the page could not be fully extracted.', + }, + { + name: 'research-topic-from-web', + description: 'Search the web for a topic and summarize the top results into a briefing.', + content: + '# Research a Topic From the Web\n\nGather and condense current web information on a topic.\n\n## Steps\n1. Run a web search for the topic with a focused query.\n2. Take the top results and read the most relevant URLs for full content.\n3. Synthesize the findings, noting points of agreement and disagreement across sources.\n\n## Output\nReturn a short briefing with key findings, each backed by the source URL it came from.', + }, + { + name: 'summarize-url', + description: 'Fetch a single URL and produce a concise summary with the main takeaways.', + content: + '# Summarize a URL\n\nGive a quick, faithful summary of a single web page.\n\n## Steps\n1. Read the URL to extract its main content.\n2. Identify the core thesis and the most important supporting points.\n3. Condense into a short summary without adding outside information.\n\n## Output\nReturn the page title, a 3-5 bullet summary of the key takeaways, and the source URL.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/jira.ts b/apps/sim/blocks/blocks/jira.ts index 42982e30dbc..cf6c498cd43 100644 --- a/apps/sim/blocks/blocks/jira.ts +++ b/apps/sim/blocks/blocks/jira.ts @@ -1410,4 +1410,31 @@ export const JiraBlockMeta = { alsoIntegrations: ['confluence'], }, ], + skills: [ + { + name: 'create-bug-from-report', + description: + 'Turn a bug report into a well-structured Jira issue with steps, severity, and labels.', + content: + '# Create a Bug From a Report\n\nConvert a raw bug report into a clean, actionable Jira issue.\n\n## Steps\n1. Parse the report for summary, steps to reproduce, expected vs actual behavior, and environment.\n2. Create an issue in the target project with type Bug, a clear summary, and a structured description.\n3. Set priority based on impact and add relevant labels or components.\n4. Optionally assign it to the right owner.\n\n## Output\nReturn the issue key, URL, priority, and assignee. Confirm the description includes reproduction steps.', + }, + { + name: 'triage-open-issues', + description: 'Search open issues with JQL and propose assignees, priorities, and labels.', + content: + '# Triage Open Issues\n\nBring order to a backlog of unassigned or stale issues.\n\n## Steps\n1. Search issues using JQL (e.g. unassigned and recently created in a project).\n2. Read each issue to understand scope and urgency.\n3. For each, propose a priority, suggested assignee, and labels; apply updates where confident.\n4. Add a short triage comment explaining the decision.\n\n## Output\nReturn a table of issues with proposed/applied priority, assignee, and labels, flagging any that need a human decision.', + }, + { + name: 'transition-and-comment', + description: 'Move an issue to a new workflow status and post a progress comment.', + content: + '# Transition and Comment\n\nAdvance a Jira issue through its workflow with a clear note.\n\n## Steps\n1. Retrieve the issue and read its current status.\n2. Get available transitions and choose the correct next status (e.g. In Progress, In Review, Done).\n3. Transition the issue to that status.\n4. Add a comment summarizing what changed and any next steps.\n\n## Output\nReturn the issue key, the new status, and the comment that was posted.', + }, + { + name: 'sprint-status-digest', + description: 'Summarize issues in a project or sprint grouped by status and assignee.', + content: + '# Sprint Status Digest\n\nProduce a quick read on where work stands.\n\n## Steps\n1. Search issues with JQL scoped to the project or current sprint.\n2. Group results by status and by assignee.\n3. Identify blocked issues, overdue items, and anything unassigned.\n\n## Output\nReturn a digest: counts by status, work per assignee, and a callout list of blocked or at-risk issues with their keys.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/jira_service_management.ts b/apps/sim/blocks/blocks/jira_service_management.ts index 0d96d5a5d07..c1d17299163 100644 --- a/apps/sim/blocks/blocks/jira_service_management.ts +++ b/apps/sim/blocks/blocks/jira_service_management.ts @@ -1334,4 +1334,25 @@ export const JiraServiceManagementBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'raise-service-request', + description: + 'Create a customer request on the right service desk with the correct request type.', + content: + '# Raise a Service Request\n\nLog an inbound customer request into the correct Jira Service Management queue.\n\n## Steps\n1. Get service desks and identify the right one for the request.\n2. Get request types for that service desk and choose the matching type.\n3. Create the request with a clear summary, description, and any required request-type fields.\n4. Capture the request key and reporter.\n\n## Output\nReturn the request key, the service desk and request type used, and the reporter. Confirm required fields were filled.', + }, + { + name: 'respond-and-update-request', + description: 'Add a public reply to a customer request and move it to the right status.', + content: + '# Respond and Update a Request\n\nReply to a customer on their request and advance it.\n\n## Steps\n1. Get the request and read its history and current status.\n2. Add a comment with the response (public to the customer).\n3. Get available transitions and move the request to the appropriate status.\n\n## Output\nReturn the request key, the comment added, and the new status.', + }, + { + name: 'sla-breach-watch', + description: 'Scan open requests on a queue and flag ones at risk of breaching SLA.', + content: + '# SLA Breach Watch\n\nSurface requests that are about to miss their SLA so the team can act.\n\n## Steps\n1. Get the service desk and its queues, then get requests in the target queue.\n2. For each request, get its SLA information and time remaining.\n3. Flag requests that are breached or close to breaching their target.\n\n## Output\nReturn a prioritized list of at-risk requests with key, summary, SLA metric, and time remaining, worst first.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/kalshi.ts b/apps/sim/blocks/blocks/kalshi.ts index 00c44734fc5..38d1f3e50a1 100644 --- a/apps/sim/blocks/blocks/kalshi.ts +++ b/apps/sim/blocks/blocks/kalshi.ts @@ -915,6 +915,28 @@ export const KalshiBlockMeta = { tags: ['finance', 'analysis'], }, ], + skills: [ + { + name: 'market-odds-snapshot', + description: + 'Pull current prices and odds for a Kalshi event and summarize the implied probabilities.', + content: + '# Market Odds Snapshot\n\nReport the current state of a Kalshi prediction market.\n\n## Steps\n1. Find the event by ticker or search recent events.\n2. Get the markets under that event and their current yes/no prices.\n3. Convert prices to implied probabilities and capture volume and open interest.\n\n## Output\nReturn each market with its current yes/no price, implied probability, and recent volume, plus a one-line read on where the market is leaning.', + }, + { + name: 'track-position-pnl', + description: + 'Report account balance, open positions, and unrealized profit or loss on Kalshi.', + content: + '# Track Position P&L\n\nGive a clear read on the current trading account state.\n\n## Steps\n1. Get the account balance.\n2. Get current positions and, for each, the market and entry exposure.\n3. Get current market prices to estimate unrealized P&L per position.\n\n## Output\nReturn balance, each open position with its market and estimated unrealized P&L, and a total exposure figure.', + }, + { + name: 'place-limit-order', + description: 'Place a limit order on a Kalshi market after confirming price and balance.', + content: + '# Place a Limit Order\n\nSubmit a limit order on a chosen Kalshi market with guardrails.\n\n## Steps\n1. Get the target market and confirm its current price and orderbook.\n2. Check the account balance to ensure the order is affordable.\n3. Create a limit order with the side (yes/no), price, and quantity.\n4. Confirm the order was accepted and capture its ID.\n\n## Output\nReturn the order ID, market, side, price, quantity, and status. State clearly if the order was rejected or only partially filled.', + }, + ], } as const satisfies BlockMeta export const KalshiV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/ketch.ts b/apps/sim/blocks/blocks/ketch.ts index ad1049b5767..e042a669b73 100644 --- a/apps/sim/blocks/blocks/ketch.ts +++ b/apps/sim/blocks/blocks/ketch.ts @@ -303,4 +303,31 @@ export const KetchBlockMeta = { tags: ['legal', 'reporting'], }, ], + skills: [ + { + name: 'check-user-consent', + description: 'Look up a user current consent state in Ketch before processing their data.', + content: + '# Check User Consent\n\nConfirm what a user has consented to before a workflow uses their data.\n\n## Steps\n1. Identify the user (by identity key) and the jurisdiction/policy scope.\n2. Get the user current consent for the relevant purposes (analytics, marketing, etc.).\n3. Determine which downstream actions are permitted based on the consent state.\n\n## Output\nReturn the consent state per purpose and a clear allow/deny decision for the intended data use. Stop the workflow if required consent is missing.', + }, + { + name: 'record-consent-update', + description: 'Set or update a user consent choices in Ketch from a preference change.', + content: + '# Record a Consent Update\n\nPersist a user updated consent choices to Ketch.\n\n## Steps\n1. Capture the user identity and the new consent choices per purpose.\n2. Set the consent for that user in the correct jurisdiction/policy scope.\n3. Read the consent back to confirm it was applied.\n\n## Output\nConfirm the user identity, the purposes updated, and the resulting consent state.', + }, + { + name: 'fulfill-data-subject-request', + description: 'Invoke a data subject right (access, delete) in Ketch and track the request.', + content: + '# Fulfill a Data Subject Request\n\nKick off a DSR (e.g. access or deletion) on behalf of a user.\n\n## Steps\n1. Capture the requester identity and the right being exercised (access, deletion, correction).\n2. Invoke the right in Ketch with the required identity and jurisdiction context.\n3. Capture the request reference for tracking.\n\n## Output\nReturn the request reference, the right invoked, and the requester identity so the request can be tracked to completion.', + }, + { + name: 'sync-subscription-preferences', + description: + 'Read a user subscription topics in Ketch and update them to honor an opt-in or opt-out.', + content: + '# Sync Subscription Preferences\n\nKeep a user communication preferences accurate in Ketch when they opt in or out of a channel or topic.\n\n## Steps\n1. Identify the user and get their current subscription topics and controls.\n2. Determine the requested change (e.g. opt out of the newsletter, set a global unsubscribe).\n3. Set the subscription topics and controls to the new state for that user.\n4. Read the subscriptions back to confirm the change applied.\n\n## Output\nReturn the topics and controls that changed and the resulting opt-in or opt-out state per channel. Confirm any global unsubscribe was honored.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/langsmith.ts b/apps/sim/blocks/blocks/langsmith.ts index b50851b3f70..984d861bbdf 100644 --- a/apps/sim/blocks/blocks/langsmith.ts +++ b/apps/sim/blocks/blocks/langsmith.ts @@ -365,4 +365,20 @@ export const LangsmithBlockMeta = { tags: ['engineering', 'monitoring'], }, ], + skills: [ + { + name: 'log-llm-run-to-langsmith', + description: + 'Send a single LLM or chain run to LangSmith with inputs, outputs, and timing for tracing.', + content: + '# Log an LLM Run to LangSmith\n\nForward one workflow step into LangSmith so it shows up in tracing and evals.\n\n## Steps\n1. Capture the run name, run type (llm, chain, tool), and the project to log into.\n2. Record the inputs (prompt or arguments) and the outputs the step produced.\n3. Include start and end times so latency is captured, plus any error if the step failed.\n4. Create the run in LangSmith.\n\n## Output\nConfirm the run was logged with its name, type, and project, and surface the run ID for follow-up inspection.', + }, + { + name: 'batch-export-runs', + description: + 'Send a batch of completed workflow runs to LangSmith in one call for observability.', + content: + '# Batch Export Runs\n\nShip multiple completed runs to LangSmith at once instead of one by one.\n\n## Steps\n1. Collect the runs to export, each with name, type, inputs, outputs, and timing.\n2. Assign a shared project so the runs land together.\n3. Submit them as a single batch.\n\n## Output\nReturn how many runs were exported, the project they landed in, and any runs that failed validation.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/launchdarkly.ts b/apps/sim/blocks/blocks/launchdarkly.ts index ea0be6b8352..b9a28c376b0 100644 --- a/apps/sim/blocks/blocks/launchdarkly.ts +++ b/apps/sim/blocks/blocks/launchdarkly.ts @@ -415,4 +415,26 @@ export const LaunchDarklyBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'toggle-flag-in-environment', + description: 'Turn a LaunchDarkly feature flag on or off in a specific environment safely.', + content: + '# Toggle a Flag in an Environment\n\nFlip a feature flag for a target environment with a confirmation step.\n\n## Steps\n1. Identify the project and the environment (e.g. production, staging) and the flag key.\n2. Get the current flag status to confirm its present state.\n3. Toggle the flag to the desired on/off state in that environment.\n4. Re-check the status to confirm the change took effect.\n\n## Output\nReturn the flag key, environment, previous state, and new state. Confirm the toggle was applied.', + }, + { + name: 'create-feature-flag', + description: + 'Create a new LaunchDarkly feature flag in a project with a clear key and description.', + content: + '# Create a Feature Flag\n\nStand up a new feature flag for an upcoming release.\n\n## Steps\n1. Choose the project and define a descriptive flag key and human-readable name.\n2. Set a description explaining what the flag controls and whether it is temporary or permanent.\n3. Create the flag, defaulting it to off so it can be rolled out deliberately.\n\n## Output\nReturn the flag key, name, project, and initial state. Confirm the flag starts disabled.', + }, + { + name: 'flag-rollout-audit', + description: + 'Report on a flag state across environments and recent changes from the audit log.', + content: + '# Flag Rollout Audit\n\nUnderstand where a flag stands and who changed it recently.\n\n## Steps\n1. Get the flag and list environments for the project.\n2. For each environment, capture the flag on/off state and targeting.\n3. Pull the audit log entries for the flag to see recent changes and who made them.\n\n## Output\nReturn a per-environment state table for the flag and a short changelog of recent modifications with actor and timestamp.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/lemlist.ts b/apps/sim/blocks/blocks/lemlist.ts index 09d94e515fe..4dd8554307f 100644 --- a/apps/sim/blocks/blocks/lemlist.ts +++ b/apps/sim/blocks/blocks/lemlist.ts @@ -308,4 +308,27 @@ export const LemlistBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'triage-campaign-replies', + description: + 'Pull recent Lemlist reply activity, classify each reply by intent, and surface the ones that need a human.', + content: + '# Triage Campaign Replies\n\nMonitor Lemlist replies and route them by intent so reps act on hot leads fast.\n\n## Steps\n1. Get Activities filtered to the Email Replied type, optionally scoped to a campaign ID, with a sensible limit.\n2. For each reply, look up the lead with Get Lead to attach name, company, and job title.\n3. Classify the reply intent: interested, not interested, out-of-office, unsubscribe, or question.\n4. For interested or question replies, build a short summary with the lead name, campaign, and the reply text.\n\n## Output\nA list of replies grouped by intent. For each interested or question reply, include lead name, company, campaign, a one-line summary, and the raw reply text so a rep can respond.', + }, + { + name: 'analyze-campaign-performance', + description: + 'Compute open, click, reply, and bounce rates per campaign and per step from Lemlist activities and flag weak steps.', + content: + '# Analyze Campaign Performance\n\nTurn raw Lemlist activity into step-level metrics and concrete fixes.\n\n## Steps\n1. Get Activities for the target campaign with a high limit, paging with offset until all activity is collected.\n2. Tally events by type: emails sent, opened, clicked, replied, and bounced.\n3. Compute open rate, click rate, reply rate, and bounce rate overall and per sequence step.\n4. Flag steps where reply rate is low, bounce rate is high, or drop-off between steps is steep.\n\n## Output\nA per-campaign and per-step metrics table plus a short list of recommendations, such as rewriting a low-reply subject line or pausing a high-bounce step.', + }, + { + name: 'qualify-and-reply-to-lead', + description: + 'Look up a Lemlist lead and send a personalized reply through their Lemlist mailbox.', + content: + '# Qualify and Reply to Lead\n\nRespond to an inbound lead with a tailored message sent from your Lemlist inbox.\n\n## Steps\n1. Get Lead by email or lead ID to pull first name, company, and job title.\n2. Draft a concise, personalized reply that references the lead context and includes a clear next step or booking link.\n3. Send Email through Lemlist using the sender user ID, sender email, mailbox ID, contact ID, lead ID, subject, and the drafted HTML message body.\n\n## Output\nConfirmation that the email was sent, the lead identity it went to, and the message body that was used.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/linear.ts b/apps/sim/blocks/blocks/linear.ts index 6f3658d3f7d..5920b2d02be 100644 --- a/apps/sim/blocks/blocks/linear.ts +++ b/apps/sim/blocks/blocks/linear.ts @@ -2685,4 +2685,34 @@ export const LinearBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'create-triaged-issue', + description: + 'Create a Linear issue in the right team with a clear title, description, priority, and labels.', + content: + '# Create Triaged Issue\n\nTurn a request or bug report into a well-formed Linear issue.\n\n## Steps\n1. If the team is unknown, List Teams and pick the team that owns the area.\n2. Write a concise title and a description with context, steps to reproduce, and acceptance criteria.\n3. Create Issue with the team ID, title, description, and a priority that matches severity.\n4. Optionally Add Label to Issue for type and area labels using IDs from List Labels.\n\n## Output\nThe created issue ID, its identifier and URL, and the team, priority, and labels applied.', + }, + { + name: 'triage-new-issue', + description: + 'Read a Linear issue, apply type and priority labels, set assignee and state, and comment a triage summary.', + content: + '# Triage New Issue\n\nTriage an incoming Linear issue so it lands in the right place with the right metadata.\n\n## Steps\n1. Get Issue to read the title and description.\n2. Determine the issue type, priority, and owning area from the content.\n3. Add Label to Issue for type and priority, and Update Issue to set the assignee, state, and priority.\n4. Create Comment with a short triage summary explaining the classification and next step.\n\n## Output\nThe issue identifier, the labels added, the assignee and state set, and the triage comment posted.', + }, + { + name: 'summarize-active-cycle', + description: + 'Pull completed and open issues in the active cycle and produce a sprint progress digest.', + content: + '# Summarize Active Cycle\n\nProduce a sprint review digest from the current Linear cycle.\n\n## Steps\n1. Get Active Cycle for the team to find the current cycle.\n2. Read Issues or Search Issues scoped to that cycle, separating completed from still-open issues.\n3. Compute counts, completion percentage, and call out blocked or at-risk issues by priority.\n4. Summarize progress, blockers, and what is likely to slip.\n\n## Output\nA digest with completed vs open counts, completion percentage, a list of blockers, and a short narrative of cycle health.', + }, + { + name: 'post-project-update', + description: + 'Assess a Linear project and post a project update with a health status and progress summary.', + content: + '# Post Project Update\n\nWrite a stakeholder-ready project update in Linear.\n\n## Steps\n1. Get Project to read its current state, target date, and lead.\n2. Read Issues for the project to gauge progress against the milestone or target date.\n3. Decide a health status of on track, at risk, or off track based on remaining work and timeline.\n4. Create Project Update with the chosen health and a concise body covering progress, risks, and next steps.\n\n## Output\nConfirmation of the posted update, the health status chosen, and the update body.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/linkedin.ts b/apps/sim/blocks/blocks/linkedin.ts index 4bab0b2a3f7..a3e21ea5f04 100644 --- a/apps/sim/blocks/blocks/linkedin.ts +++ b/apps/sim/blocks/blocks/linkedin.ts @@ -191,4 +191,27 @@ export const LinkedInBlockMeta = { tags: ['marketing', 'content', 'automation'], }, ], + skills: [ + { + name: 'publish-linkedin-post', + description: + 'Draft and share a post to your LinkedIn feed with a hook, value, and a clear call-to-action.', + content: + '# Publish LinkedIn Post\n\nWrite and publish an engagement-optimized post to your LinkedIn feed.\n\n## Steps\n1. Take the source idea, article, or update to post about.\n2. Draft post text with a strong first-line hook, two to three lines of value or insight, and a clear call-to-action, kept within LinkedIn length limits.\n3. Share Post with the drafted text and a visibility of PUBLIC or CONNECTIONS.\n\n## Output\nConfirmation the post was shared, the created post ID, and the final post text used.', + }, + { + name: 'repurpose-content-to-post', + description: + 'Turn a blog post, release note, or announcement into a punchy LinkedIn post and share it.', + content: + '# Repurpose Content to Post\n\nRepurpose long-form content into a native LinkedIn post.\n\n## Steps\n1. Read the source content and pull out the single most compelling insight or takeaway.\n2. Rewrite it as a standalone LinkedIn post with a hook, a concise body, and a call-to-action or link.\n3. Share Post with PUBLIC visibility.\n\n## Output\nThe published post ID and the post text, plus a note of the source it was derived from.', + }, + { + name: 'get-my-profile', + description: + 'Fetch your LinkedIn profile information for use in downstream personalization or logging.', + content: + '# Get My Profile\n\nRetrieve your authenticated LinkedIn profile.\n\n## Steps\n1. Run Get Profile to fetch the connected account profile.\n2. Extract the fields you need, such as name and identifiers, for personalization or record-keeping.\n\n## Output\nThe profile JSON and a short summary of the key fields available.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/linkup.ts b/apps/sim/blocks/blocks/linkup.ts index 03de92cdcf0..19b26c5cb46 100644 --- a/apps/sim/blocks/blocks/linkup.ts +++ b/apps/sim/blocks/blocks/linkup.ts @@ -225,4 +225,27 @@ export const LinkupBlockMeta = { tags: ['sales', 'research'], }, ], + skills: [ + { + name: 'answer-with-citations', + description: + 'Answer a question with Linkup using a sourced answer and surface the supporting source URLs.', + content: + '# Answer with Citations\n\nGround an answer in live web facts using Linkup.\n\n## Steps\n1. Set the search query to the user question, phrased clearly.\n2. Choose the Answer output type and include sources so the response carries verifiable URLs.\n3. Use Deep search depth for complex or multi-part questions, otherwise Standard.\n4. Present the answer and attach the source links.\n\n## Output\nA concise answer followed by a list of the source URLs that support it.', + }, + { + name: 'gather-research-sources', + description: + 'Run a Linkup search and return a ranked list of relevant sources with snippets for a topic.', + content: + '# Gather Research Sources\n\nCollect authoritative sources on a topic for downstream research.\n\n## Steps\n1. Set the search query to the research topic, narrowing with key terms.\n2. Choose the Search output type to get raw results with sources.\n3. Optionally restrict or exclude domains, and set a from and to date to bound recency.\n4. Review the returned sources and order them by relevance.\n\n## Output\nA ranked list of sources with titles, URLs, and snippets, ready to feed a summarizer or knowledge base.', + }, + { + name: 'monitor-topic-mentions', + description: + 'Search Linkup for recent mentions of a topic, competitor, or brand within a date window.', + content: + '# Monitor Topic Mentions\n\nTrack fresh mentions of a topic or competitor.\n\n## Steps\n1. Set the search query to the brand, competitor, or topic to monitor.\n2. Use the Search output type and set the from date to the start of the window you want to cover.\n3. Optionally restrict to news or specific domains.\n4. Filter the results to genuinely new or relevant mentions and summarize each.\n\n## Output\nA list of new mentions with source URL, date, and a one-line summary of each.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/linq.ts b/apps/sim/blocks/blocks/linq.ts index c0dcb5f4be6..170da5b420c 100644 --- a/apps/sim/blocks/blocks/linq.ts +++ b/apps/sim/blocks/blocks/linq.ts @@ -896,4 +896,27 @@ export const LinqBlockMeta = { tags: ['messaging', 'automation'], }, ], + skills: [ + { + name: 'send-personalized-message', + description: + 'Start a Linq chat and send a personalized iMessage, SMS, or RCS message to a recipient.', + content: + '# Send Personalized Message\n\nReach a person on iMessage, SMS, or RCS through Linq.\n\n## Steps\n1. Create Chat with your sending number in From and the recipient handle in To.\n2. Draft a friendly, concise message body tailored to the recipient.\n3. Send Message to the chat with the message text, optionally setting a preferred service or media URL.\n4. Optionally Check iMessage or Check RCS first to pick the best service for the recipient.\n\n## Output\nThe chat ID, the message ID, the delivery service used, and the delivery status.', + }, + { + name: 'respond-to-unread-messages', + description: + 'List recent Linq chats and messages, draft a reply for each unread conversation, and send it.', + content: + '# Respond to Unread Messages\n\nClear an inbox by replying to recent unread Linq conversations.\n\n## Steps\n1. List Chats to find active conversations, then List Messages per chat to find unread inbound messages.\n2. For each conversation needing a reply, read the recent thread for context.\n3. Draft a relevant reply.\n4. Send Message to that chat ID with the drafted text.\n\n## Output\nFor each handled chat: the chat ID, the reply sent, and the delivery status.', + }, + { + name: 'dispatch-alert-notifications', + description: + 'Send an RCS or SMS notification to one or more recipients from a list of alerts.', + content: + '# Dispatch Alert Notifications\n\nFan out notifications to recipients through Linq.\n\n## Steps\n1. Take the list of recipients and the alert content to send.\n2. For each recipient, Create Chat from your sending number to their handle.\n3. Format a clear notification message and Send Message, setting the preferred service to RCS or SMS as needed.\n4. Use an idempotency key per message so retries do not double-send.\n\n## Output\nA per-recipient list of chat IDs, message IDs, and delivery statuses.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/loops.ts b/apps/sim/blocks/blocks/loops.ts index a63ab116103..6685e09db34 100644 --- a/apps/sim/blocks/blocks/loops.ts +++ b/apps/sim/blocks/blocks/loops.ts @@ -604,4 +604,33 @@ export const LoopsBlockMeta = { tags: ['marketing', 'automation', 'communication'], }, ], + skills: [ + { + name: 'onboard-new-contact', + description: 'Create a Loops contact on signup and send a transactional welcome email.', + content: + '# Onboard New Contact\n\nAdd a new signup to Loops and welcome them.\n\n## Steps\n1. Create Contact with the email, first and last name, and any source or user group, plus custom properties like plan.\n2. Send Transactional Email using the welcome template ID, passing the contact data as data variables.\n3. Optionally Send Event with a signup event name so any onboarding automation begins.\n\n## Output\nThe created contact ID, confirmation the welcome email was sent, and any event fired.', + }, + { + name: 'send-product-event', + description: + 'Fire a Loops event for a user with structured properties to trigger lifecycle automations.', + content: + '# Send Product Event\n\nDrive Loops automations from real product behavior.\n\n## Steps\n1. Identify the contact by email or user ID and the event that occurred.\n2. Build event properties as a JSON object with the relevant values, such as plan and amount.\n3. Send Event with the event name, the contact identifier, and the properties.\n4. Optionally update mailing list subscriptions in the same call.\n\n## Output\nConfirmation the event was sent, the contact it was attributed to, and the properties included.', + }, + { + name: 'enrich-contact-properties', + description: + 'Find a Loops contact and update it with enriched custom properties and user group.', + content: + '# Enrich Contact Properties\n\nKeep Loops contact data complete and current.\n\n## Steps\n1. Find Contact by email or user ID to read existing fields and spot gaps.\n2. Gather the missing or stale values from your source or research.\n3. Update Contact with the new custom properties, user group, and any name fields.\n\n## Output\nThe updated contact ID and a summary of the properties that were set or changed.', + }, + { + name: 'send-transactional-email', + description: + 'Send a Loops transactional email from a template with personalized data variables.', + content: + '# Send Transactional Email\n\nDeliver a templated transactional email through Loops.\n\n## Steps\n1. Confirm the transactional email template ID to use.\n2. Build the data variables JSON to match the variable names in the template, such as name and a confirmation URL.\n3. Send Transactional Email with the recipient email, template ID, and data variables, attaching files if needed.\n\n## Output\nConfirmation of send success and the template ID and recipient used.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/luma.ts b/apps/sim/blocks/blocks/luma.ts index 9946f019551..b59a80174d9 100644 --- a/apps/sim/blocks/blocks/luma.ts +++ b/apps/sim/blocks/blocks/luma.ts @@ -468,4 +468,33 @@ export const LumaBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'create-event', + description: + 'Create a Luma event with a name, start time, timezone, description, and visibility.', + content: + '# Create Event\n\nSpin up a new Luma event ready to share.\n\n## Steps\n1. Decide the event name, start time as an ISO 8601 timestamp, and the IANA timezone.\n2. Create Event with those fields plus an optional end time or duration, a Markdown description, and a meeting URL for virtual events.\n3. Set visibility to public, members-only, or private as appropriate.\n\n## Output\nThe created event ID and URL, with its start time, timezone, and visibility.', + }, + { + name: 'add-guests-to-event', + description: 'Add a batch of guests to a Luma event from a list of emails and names.', + content: + '# Add Guests to Event\n\nBulk-register guests on a Luma event.\n\n## Steps\n1. Confirm the target event ID.\n2. Build the guests JSON array, one object per guest with an email and optional name or first and last name.\n3. Add Guests with the event ID and the guest array.\n\n## Output\nConfirmation of how many guests were added and the event ID they were added to.', + }, + { + name: 'export-guest-list', + description: + 'Pull a Luma event guest list, optionally filtered by approval status, for follow-up or enrichment.', + content: + '# Export Guest List\n\nRetrieve registrants for an event.\n\n## Steps\n1. Get Guests for the event ID, optionally filtering by approval status such as approved or waitlist.\n2. Page through results using the limit and pagination cursor until the full list is collected.\n3. Extract the fields you need, such as email, name, approval status, and registered or checked-in timestamps.\n\n## Output\nThe full guest list with key fields, ready to segment attendees from no-shows or feed into a CRM.', + }, + { + name: 'send-event-reminders', + description: + 'Pull the Luma guest list and prepare personalized reminders for upcoming registrants.', + content: + '# Send Event Reminders\n\nPrepare reminder content for an upcoming Luma event.\n\n## Steps\n1. Get Event to read the name, start time, timezone, and meeting or location details.\n2. Get Guests filtered to approved registrants, paging until complete.\n3. For each guest, draft a personalized reminder with the event time in their context and the join or location info.\n\n## Output\nA per-guest list of email addresses and drafted reminder messages, ready to hand to an email or messaging step.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/mailchimp.ts b/apps/sim/blocks/blocks/mailchimp.ts index 1dbe489fdec..9650d7676ef 100644 --- a/apps/sim/blocks/blocks/mailchimp.ts +++ b/apps/sim/blocks/blocks/mailchimp.ts @@ -1532,4 +1532,33 @@ export const MailchimpBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'sync-contact-to-audience', + description: 'Add or update a contact in a Mailchimp audience with merge fields and tags.', + content: + '# Sync Contact to Audience\n\nKeep a Mailchimp audience in sync with your source of truth.\n\n## Steps\n1. If the audience is unknown, Get Audiences to find the right list ID.\n2. Use Add or Update Member with the email, subscription status, and merge fields like first and last name.\n3. Apply segmentation with Add Member Tags for lifecycle stage or ICP tags.\n\n## Output\nThe member ID and status in the audience, plus the merge fields and tags applied.', + }, + { + name: 'create-and-send-campaign', + description: + 'Create a Mailchimp campaign, set its content, and send or schedule it to an audience.', + content: + '# Create and Send Campaign\n\nLaunch an email campaign to an audience or segment.\n\n## Steps\n1. Create Campaign targeting the audience or a saved segment, with the subject line and from details.\n2. Set Campaign Content with the HTML or a template ID.\n3. Send Campaign immediately, or Schedule Campaign for a future send time.\n\n## Output\nThe campaign ID, the audience or segment targeted, and whether it was sent or scheduled with the send time.', + }, + { + name: 'build-targeted-segment', + description: + 'Create a Mailchimp segment from conditions so a campaign can target a specific slice of an audience.', + content: + '# Build Targeted Segment\n\nDefine a reusable audience segment for targeting.\n\n## Steps\n1. Identify the audience and the conditions that define the segment, such as tags, merge field values, or activity.\n2. Create Segment on that audience with the conditions and a clear name.\n3. Optionally Get Segment Members to verify the segment matches the intended contacts.\n\n## Output\nThe segment ID and name, the conditions used, and the count of matching members.', + }, + { + name: 'report-campaign-performance', + description: + 'Pull Mailchimp campaign reports and summarize open, click, and bounce performance.', + content: + '# Report Campaign Performance\n\nTurn Mailchimp report data into a readable summary.\n\n## Steps\n1. Get Campaign Reports for the recent window, or Get Campaign Report for a specific campaign ID.\n2. Extract opens, clicks, bounces, and unsubscribes per campaign.\n3. Compute open rate, click rate, and bounce rate and flag campaigns that underperformed.\n\n## Output\nA per-campaign metrics summary with rates and a short list of underperformers worth revisiting.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/mailgun.ts b/apps/sim/blocks/blocks/mailgun.ts index 14013716e5e..24328492724 100644 --- a/apps/sim/blocks/blocks/mailgun.ts +++ b/apps/sim/blocks/blocks/mailgun.ts @@ -483,4 +483,33 @@ export const MailgunBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'send-transactional-email', + description: + 'Send a transactional email through a Mailgun sending domain to one or more recipients.', + content: + '# Send Transactional Email\n\nDeliver an email through Mailgun.\n\n## Steps\n1. Confirm the verified sending domain to use, listing domains first if unsure.\n2. Compose the message with from, to, subject, and an HTML or text body.\n3. Send Message with those fields, adding CC, BCC, or attachments as needed.\n\n## Output\nConfirmation of acceptance with the Mailgun message ID and the recipients it was queued to.', + }, + { + name: 'track-delivery-events', + description: + 'Pull Mailgun events filtered by type to see what was delivered, opened, clicked, or failed.', + content: + '# Track Delivery Events\n\nMonitor what happened to your Mailgun sends.\n\n## Steps\n1. List Messages or query events filtered by an event type such as delivered, failed, opened, or clicked.\n2. Group the events by recipient and by type to see delivery outcomes.\n3. Highlight failures and bounces that need attention.\n\n## Output\nA summary of event counts by type and a list of failed or bounced recipients.', + }, + { + name: 'sweep-bounces-and-complaints', + description: + 'Collect Mailgun failed and complained events and compile the offending addresses for suppression.', + content: + '# Sweep Bounces and Complaints\n\nKeep your list clean by capturing bad addresses.\n\n## Steps\n1. Query Mailgun events filtered to failed and complained types over the chosen window.\n2. Extract the recipient addresses and the reason for each.\n3. Compile a suppression list of addresses to stop mailing.\n\n## Output\nA list of bounced and complained addresses with reasons, ready to write to a suppression table.', + }, + { + name: 'add-member-to-list', + description: 'Create a Mailgun mailing list if needed and add a subscriber to it.', + content: + '# Add Member to List\n\nGrow a Mailgun mailing list.\n\n## Steps\n1. Get Mailing List to confirm the list exists, or Create Mailing List with the address and access level if it does not.\n2. Add List Member with the subscriber email and any name or variables.\n\n## Output\nConfirmation the member was added, the list address, and the member email.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/mem0.ts b/apps/sim/blocks/blocks/mem0.ts index 53f8dcb2781..21c22a1409f 100644 --- a/apps/sim/blocks/blocks/mem0.ts +++ b/apps/sim/blocks/blocks/mem0.ts @@ -343,4 +343,27 @@ export const Mem0BlockMeta = { tags: ['individual', 'automation', 'onboarding'], }, ], + skills: [ + { + name: 'remember-user-context', + description: + 'Store new facts and preferences for a user in Mem0 from the latest conversation.', + content: + '# Remember User Context\n\nPersist what you learned about a user so future sessions stay informed.\n\n## Steps\n1. Identify the user ID this memory belongs to.\n2. Build the messages array from the relevant conversation turns as role and content objects.\n3. Add Memories with the user ID and messages so Mem0 extracts and stores the durable facts.\n\n## Output\nConfirmation the memories were added for the user, with the IDs of the facts created.', + }, + { + name: 'recall-relevant-memories', + description: + "Search a user's Mem0 memories for the facts relevant to the current request before answering.", + content: + '# Recall Relevant Memories\n\nGround a response in what Mem0 already knows about the user.\n\n## Steps\n1. Identify the user ID.\n2. Phrase a search query that captures the current request or topic.\n3. Search Memories with the user ID and query.\n4. Use the returned memories as context when drafting the answer.\n\n## Output\nThe most relevant memories for the user and a note of how they should shape the response.', + }, + { + name: 'review-stored-memories', + description: + "Retrieve a user's stored Mem0 memories, optionally within a date range, to audit what is known.", + content: + "# Review Stored Memories\n\nInspect what Mem0 holds for a user.\n\n## Steps\n1. Identify the user ID.\n2. Get Memories for that user, optionally bounding by a start and end date or a specific memory ID.\n3. Page through results if there are many.\n4. Summarize the stored facts and flag anything stale or contradictory.\n\n## Output\nA readable list of the user's stored memories with a short summary and any items worth updating.", + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/microsoft_ad.ts b/apps/sim/blocks/blocks/microsoft_ad.ts index c303582f62f..167572aced5 100644 --- a/apps/sim/blocks/blocks/microsoft_ad.ts +++ b/apps/sim/blocks/blocks/microsoft_ad.ts @@ -466,4 +466,27 @@ export const MicrosoftAdBlockMeta = { alsoIntegrations: ['microsoft_teams'], }, ], + skills: [ + { + name: 'provision-new-user', + description: + 'Create a new Azure AD (Entra ID) user account and add it to the right groups. Use when onboarding an employee or contractor.', + content: + '# Provision New User\n\nCreate an Azure AD user and grant initial group access.\n\n## Steps\n1. Use Create User with the required fields: display name, mail nickname, user principal name (e.g. name@yourdomain.com), and an initial password. Set Account Enabled to Yes.\n2. Fill optional profile fields when available: first name, last name, job title, department, office location, and mobile phone.\n3. For each group the person should belong to, resolve the group with Get Group or List Groups, then call Add Group Member with the new user id.\n4. Confirm membership with List Group Members.\n\n## Output\nReturn the created user id, user principal name, and the list of groups they were added to. If a username collision or password-policy error occurs, report it clearly instead of retrying blindly.', + }, + { + name: 'offboard-user', + description: + 'Disable an Azure AD account and strip its group memberships when someone leaves. Use for secure offboarding.', + content: + '# Offboard User\n\nRevoke access for a departing user.\n\n## Steps\n1. Resolve the account with Get User by user principal name or id.\n2. Use Update User to set Account Enabled to No so the user can no longer sign in.\n3. Use List Group Members or the user record to enumerate the groups the user belongs to.\n4. For each group, call Remove Group Member with the user id.\n\n## Output\nReturn the disabled user id and the list of groups the user was removed from. Note any group where removal failed so it can be handled manually, and recommend writing the action to an audit record.', + }, + { + name: 'audit-group-membership', + description: + 'List the members of an Azure AD group for an access review. Use for periodic attestation of privileged or sensitive groups.', + content: + '# Audit Group Membership\n\nProduce a current membership snapshot for a group.\n\n## Steps\n1. Resolve the target group with Get Group or List Groups (filter or search by name).\n2. Call List Group Members for the group id, raising Max Results if the group is large.\n3. For each member, optionally call Get User to enrich with job title, department, and account-enabled status.\n\n## Output\nReturn a table of members with id, display name, email, department, and whether the account is enabled. Highlight disabled or stale accounts that still hold membership and should be reviewed for removal.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/microsoft_dataverse.ts b/apps/sim/blocks/blocks/microsoft_dataverse.ts index 0237acdc16a..6682f293d68 100644 --- a/apps/sim/blocks/blocks/microsoft_dataverse.ts +++ b/apps/sim/blocks/blocks/microsoft_dataverse.ts @@ -663,4 +663,31 @@ export const MicrosoftDataverseBlockMeta = { alsoIntegrations: ['microsoft_teams'], }, ], + skills: [ + { + name: 'upsert-record', + description: 'Create or update a record in a Dataverse table by its key without duplicating.', + content: + '# Upsert Record\n\nKeep a Dataverse table in sync from an external source without creating duplicates.\n\n## Steps\n1. Identify the target table and the key field that uniquely identifies the record.\n2. Map the incoming data to the table column names.\n3. Use Upsert Record so an existing match is updated and a new key creates a record.\n\n## Output\nThe record ID and whether it was created or updated, plus the fields written.', + }, + { + name: 'query-records', + description: 'List or query Dataverse records with filters and return the matching rows.', + content: + '# Query Records\n\nRetrieve a filtered set of rows from a Dataverse table.\n\n## Steps\n1. Choose the table to query.\n2. Use List Records with OData filters, selected columns, and ordering, or use a FetchXML Query for complex joins and aggregates.\n3. Page through results until the needed rows are collected.\n\n## Output\nThe matching records with the selected columns, ready for downstream processing.', + }, + { + name: 'relevance-search', + description: + 'Run a relevance search across Dataverse tables to find records matching a term.', + content: + '# Relevance Search\n\nFind records across Dataverse using full-text relevance search.\n\n## Steps\n1. Take the search term, such as a customer name or case keyword.\n2. Use Search with the term, choosing simple or Lucene query syntax and match-any or match-all behavior.\n3. Review the ranked matches and pick the relevant record.\n\n## Output\nA ranked list of matching records with their table and key fields.', + }, + { + name: 'bulk-write-records', + description: 'Create or update many Dataverse records in one batch operation.', + content: + '# Bulk Write Records\n\nWrite many Dataverse rows efficiently in a single call.\n\n## Steps\n1. Assemble the array of records, mapping each to the table column names.\n2. Use Create Multiple to insert new rows, or Update Multiple to change existing rows by ID.\n3. Verify the operation succeeded and capture any per-record errors.\n\n## Output\nThe count of records written, their IDs, and any rows that failed with their error.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/microsoft_excel.ts b/apps/sim/blocks/blocks/microsoft_excel.ts index 22ce69f5b4f..0a949a24789 100644 --- a/apps/sim/blocks/blocks/microsoft_excel.ts +++ b/apps/sim/blocks/blocks/microsoft_excel.ts @@ -747,6 +747,35 @@ export const MicrosoftExcelBlockMeta = { alsoIntegrations: ['microsoft_teams'], }, ], + skills: [ + { + name: 'read-sheet-range', + description: 'Read data from a Microsoft Excel worksheet range and return the rows.', + content: + '# Read Sheet Range\n\nPull data out of an Excel workbook for analysis or downstream steps.\n\n## Steps\n1. Identify the workbook and the worksheet and range to read.\n2. Use Read Data with the spreadsheet ID and range.\n3. Parse the returned rows into a structured form for the next step.\n\n## Output\nThe values from the range as rows, plus the sheet and range they came from.', + }, + { + name: 'write-sheet-data', + description: + 'Write or update values in a Microsoft Excel worksheet range, with formula parsing control.', + content: + '# Write Sheet Data\n\nUpdate cells in an Excel workbook.\n\n## Steps\n1. Identify the workbook, worksheet, and target range.\n2. Prepare the values as rows matching the range shape.\n3. Use Write/Update Data, choosing User Entered to parse formulas or Raw to write values literally.\n\n## Output\nConfirmation of the cells updated and the range that was written.', + }, + { + name: 'append-table-row', + description: + 'Append a new row to a Microsoft Excel table so it stays structured and formatted.', + content: + '# Append Table Row\n\nAdd a record to an existing Excel table.\n\n## Steps\n1. Identify the workbook and the table to append to.\n2. Build the row values in the table column order.\n3. Use Add to Table to append the row so table formatting and references update automatically.\n\n## Output\nConfirmation the row was appended and the table it was added to.', + }, + { + name: 'add-worksheet', + description: + 'Add a new worksheet to a Microsoft Excel workbook to hold a new dataset or report.', + content: + '# Add Worksheet\n\nCreate a fresh worksheet inside a workbook.\n\n## Steps\n1. Identify the workbook to add the sheet to.\n2. Choose a name for the new worksheet.\n3. Use Add Worksheet to create it, then write headers or data with Write/Update Data if needed.\n\n## Output\nThe new worksheet name and confirmation it was created in the workbook.', + }, + ], } as const satisfies BlockMeta export const MicrosoftExcelV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/microsoft_planner.ts b/apps/sim/blocks/blocks/microsoft_planner.ts index c9f948f963b..60958324e50 100644 --- a/apps/sim/blocks/blocks/microsoft_planner.ts +++ b/apps/sim/blocks/blocks/microsoft_planner.ts @@ -736,4 +736,27 @@ export const MicrosoftPlannerBlockMeta = { alsoIntegrations: ['microsoft_teams'], }, ], + skills: [ + { + name: 'create-task-in-bucket', + description: + 'Create a Microsoft Planner task in a specific plan and bucket with title, due date, and assignee.', + content: + '# Create Planner Task\n\nCreate a new task in a Microsoft Planner plan, placing it in the right bucket and setting a due date and owner.\n\n## Steps\n1. Use List Plans to find the target plan, then List Buckets for that plan to locate the bucket id.\n2. Run Create Task with the plan id, a clear title, and the bucket id so it lands in the right column.\n3. If a due date was described in natural language, convert it to ISO 8601 (YYYY-MM-DDTHH:MM:SSZ) before passing dueDateTime.\n4. Set assigneeUserId when an owner is known.\n\n## Output\nConfirm the created task id and report title, bucket, due date, and assignee. Surface the etag for any follow-up updates.', + }, + { + name: 'set-up-plan-buckets', + description: + 'Create a set of stage or phase buckets in a Planner plan to organize tasks by workflow column.', + content: + '# Set Up Plan Buckets\n\nStructure a Microsoft Planner plan into the workflow columns a team needs, such as To Do, In Progress, Review, and Done, or project phases.\n\n## Steps\n1. Use List Plans to find the target plan, then List Buckets to see which buckets already exist and avoid duplicates.\n2. Run Create Bucket once per desired column, passing the plan id and a clear bucket name.\n3. Keep names short and ordered so the board reads left to right as work progresses.\n\n## Output\nList every bucket id and name that now exists in the plan, marking which were newly created. Suggest the next bucket only if a stage is clearly missing.', + }, + { + name: 'add-task-checklist', + description: + 'Add a step-by-step checklist to a Planner task so each subtask can be tracked and checked off.', + content: + '# Add Task Checklist\n\nBreak a Microsoft Planner task into trackable subtasks using its checklist.\n\n## Steps\n1. Identify the target task id, using Read Task to confirm the title if needed.\n2. Use Get Task Details to read the current checklist and capture the etag required for updates.\n3. Run Update Task Details with the checklist items to add, passing the etag from the previous step.\n4. Set percentComplete on the task with Update Task when progress should reflect the checklist state.\n\n## Output\nConfirm the task id and list the checklist items now present. Note the refreshed etag for any further edits.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/microsoft_teams.ts b/apps/sim/blocks/blocks/microsoft_teams.ts index 8b0a3993b24..c0bdd62ea8a 100644 --- a/apps/sim/blocks/blocks/microsoft_teams.ts +++ b/apps/sim/blocks/blocks/microsoft_teams.ts @@ -553,4 +553,31 @@ export const MicrosoftTeamsBlockMeta = { alsoIntegrations: ['zendesk'], }, ], + skills: [ + { + name: 'post-channel-announcement', + description: 'Write a formatted message to a specific Microsoft Teams channel.', + content: + '# Post Channel Announcement\n\nSend an announcement or update to a Microsoft Teams channel.\n\n## Steps\n1. Identify the team and channel to post to, selecting the channel id.\n2. Compose the message body, using clear headings and bullets so it reads well in Teams.\n3. Run Write Channel Message with the channel id and the formatted content.\n4. If a thread already exists for the topic, use Reply to Channel Message instead to keep context together.\n\n## Output\nConfirm the posted message id and channel. Quote the first line of what was posted.', + }, + { + name: 'summarize-channel-activity', + description: + 'Read recent Microsoft Teams channel messages and produce a concise digest of decisions and action items.', + content: + '# Summarize Channel Activity\n\nTurn a busy Microsoft Teams channel into a short readable digest.\n\n## Steps\n1. Run Read Channel Messages for the target channel.\n2. Group messages by topic or thread and drop noise such as greetings and reactions.\n3. Extract decisions made, open questions, and any explicit action items with owners.\n4. Optionally post the digest back to the channel as a new message.\n\n## Output\nThree short sections: Decisions, Open Questions, Action Items. Each item one line with the person responsible when known.', + }, + { + name: 'acknowledge-with-reaction', + description: 'React to a specific Microsoft Teams message to acknowledge it.', + content: + '# Acknowledge with Reaction\n\nAdd or remove an emoji reaction on a Microsoft Teams message.\n\n## Steps\n1. Locate the message using Get Message or the known message id and channel/chat id.\n2. Run Add Reaction with the desired reactionType to acknowledge or signal status.\n3. Use Remove Reaction when the acknowledgment should be cleared.\n\n## Output\nConfirm the reaction applied and on which message. Keep the response to one line.', + }, + { + name: 'list-team-members', + description: 'List the members of a Microsoft Teams team or channel for routing or auditing.', + content: + '# List Team Members\n\nRetrieve who belongs to a Microsoft Teams team or channel.\n\n## Steps\n1. Decide whether you need team-wide membership or a single channel and pick List Team Members or List Channel Members.\n2. Run the operation with the team id (and channel id when needed).\n3. Normalize the result into a clean roster of names and roles.\n\n## Output\nA roster list with display name and role. Note the total count at the top.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/mistral_parse.ts b/apps/sim/blocks/blocks/mistral_parse.ts index 6bcac848913..ecb00d06909 100644 --- a/apps/sim/blocks/blocks/mistral_parse.ts +++ b/apps/sim/blocks/blocks/mistral_parse.ts @@ -473,4 +473,25 @@ export const MistralParseBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'pdf-to-markdown', + description: 'Convert a PDF document into clean structured Markdown using Mistral OCR.', + content: + '# PDF to Markdown\n\nUse Mistral Parser to turn a PDF, including scanned image-only pages, into clean Markdown.\n\n## Steps\n1. Provide the PDF as a URL or uploaded file to the parser.\n2. Run the parse to extract text, headings, tables, and layout into Markdown.\n3. Review the Markdown for page-break artifacts and stray headers or footers and clean them.\n\n## Output\nReturn the full Markdown. Note the page count and flag any pages where OCR confidence looked low.', + }, + { + name: 'extract-document-fields', + description: + 'Parse a PDF and pull specific structured fields such as totals, dates, or names.', + content: + '# Extract Document Fields\n\nExtract a defined set of fields from a document such as an invoice, statement, or contract.\n\n## Steps\n1. Run Mistral Parser on the source PDF to get the text content.\n2. Locate the requested fields (for example vendor, total, due date, line items) within the parsed text.\n3. Return the fields as a structured object, leaving any field that is genuinely absent as null rather than guessing.\n\n## Output\nA JSON object keyed by the requested field names. List any fields that could not be found.', + }, + { + name: 'summarize-long-document', + description: 'Parse a long PDF and produce a concise summary of its key points.', + content: + '# Summarize Long Document\n\nProduce a readable summary from a long PDF such as a report, paper, or agreement.\n\n## Steps\n1. Parse the PDF with Mistral Parser to get its full text.\n2. Identify the main sections and the most important claims, findings, or obligations.\n3. Write a tight summary that preserves specifics like figures and dates.\n\n## Output\nA short summary with a few bullet highlights. Keep numbers and named entities exact.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/monday.ts b/apps/sim/blocks/blocks/monday.ts index 17ce36d3213..19ede82f0b6 100644 --- a/apps/sim/blocks/blocks/monday.ts +++ b/apps/sim/blocks/blocks/monday.ts @@ -553,4 +553,24 @@ export const MondayBlockMeta = { alsoIntegrations: ['workday'], }, ], + skills: [ + { + name: 'create-board-item', + description: 'Create a new item on a Monday board in the right group with column values set.', + content: + '# Create Board Item\n\nAdd an item to a Monday.com board and populate its columns.\n\n## Steps\n1. Use List Boards to find the board, then Get Board to read its groups and column ids.\n2. Run Create Item with the board id, item name, and the target group.\n3. Map the requested fields to the correct column ids, formatting status and date columns as Monday expects.\n4. Add a follow-up Create Update if a comment or context note is needed on the item.\n\n## Output\nConfirm the new item id, board, and group. List the column values that were set.', + }, + { + name: 'find-items-by-criteria', + description: 'Search a Monday board for items matching a value such as status or owner.', + content: + '# Find Items by Criteria\n\nLocate Monday.com items that match a given condition.\n\n## Steps\n1. Identify the board and the column to filter on with Get Board.\n2. Use Search Items or Get Items to retrieve candidates.\n3. Filter to the items whose column value matches the requested criteria.\n\n## Output\nA list of matching items with name, group, and the relevant column values. Note the total match count.', + }, + { + name: 'progress-item-status', + description: 'Move a Monday item forward by updating its status column and group.', + content: + '# Progress Item Status\n\nAdvance a Monday.com item through its workflow.\n\n## Steps\n1. Get the item with Get Item to read its current status and group.\n2. Run Update Item to set the new status column value.\n3. If the stage maps to a different group, use Move Item to Group to keep the board organized.\n4. Optionally post a Create Update noting the transition.\n\n## Output\nConfirm the item id, the old and new status, and the group it now sits in.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/mongodb.ts b/apps/sim/blocks/blocks/mongodb.ts index fbcb21198b1..43e8229810a 100644 --- a/apps/sim/blocks/blocks/mongodb.ts +++ b/apps/sim/blocks/blocks/mongodb.ts @@ -1036,4 +1036,24 @@ export const MongoDBBlockMeta = { alsoIntegrations: ['tinybird'], }, ], + skills: [ + { + name: 'find-documents', + description: 'Query a MongoDB collection with a filter and return the matching documents.', + content: + '# Find Documents\n\nRetrieve documents from a MongoDB collection that match a filter.\n\n## Steps\n1. If the collection shape is unknown, run Introspect Database first to learn the fields.\n2. Build a MongoDB filter document for the requested condition, using operators like $gte, $in, and $regex as needed.\n3. Run Find Documents against the target collection with the filter, plus projection and limit when appropriate.\n\n## Output\nReturn the matching documents. State the filter used and the number of results. Suggest an index if a scan looks slow.', + }, + { + name: 'aggregate-report', + description: 'Run a MongoDB aggregation pipeline to group and summarize collection data.', + content: + '# Aggregate Report\n\nProduce a summary from a MongoDB collection using an aggregation pipeline.\n\n## Steps\n1. Introspect the collection to confirm the fields to group and measure on.\n2. Compose a pipeline with stages such as $match, $group, $sort, and $limit to compute the requested metric.\n3. Run the Aggregate Pipeline operation and read back the grouped results.\n\n## Output\nA compact table of the grouped metrics. Include the pipeline used so the query can be rerun.', + }, + { + name: 'upsert-document', + description: 'Insert a new MongoDB document or update an existing one matched by a key.', + content: + '# Upsert Document\n\nWrite a document to MongoDB, creating it or updating the existing match.\n\n## Steps\n1. Determine the key field that identifies the record uniquely.\n2. Run Find Documents on that key to see whether a record already exists.\n3. If it exists, run Update Documents with the new values; otherwise run Insert Documents.\n\n## Output\nReport whether a document was inserted or updated and echo the key value. Confirm the affected count.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/neo4j.ts b/apps/sim/blocks/blocks/neo4j.ts index 60891c0978a..999f47330a6 100644 --- a/apps/sim/blocks/blocks/neo4j.ts +++ b/apps/sim/blocks/blocks/neo4j.ts @@ -770,4 +770,25 @@ export const Neo4jBlockMeta = { tags: ['analysis', 'research', 'automation'], }, ], + skills: [ + { + name: 'answer-graph-question', + description: + 'Translate a plain-English question into Cypher, run it on Neo4j, and explain the result.', + content: + '# Answer Graph Question\n\nTurn a natural-language question into a Cypher query against the Neo4j graph.\n\n## Steps\n1. Run Introspect Schema to learn the node labels, relationship types, and properties.\n2. Translate the question into a Cypher MATCH that uses the real labels and relationships from the schema.\n3. Run the Query operation and read the returned rows.\n4. If the query returns nothing, relax the pattern and explain what was tried.\n\n## Output\nA plain-language answer plus the Cypher used and the key matching nodes or paths.', + }, + { + name: 'create-graph-relationship', + description: 'Create or merge nodes and connect them with a relationship in Neo4j.', + content: + '# Create Graph Relationship\n\nAdd nodes and a relationship between them without creating duplicates.\n\n## Steps\n1. Introspect Schema to confirm the labels and relationship type to use.\n2. Use Merge (Find or Create) for each node so existing nodes are reused rather than duplicated.\n3. Create the relationship between them with the requested direction and any properties.\n\n## Output\nConfirm the nodes involved and the relationship created, noting whether each node was found or newly created.', + }, + { + name: 'find-connected-nodes', + description: 'Traverse the Neo4j graph from a starting node to find related entities.', + content: + '# Find Connected Nodes\n\nExplore the neighborhood of a node to find connected entities.\n\n## Steps\n1. Introspect Schema to know the relationship types available.\n2. Build a Cypher MATCH that starts at the given node and traverses the relevant relationships to the desired depth.\n3. Run the Query operation and collect the connected nodes.\n\n## Output\nA list of connected nodes grouped by relationship type, with the traversal path described in one line.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/new_relic.ts b/apps/sim/blocks/blocks/new_relic.ts index 0ba0b42b05c..6992c29b7e7 100644 --- a/apps/sim/blocks/blocks/new_relic.ts +++ b/apps/sim/blocks/blocks/new_relic.ts @@ -426,4 +426,26 @@ export const NewRelicBlockMeta = { alsoIntegrations: ['pagerduty', 'slack'], }, ], + skills: [ + { + name: 'query-golden-signals', + description: + 'Run NRQL to pull latency, error rate, and throughput for a service over a time window.', + content: + '# Query Golden Signals\n\nUse New Relic NRQL to read the golden signals for a service.\n\n## Steps\n1. Identify the service or application name, using Search Entities if it is unknown.\n2. Build NRQL queries for throughput, average and p95 latency, and error rate over the requested window using SELECT ... FROM Transaction WHERE appName = ... SINCE ...\n3. Run NRQL Query for each signal and collect the values.\n\n## Output\nA short table of throughput, latency p50/p95, and error rate with the time window stated. Flag any signal that looks anomalous.', + }, + { + name: 'investigate-error-spike', + description: + 'Use NRQL to break down a New Relic error spike by type and impacted transaction.', + content: + '# Investigate Error Spike\n\nDrill into an error spike for a service in New Relic.\n\n## Steps\n1. Run an NRQL query counting errors over time to confirm and bound the spike window.\n2. Break the errors down by error.class, message, and transactionName using FACET.\n3. Use Get Entity to add context such as the service health and recent alerts.\n4. Check for a recent Create Deployment Event near the spike start to correlate with a release.\n\n## Output\nThe top error types by count, the most impacted transactions, and whether a recent deployment lines up with the spike.', + }, + { + name: 'record-deployment-marker', + description: 'Create a New Relic deployment event so releases line up with metric changes.', + content: + '# Record Deployment Marker\n\nMark a deployment in New Relic to correlate releases with performance.\n\n## Steps\n1. Identify the target entity with Search Entities to get its GUID.\n2. Run Create Deployment Event with the version, and include the commit or changelog and the user who deployed.\n3. Confirm the marker is associated with the right entity.\n\n## Output\nConfirm the deployment event created, with the entity name, version, and timestamp.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/notion.ts b/apps/sim/blocks/blocks/notion.ts index f45e0d80587..aa3cbb9bb5e 100644 --- a/apps/sim/blocks/blocks/notion.ts +++ b/apps/sim/blocks/blocks/notion.ts @@ -630,6 +630,33 @@ export const NotionBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'create-structured-page', + description: + 'Create a Notion page under a parent with headings, bullets, and a clean layout.', + content: + '# Create Structured Page\n\nCreate a well-formatted Notion page, such as meeting notes or a project brief.\n\n## Steps\n1. Identify the parent page or database, using Search Workspace if the destination is not known.\n2. Run Create Page with the title and parent.\n3. Use Append Content to add the body as Notion blocks: headings for sections, bulleted lists for items, and to-do blocks for action items.\n\n## Output\nReturn the new page URL and id. Summarize the sections that were added.', + }, + { + name: 'add-database-entry', + description: 'Add a row to a Notion database with the correct property values.', + content: + '# Add Database Entry\n\nInsert a new row into a Notion database with its properties set.\n\n## Steps\n1. Run Read Database on the target database to learn its property names and types.\n2. Map the requested values to the matching properties, formatting select, date, and relation fields correctly.\n3. Run Add Database Row with the property values.\n\n## Output\nConfirm the new row id and URL, and list the property values that were written.', + }, + { + name: 'query-database', + description: 'Filter and sort a Notion database to return matching entries.', + content: + '# Query Database\n\nRetrieve entries from a Notion database that match a condition.\n\n## Steps\n1. Read the database with Read Database to confirm the property to filter on.\n2. Build a filter and optional sort for the requested condition (for example Status equals Done, sorted by date).\n3. Run Query Database and collect the matching pages.\n\n## Output\nA list of matching entries with their key properties and page links. Note the total count.', + }, + { + name: 'search-and-summarize', + description: 'Search the Notion workspace for a topic and summarize the relevant pages.', + content: + '# Search and Summarize\n\nFind and summarize Notion content on a given topic.\n\n## Steps\n1. Run Search Workspace with the topic keywords.\n2. Read the most relevant pages with Read Page.\n3. Synthesize the key points across the pages, citing each source page by title and link.\n\n## Output\nA short synthesized answer with citations to the Notion pages used. Note if the workspace had no relevant content.', + }, + ], } as const satisfies BlockMeta export const NotionV2BlockMeta = { diff --git a/apps/sim/blocks/blocks/obsidian.ts b/apps/sim/blocks/blocks/obsidian.ts index 0e5207c19e3..fa71d4920b5 100644 --- a/apps/sim/blocks/blocks/obsidian.ts +++ b/apps/sim/blocks/blocks/obsidian.ts @@ -340,4 +340,24 @@ export const ObsidianBlockMeta = { tags: ['individual', 'research', 'automation'], }, ], + skills: [ + { + name: 'capture-note', + description: 'Create a new Obsidian note with Markdown content at a chosen vault path.', + content: + '# Capture Note\n\nWrite a new note into the Obsidian vault.\n\n## Steps\n1. Decide the vault path and filename for the note, keeping folder conventions consistent.\n2. Compose the Markdown body with a clear title heading and any tags or frontmatter wanted.\n3. Run Create Note with the path and content. If the note may already exist, use Append to Note instead to avoid overwriting.\n\n## Output\nConfirm the note path created and summarize what was captured.', + }, + { + name: 'append-to-daily-note', + description: 'Append an entry to the Obsidian periodic daily note.', + content: + '# Append to Daily Note\n\nAdd a timestamped entry to the current daily note.\n\n## Steps\n1. Use Get Periodic Note to confirm the daily note exists and read its current content if needed.\n2. Format the entry as a Markdown bullet or section, including a timestamp where useful.\n3. Run Append to Periodic Note to add it to the day.\n\n## Output\nConfirm the entry was appended to the daily note and quote the line added.', + }, + { + name: 'search-vault', + description: 'Search the Obsidian vault for notes matching a query and summarize matches.', + content: + '# Search Vault\n\nFind notes in the Obsidian vault that mention a topic.\n\n## Steps\n1. Run Search with the query terms.\n2. Open the most relevant results with Get Note to read their content.\n3. Summarize the findings, linking each note by its path.\n\n## Output\nA short synthesis of what the vault says about the topic, with the source note paths listed.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/okta.ts b/apps/sim/blocks/blocks/okta.ts index e3e70fd9d16..02087c286cc 100644 --- a/apps/sim/blocks/blocks/okta.ts +++ b/apps/sim/blocks/blocks/okta.ts @@ -455,4 +455,30 @@ export const OktaBlockMeta = { tags: ['legal', 'enterprise'], }, ], + skills: [ + { + name: 'onboard-user', + description: 'Create an Okta user, set their profile, and add them to the right groups.', + content: + '# Onboard User\n\nProvision a new user in Okta and grant their group access.\n\n## Steps\n1. Run Create User with the profile fields: first name, last name, email, and login.\n2. Determine the groups the role requires, using List Groups to resolve group ids.\n3. Run Add User to Group for each required group.\n4. Activate the user if it was created in a staged state.\n\n## Output\nConfirm the new user id and login, and list the groups they were added to.', + }, + { + name: 'offboard-user', + description: 'Deactivate an Okta user and remove their group memberships during offboarding.', + content: + '# Offboard User\n\nRevoke access for a departing user in Okta.\n\n## Steps\n1. Find the user with List Users or Get User to confirm the user id.\n2. Run Deactivate User (or Suspend User for a temporary hold) to block sign-in.\n3. Remove the user from sensitive groups with Remove User from Group.\n4. Only run Delete User when permanent removal is explicitly requested, since it is irreversible.\n\n## Output\nConfirm the user status and the groups removed. State clearly whether the account was deactivated or deleted.', + }, + { + name: 'audit-group-membership', + description: 'List Okta groups and their members to audit access for a security review.', + content: + '# Audit Group Membership\n\nReview who belongs to Okta groups, focusing on privileged access.\n\n## Steps\n1. Run List Groups to enumerate the groups, or Get Group for a specific one.\n2. For each group of interest, run List Group Members.\n3. Highlight privileged or admin groups and call out any unexpected members.\n\n## Output\nA per-group roster with member counts, and a short list of access concerns to review.', + }, + { + name: 'reset-user-password', + description: 'Trigger an Okta password reset for a user who is locked out.', + content: + '# Reset User Password\n\nHelp a user regain access by resetting their Okta password.\n\n## Steps\n1. Locate the user with Get User to confirm identity.\n2. Run Reset Password to start the reset flow for that user.\n3. If the account is suspended, run Unsuspend User first so the reset can proceed.\n\n## Output\nConfirm the reset was initiated for the named user and note any prerequisite step that was taken.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/onedrive.ts b/apps/sim/blocks/blocks/onedrive.ts index d901d851c02..57d42766324 100644 --- a/apps/sim/blocks/blocks/onedrive.ts +++ b/apps/sim/blocks/blocks/onedrive.ts @@ -503,4 +503,25 @@ export const OneDriveBlockMeta = { alsoIntegrations: ['workday'], }, ], + skills: [ + { + name: 'upload-file-to-folder', + description: 'Upload a file to a specific OneDrive folder, creating the folder if needed.', + content: + '# Upload File to Folder\n\nPlace a file into the right OneDrive folder.\n\n## Steps\n1. Use List Files to confirm the destination folder exists; if not, run Create Folder.\n2. Run Upload File with the file content and the target folder.\n3. Use a clear, consistent filename so the document is easy to find later.\n\n## Output\nConfirm the uploaded file name, its folder, and the file id or link.', + }, + { + name: 'find-and-download-file', + description: 'Locate a file in OneDrive by name and download its contents.', + content: + '# Find and Download File\n\nRetrieve a file from OneDrive for processing.\n\n## Steps\n1. Run List Files in the likely folder to find the file and its id.\n2. Run Download File with the matched file id.\n3. Pass the downloaded content to the next step, such as a parser or summarizer.\n\n## Output\nConfirm the file downloaded with its name and size, and hand off the content.', + }, + { + name: 'save-generated-document', + description: + 'Create a new text or document file in OneDrive from generated content, in the right folder.', + content: + '# Save Generated Document\n\nWrite generated content, such as a report or notes, into OneDrive as a new file.\n\n## Steps\n1. Use List Files to confirm the destination folder exists; if not, run Create Folder.\n2. Compose the document content and choose a clear filename and type.\n3. Run Create File with the content, filename, and target folder.\n\n## Output\nConfirm the created file name, its folder, and the file id or link.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/onepassword.ts b/apps/sim/blocks/blocks/onepassword.ts index 52099ab5eaf..8bcae491777 100644 --- a/apps/sim/blocks/blocks/onepassword.ts +++ b/apps/sim/blocks/blocks/onepassword.ts @@ -340,4 +340,27 @@ export const OnePasswordBlockMeta = { tags: ['legal', 'enterprise'], }, ], + skills: [ + { + name: 'fetch-secret-for-runtime', + description: + 'Retrieve a secret (API key, token, or credential) from a 1Password vault to pass into a downstream step.', + content: + '# Fetch Secret for Runtime\n\nSecurely read a credential from 1Password so a later step can authenticate without hardcoding it.\n\n## Steps\n1. Identify the vault and item that holds the needed secret.\n2. Read the specific field (password, token, or key) from that item.\n3. Pass the value to the downstream tool or request that needs it.\n\n## Output\nConfirm the secret was retrieved without printing its value. Never echo, log, or include the raw secret in any summary or message.', + }, + { + name: 'audit-vault-items', + description: + 'List items in a 1Password vault and report metadata like titles, categories, and last-updated dates.', + content: + '# Audit Vault Items\n\nProduce an inventory of items in a 1Password vault for review.\n\n## Steps\n1. List the items in the specified vault.\n2. For each item collect non-sensitive metadata: title, category, tags, and last-updated date.\n3. Flag items that look stale or duplicated based on titles and dates.\n\n## Output\nA table of items with metadata only. Do not retrieve or display any secret values, just the item references.', + }, + { + name: 'create-credential-item', + description: + 'Store a new credential (login, API key, or token) as an item in a 1Password vault.', + content: + '# Create Credential Item\n\nSave a new secret into 1Password so it is centrally managed.\n\n## Steps\n1. Determine the target vault and the item category (login, API credential, secure note).\n2. Set the title and the secret fields from the provided values.\n3. Create the item in the vault.\n\n## Output\nConfirm the item was created with its title and vault. Do not repeat the secret value back in the response.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/openai.ts b/apps/sim/blocks/blocks/openai.ts index 0ba18930197..15c36bc84d0 100644 --- a/apps/sim/blocks/blocks/openai.ts +++ b/apps/sim/blocks/blocks/openai.ts @@ -127,4 +127,27 @@ export const OpenAIBlockMeta = { tags: ['analysis', 'automation', 'vector-search'], }, ], + skills: [ + { + name: 'embed-text', + description: + 'Generate an OpenAI embedding vector for a piece of text to use in semantic search or similarity.', + content: + '# Embed Text\n\nConvert text into an OpenAI embedding vector.\n\n## Steps\n1. Take the input text. If it is long, ensure it fits the model context; otherwise chunk it first.\n2. Choose the model — text-embedding-3-small for cost-efficient general use or text-embedding-3-large for higher accuracy. Keep the model consistent with any existing vectors it will be compared against.\n3. Generate the embedding.\n\n## Output\nReturn the embedding vector, the model used, and token usage. Note the vector dimensionality so it can be matched to the destination vector index.', + }, + { + name: 'embed-documents-for-retrieval', + description: + 'Chunk and embed a set of documents so they can be upserted into a vector store for retrieval.', + content: + '# Embed Documents for Retrieval\n\nPrepare documents for semantic retrieval by chunking and embedding them.\n\n## Steps\n1. Split each document into reasonably sized chunks with light overlap so context is preserved.\n2. Embed each chunk with a single consistent OpenAI model (e.g., text-embedding-3-small).\n3. Pair each vector with its source metadata (document ID, chunk index, title) ready for upsert into the vector store.\n\n## Output\nReturn the embeddings with their associated metadata and the model used. Report how many chunks were produced and flag any chunk that failed to embed.', + }, + { + name: 'find-semantic-duplicates', + description: + 'Embed items and compare vectors by cosine similarity to flag near-duplicate content.', + content: + '# Find Semantic Duplicates\n\nDetect items that mean the same thing even when worded differently.\n\n## Steps\n1. Embed each candidate item with the same OpenAI model used for the existing set.\n2. Compare each new vector against existing vectors using cosine similarity.\n3. Flag pairs above a similarity threshold (e.g., 0.9) as likely duplicates; treat lower scores as distinct.\n\n## Output\nReturn the flagged duplicate pairs with their similarity scores, sorted highest first, so they can be merged or deduplicated.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/outlook.ts b/apps/sim/blocks/blocks/outlook.ts index c6324228087..015d3428e6a 100644 --- a/apps/sim/blocks/blocks/outlook.ts +++ b/apps/sim/blocks/blocks/outlook.ts @@ -537,4 +537,30 @@ export const OutlookBlockMeta = { tags: ['legal', 'analysis', 'automation'], }, ], + skills: [ + { + name: 'send-email', + description: 'Compose and send an Outlook email to one or more recipients.', + content: + '# Send Email\n\nSend a message from the connected Outlook account.\n\n## Steps\n1. Gather the recipients, subject, and the body content.\n2. Write a clear subject and a concise, well-structured body.\n3. Run Send Email with the recipients, subject, and body. Use Draft Email instead when the message should be reviewed before sending.\n\n## Output\nConfirm the email was sent, listing recipients and subject. If drafted, note that it awaits review.', + }, + { + name: 'triage-inbox', + description: 'Read recent Outlook emails and summarize which ones need a reply or action.', + content: + '# Triage Inbox\n\nTurn a noisy Outlook inbox into a short action list.\n\n## Steps\n1. Run Read Email to pull recent unread messages.\n2. Classify each as needs reply, needs action, FYI, or ignore.\n3. For handled messages, run Mark as Read; leave items that still need a reply unread.\n\n## Output\nA prioritized list of emails that need attention, each with sender, subject, and the suggested next action.', + }, + { + name: 'forward-with-context', + description: 'Forward an Outlook email to the right person with an added note.', + content: + '# Forward with Context\n\nRoute an email to the correct owner with a short explanation.\n\n## Steps\n1. Read the target email to capture its content with Read Email.\n2. Identify the correct recipient for the topic.\n3. Run Forward Email to that recipient, adding a brief note on why it is being forwarded and what is needed.\n\n## Output\nConfirm the email was forwarded, to whom, and the note that was added.', + }, + { + name: 'file-email-to-folder', + description: 'Move an Outlook email to the appropriate folder to keep the inbox clean.', + content: + '# File Email to Folder\n\nOrganize the inbox by moving a message into the right folder.\n\n## Steps\n1. Identify the email and the destination folder.\n2. Run Move Email to relocate the message.\n3. Optionally run Mark as Read so it does not linger as unread.\n\n## Output\nConfirm the email moved, naming the source and destination folders.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/pagerduty.ts b/apps/sim/blocks/blocks/pagerduty.ts index abd410615c1..895eb12c1f7 100644 --- a/apps/sim/blocks/blocks/pagerduty.ts +++ b/apps/sim/blocks/blocks/pagerduty.ts @@ -555,4 +555,34 @@ export const PagerDutyBlockMeta = { alsoIntegrations: ['linear'], }, ], + skills: [ + { + name: 'open-incident', + description: + 'Create a PagerDuty incident on a service with a title, urgency, and description so responders get paged.', + content: + '# Open Incident\n\nCreate a new PagerDuty incident and page the on-call responder.\n\n## Steps\n1. Use the Create Incident operation with the target Service ID and a clear, specific Title summarizing the problem.\n2. Set Urgency (high or low) based on customer impact and add a Description with affected systems, symptoms, and any error signatures.\n3. Optionally set an Escalation Policy ID or Assignee User ID to route the page directly.\n4. Capture the returned incident ID, number, and web URL for follow-up.\n\n## Output\nReport the new incident number, urgency, assigned service, and the PagerDuty URL so the team can jump straight to the incident.', + }, + { + name: 'triage-active-incidents', + description: + 'List triggered and acknowledged PagerDuty incidents and produce a prioritized triage summary.', + content: + '# Triage Active Incidents\n\nReview what is currently on fire and summarize it for the team.\n\n## Steps\n1. Use List Incidents filtered to Triggered then Acknowledged statuses, sorted by created at (newest first).\n2. Optionally scope to specific Service IDs or a Since window to focus on a team or recent activity.\n3. Group results by service and urgency, flagging high-urgency triggered incidents that are still unacknowledged.\n4. For each, note title, age, status, and the responsible service.\n\n## Output\nA prioritized list leading with unacknowledged high-urgency incidents, including incident number, service, age, and URL.', + }, + { + name: 'resolve-and-note-incident', + description: + 'Update a PagerDuty incident status and add a resolution note documenting what was done.', + content: + '# Resolve and Note Incident\n\nClose out an incident with a clear audit trail.\n\n## Steps\n1. Use Update Incident with the Incident ID and set Status to acknowledged or resolved as appropriate.\n2. Use Add Note on the same Incident ID to record the root cause, the fix applied, and any follow-up actions.\n3. Provide a valid From Email (a real PagerDuty user) since these write operations require it.\n4. Confirm the new status from the response.\n\n## Output\nState the incident number, its new status, and a one-line summary of the note that was attached.', + }, + { + name: 'check-whos-on-call', + description: + 'List current PagerDuty on-call assignments for given schedules or escalation policies.', + content: + '# Check Who Is On Call\n\nFind the right person to reach right now.\n\n## Steps\n1. Use List On-Calls, optionally scoped by Escalation Policy IDs or Schedule IDs.\n2. Set a Since and Until window to look at the current or an upcoming shift.\n3. Map each on-call entry to its escalation level so primary versus backup responders are clear.\n\n## Output\nA concise roster: who is on call at level 1 (primary) and level 2 (backup) per schedule, with the time window covered.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/parallel.ts b/apps/sim/blocks/blocks/parallel.ts index a4649fafc6c..62bd9712f81 100644 --- a/apps/sim/blocks/blocks/parallel.ts +++ b/apps/sim/blocks/blocks/parallel.ts @@ -346,4 +346,33 @@ export const ParallelBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'research-company-brief', + description: + 'Run Parallel AI deep research on a company and produce a cited brief covering funding, leadership, and product.', + content: + '# Research Company Brief\n\nGenerate a sourced account brief for a target company.\n\n## Steps\n1. Use the Deep Research operation with a Research Query naming the company and the angles to cover: recent funding, leadership changes, product launches, and notable news.\n2. Choose a processor tier (Pro for balance, Ultra for depth) and optionally constrain Include or Exclude Domains.\n3. Read the structured content plus the basis field for citations and confidence per claim.\n\n## Output\nA brief organized by topic, where every claim links to its source URL from the basis, and note any low-confidence items that need verification.', + }, + { + name: 'web-search-with-objective', + description: + 'Use Parallel AI search to answer a question across the web and return ranked, cited results.', + content: + '# Web Search With Objective\n\nAnswer a factual question grounded in fresh web sources.\n\n## Steps\n1. Use the Search operation and state a clear Objective describing what you want to know and which sources to prefer.\n2. Optionally add specific Search Queries, set a Search Mode (one-shot, agentic, or fast), and limit results with Include or Exclude Domains.\n3. Tune Max Results and Max Chars Per Result for breadth versus depth.\n\n## Output\nA direct answer to the objective followed by the supporting results, each with title, URL, and the relevant excerpt.', + }, + { + name: 'extract-facts-from-urls', + description: 'Use Parallel AI extract to pull structured facts from a list of source URLs.', + content: + '# Extract Facts From URLs\n\nTurn a set of pages into structured data.\n\n## Steps\n1. Use the Extract operation and provide the comma-separated URLs to read.\n2. Set an Extract Objective describing exactly which fields to pull from each page.\n3. Enable Include Excerpts for supporting snippets and Include Full Content only when the whole page text is needed.\n\n## Output\nA normalized record per URL with the requested fields and an excerpt backing each value, plus a note on any URL that could not be parsed.', + }, + { + name: 'monitor-competitor-news', + description: + 'Search Parallel AI for recent announcements from named competitors and summarize the changes.', + content: + '# Monitor Competitor News\n\nTrack what rivals shipped or announced recently.\n\n## Steps\n1. Use the Search operation with an Objective naming the competitors and the timeframe of interest.\n2. Optionally restrict Include Domains to the competitors official sites and reputable news outlets.\n3. For high-signal hits, follow up with the Extract operation to pull the specific details from each announcement URL.\n\n## Output\nA dated digest grouped by competitor, each item a one-line summary with its source URL and why it matters.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/peopledatalabs.ts b/apps/sim/blocks/blocks/peopledatalabs.ts index 3c1b00d5bfc..f7fda642d6b 100644 --- a/apps/sim/blocks/blocks/peopledatalabs.ts +++ b/apps/sim/blocks/blocks/peopledatalabs.ts @@ -703,4 +703,34 @@ export const PeopleDataLabsBlockMeta = { alsoIntegrations: ['emailbison'], }, ], + skills: [ + { + name: 'enrich-person', + description: + 'Enrich a single person from an email, LinkedIn URL, or name plus company using People Data Labs.', + content: + '# Enrich Person\n\nFill in a full profile for one contact.\n\n## Steps\n1. Use the Person Enrich operation and provide the strongest identifier available: Email or LinkedIn URL first, otherwise First and Last Name plus Company.\n2. Set a Min Likelihood (for example 6) to avoid weak matches.\n3. Read the matched person record for job title, seniority, company, location, and contact fields, and check the likelihood score.\n\n## Output\nThe enriched profile (title, seniority, company, location, emails) plus the match likelihood; if not matched, say so and list which identifiers were tried.', + }, + { + name: 'search-people-by-criteria', + description: + 'Search the People Data Labs person dataset by role, location, or company using SQL or Elasticsearch DSL.', + content: + '# Search People By Criteria\n\nFind people matching a target profile.\n\n## Steps\n1. Use the Person Search operation and write a SQL query (for example filter on job_title and location_country) or an Elasticsearch DSL query for finer control.\n2. Set Result Size for the page, and optionally a Dataset filter (such as email or mobile_phone) to require certain coverage.\n3. To page through more results, pass the returned scroll token on the next call.\n\n## Output\nThe list of matched people with key fields, the total dataset match count, and the scroll token to fetch the next page.', + }, + { + name: 'enrich-company', + description: + 'Enrich a company from a name, website, or LinkedIn URL to get firmographics with People Data Labs.', + content: + '# Enrich Company\n\nBuild a firmographic profile for one company.\n\n## Steps\n1. Use the Company Enrich operation and provide a Website (most reliable), Company Name, ticker, or LinkedIn URL.\n2. Optionally add a Location or PDL Company ID to disambiguate common names, and set Min Likelihood.\n3. Read the matched company record for industry, employee count, headquarters, and tech-related signals.\n\n## Output\nThe company firmographics (industry, size, location, founded, website) with the match confidence noted.', + }, + { + name: 'bulk-enrich-contacts', + description: + 'Enrich many people or companies in one call with People Data Labs bulk enrichment.', + content: + '# Bulk Enrich Contacts\n\nEnrich a batch of records efficiently.\n\n## Steps\n1. Use Bulk Person Enrich (or Bulk Company Enrich) and pass a JSON array of request objects, each with its own params such as a LinkedIn URL, email, or website.\n2. Optionally set a Required Fields expression (for example emails AND job_title) so only records with that coverage are returned.\n3. Iterate the results array in order, matching each result back to its input record.\n\n## Output\nA per-record summary listing which inputs matched, the enriched fields returned, and which inputs had no match for follow-up.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/perplexity.ts b/apps/sim/blocks/blocks/perplexity.ts index 14371358e24..2d57c8da935 100644 --- a/apps/sim/blocks/blocks/perplexity.ts +++ b/apps/sim/blocks/blocks/perplexity.ts @@ -334,4 +334,27 @@ export const PerplexityBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'answer-with-citations', + description: + 'Ask Perplexity a question and get an answer grounded in current web sources with citations.', + content: + '# Answer With Citations\n\nGet a current, sourced answer to a question.\n\n## Steps\n1. Use the Chat operation and write the question as the User Prompt. Add a System Prompt to set tone and require inline citations.\n2. Pick a model: sonar for quick answers, sonar-pro for harder questions, or sonar-deep-research for thorough multi-source work.\n3. Keep temperature low (around 0.2) for factual tasks and set Max Tokens to cap length.\n\n## Output\nThe answer with its supporting sources, and a note flagging anything the model could not confirm.', + }, + { + name: 'search-recent-news', + description: + 'Use Perplexity search with a recency filter to find the latest results on a topic.', + content: + '# Search Recent News\n\nFind the freshest sources on a topic.\n\n## Steps\n1. Use the Search operation and enter the topic as the Search Query.\n2. Set a Recency Filter (hour, day, week, month, or year) or pin an After Date and Before Date window.\n3. Optionally constrain a Domain Filter to trusted outlets and set a Country code for regional results.\n4. Adjust Max Results for breadth.\n\n## Output\nA dated list of results, each with title, URL, and a one-line summary, ordered by relevance and recency.', + }, + { + name: 'domain-restricted-research', + description: + 'Run a Perplexity search restricted to specific authoritative domains and summarize findings.', + content: + '# Domain-Restricted Research\n\nResearch a topic using only trusted sources.\n\n## Steps\n1. Use the Search operation with a precise Search Query.\n2. Set the Domain Filter to the allowed domains (comma-separated, up to twenty) such as official, academic, or .gov sites.\n3. Tune Max Page Tokens to control how much text is pulled per source.\n4. Synthesize the returned results into a short summary.\n\n## Output\nA concise summary drawn only from the allowed domains, with each finding attributed to its source URL.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/pinecone.ts b/apps/sim/blocks/blocks/pinecone.ts index 2530919f0bd..06e9c9e13f3 100644 --- a/apps/sim/blocks/blocks/pinecone.ts +++ b/apps/sim/blocks/blocks/pinecone.ts @@ -401,4 +401,33 @@ export const PineconeBlockMeta = { alsoIntegrations: ['openai', 'zendesk'], }, ], + skills: [ + { + name: 'upsert-text-records', + description: + 'Embed and upsert text records into a Pinecone namespace using integrated embeddings.', + content: + '# Upsert Text Records\n\nLoad documents into a Pinecone index for retrieval.\n\n## Steps\n1. Use the Upsert Text operation and provide the Index Host and target Namespace.\n2. Pass newline-delimited JSON Records, each with a unique _id, a text or chunk_text field, and any metadata fields such as category for later filtering.\n3. Keep chunks reasonably sized so each record carries one coherent idea.\n4. Confirm the upsert status from the response.\n\n## Output\nReport how many records were upserted into which namespace and surface any records that failed validation.', + }, + { + name: 'semantic-search', + description: + 'Run a text query against a Pinecone index with metadata filtering and optional reranking.', + content: + '# Semantic Search\n\nRetrieve the most relevant records for a query.\n\n## Steps\n1. Use the Search With Text operation with the Index Host, Namespace, and a natural-language Search Query.\n2. Set Top K for how many matches to return and list the Fields to Return.\n3. Optionally apply a metadata Filter (operators like $eq, $in, $gte) to scope the search, and pass Rerank Options to reorder by a cross-encoder for higher precision.\n\n## Output\nThe top matches with their scores, returned fields, and IDs, ordered by relevance after any reranking.', + }, + { + name: 'generate-embeddings', + description: + 'Generate vector embeddings for a set of texts with a Pinecone-hosted embedding model.', + content: + '# Generate Embeddings\n\nTurn text into vectors for storage or comparison.\n\n## Steps\n1. Use the Generate Embeddings operation and choose a model such as multilingual-e5-large or llama-text-embed-v2.\n2. Provide the Text Inputs as a JSON array of objects each with a text field.\n3. Use the returned vectors for downstream upserts or similarity work.\n\n## Output\nThe embedding vector per input, the model used, and the usage statistics for cost tracking.', + }, + { + name: 'fetch-vectors-by-id', + description: 'Fetch specific vectors and their metadata from a Pinecone namespace by ID.', + content: + '# Fetch Vectors By ID\n\nLook up known records directly.\n\n## Steps\n1. Use the Fetch Vectors operation with the Index Host and Namespace.\n2. Provide the Vector IDs as a JSON array of the records to retrieve.\n3. Inspect the returned values and metadata to confirm content or debug retrieval.\n\n## Output\nThe requested records with their stored metadata, and a note listing any IDs that were not found.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/pipedrive.ts b/apps/sim/blocks/blocks/pipedrive.ts index d00ddbbd9cf..de03c2f9c47 100644 --- a/apps/sim/blocks/blocks/pipedrive.ts +++ b/apps/sim/blocks/blocks/pipedrive.ts @@ -912,4 +912,34 @@ export const PipedriveBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'create-deal', + description: + 'Create a Pipedrive deal with a title, value, pipeline stage, and linked person or organization.', + content: + '# Create Deal\n\nAdd a new opportunity to the sales pipeline.\n\n## Steps\n1. Use the Create Deal operation with a clear Title.\n2. Set Value and Currency, the target Pipeline and Stage ID, and Status (open, won, or lost).\n3. Link the deal to a Person ID or Organization ID, and set an Expected Close Date.\n4. Capture the returned deal ID for follow-up activities.\n\n## Output\nConfirm the new deal title, value, pipeline stage, and ID so it can be referenced in later steps.', + }, + { + name: 'review-pipeline', + description: + 'List Pipedrive deals in a pipeline and summarize stage distribution and deals at risk.', + content: + '# Review Pipeline\n\nGet a snapshot of the current sales pipeline.\n\n## Steps\n1. Use Get All Deals (or Get Pipeline Deals for one pipeline) filtered to open status.\n2. Optionally scope by Pipeline, Person ID, or Organization ID and set Updated Since to focus on recent movement.\n3. Group deals by stage and total their value, flagging stale deals with no recent update.\n4. Page with the cursor or start offset for large pipelines.\n\n## Output\nA stage-by-stage breakdown with deal counts and total value, plus a short list of at-risk deals that have gone quiet.', + }, + { + name: 'log-activity', + description: + 'Create a Pipedrive activity such as a call, meeting, or task linked to a deal or contact.', + content: + '# Log Activity\n\nSchedule or record follow-up work against a record.\n\n## Steps\n1. Use the Create Activity operation with a Subject and an activity Type (call, meeting, task, deadline, email, or lunch).\n2. Set the Due Date and optional Due Time, Duration, and Notes.\n3. Link the activity to the relevant Deal ID, Person ID, or Organization ID.\n4. Use Update Activity later to mark it done.\n\n## Output\nConfirm the activity subject, type, due date, and the record it is linked to.', + }, + { + name: 'manage-leads', + description: + 'Create or update Pipedrive leads with value, contacts, and expected close date.', + content: + '# Manage Leads\n\nCapture and maintain top-of-funnel leads.\n\n## Steps\n1. Use Create Lead with a Title and link a Person ID or Organization ID and an Owner ID.\n2. Set the Value Amount and Value Currency and an Expected Close Date.\n3. Use Update Lead to revise details or archive a lead once it converts or goes cold.\n4. Use Get Leads to review active or archived leads.\n\n## Output\nThe lead title, linked contact, value, and current state (active or archived) with its ID.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/polymarket.ts b/apps/sim/blocks/blocks/polymarket.ts index a9d718332b7..36ccaf03c07 100644 --- a/apps/sim/blocks/blocks/polymarket.ts +++ b/apps/sim/blocks/blocks/polymarket.ts @@ -977,4 +977,34 @@ export const PolymarketBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'find-market-odds', + description: + 'Look up a Polymarket market and report the current implied odds and price for each outcome.', + content: + '# Find Market Odds\n\nGet the live implied probability for a question.\n\n## Steps\n1. Use Search or Get Markets to locate the market, or Get Market with a known market ID or slug.\n2. Read the outcome token IDs from the market, then use Get Price or Get Midpoint per token to get the current price.\n3. Treat the price (0 to 1) as the implied probability of that outcome.\n\n## Output\nFor the market, list each outcome with its current price as a percentage probability, plus the market volume and whether it is still open.', + }, + { + name: 'list-top-markets', + description: + 'List the highest-volume or most-liquid Polymarket markets, optionally filtered by category tag.', + content: + '# List Top Markets\n\nSurface the markets attracting the most attention.\n\n## Steps\n1. Use Get Markets (or Get Events) sorted by Volume or Liquidity in descending order.\n2. Optionally filter by a Tag ID for a category and set Closed Status to open only.\n3. Set a Limit and use the offset to page through results.\n\n## Output\nA ranked list of markets with title, volume, liquidity, and current implied odds for the leading outcome.', + }, + { + name: 'track-price-history', + description: + 'Pull Polymarket price history for an outcome token over an interval and summarize the trend.', + content: + '# Track Price History\n\nSee how an outcome moved over time.\n\n## Steps\n1. Identify the outcome token ID from the market.\n2. Use Get Price History with that Token ID and either a preset Interval (1h, 6h, 1d, 1w, max) or a Start and End timestamp with a Fidelity in minutes.\n3. Compare the latest price against the start of the window to compute the move.\n\n## Output\nThe price at the start and end of the window, the net change, and a one-line read on the trend (rising, falling, or flat).', + }, + { + name: 'analyze-wallet-positions', + description: + "Fetch a Polymarket wallet's open positions and summarize value and profit and loss.", + content: + '# Analyze Wallet Positions\n\nReview what a trader holds and how it is performing.\n\n## Steps\n1. Use Get Positions with the User Wallet Address, optionally sorted by Cash P&L or Current Value.\n2. Filter with a Size Threshold or by redeemable status to focus on meaningful holdings.\n3. Optionally use Get Activity for the same wallet to see recent trades and redemptions.\n\n## Output\nA summary of the wallet positions: total current value, aggregate profit and loss, and the largest winners and losers by market.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/posthog.ts b/apps/sim/blocks/blocks/posthog.ts index fcd9efcc4d9..70f06fe1c04 100644 --- a/apps/sim/blocks/blocks/posthog.ts +++ b/apps/sim/blocks/blocks/posthog.ts @@ -1400,4 +1400,37 @@ export const PostHogBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'capture-event', + description: 'Send a product analytics event to PostHog for a user with custom properties.', + content: + '# Capture Event\n\nRecord a user action in PostHog.\n\n## Steps\n1. Use the Capture Event operation with the Project API Key and Project ID.\n2. Set the Event Name (for example purchase_completed) and the Distinct ID identifying the user.\n3. Add Properties as a JSON object with relevant context such as plan, price, or page, and optionally a Timestamp.\n4. For many events at once, use Batch Events with a JSON array instead.\n\n## Output\nConfirm the event name and user it was captured for, and report success or any validation error returned.', + }, + { + name: 'query-product-data', + description: 'Run a HogQL query against PostHog to answer a product analytics question.', + content: + '# Query Product Data\n\nPull custom analytics with HogQL.\n\n## Steps\n1. Use the Run Query operation with your Personal API Key, Project ID, and Region.\n2. Write the HogQL Query (SQL-like) to compute the metric, for example daily active users or top events over a window.\n3. Pass Query Values for any parameters.\n4. Aggregate or format the returned rows for the answer.\n\n## Output\nThe query result rows summarized into a direct answer, noting the time window and any assumptions in the query.', + }, + { + name: 'manage-feature-flag', + description: 'Create, update, or toggle a PostHog feature flag and control its rollout.', + content: + '# Manage Feature Flag\n\nControl a feature rollout in PostHog.\n\n## Steps\n1. Use Create Feature Flag with a Flag Key, Name, and a Rollout Percentage, or Update Feature Flag by Feature Flag ID to change state.\n2. Set Active on or off and supply Filters as JSON to target specific cohorts or person properties.\n3. Provide the Personal API Key, Project ID, and Region.\n4. Use List Feature Flags to confirm the current state.\n\n## Output\nReport the flag key, whether it is active, and the rollout percentage or targeting now in effect.', + }, + { + name: 'analyze-survey-responses', + description: 'List PostHog surveys and pull responses to summarize themes and satisfaction.', + content: + '# Analyze Survey Responses\n\nTurn survey feedback into insight.\n\n## Steps\n1. Use List Surveys to find the active survey, then Get Survey for its definition.\n2. Use Run Query (HogQL) to pull the survey response events for that survey over a date window.\n3. Group open-text answers by theme and compute the rating or NPS distribution.\n\n## Output\nA short summary of the top themes from open responses plus the rating or NPS breakdown and any notable movement.', + }, + { + name: 'add-release-annotation', + description: + 'Create a PostHog annotation marking a deploy or release on the analytics timeline.', + content: + '# Add Release Annotation\n\nMark an event on the PostHog timeline for context.\n\n## Steps\n1. Use the Create Annotation operation with the Personal API Key, Project ID, and Region.\n2. Provide the Content describing what happened (for example a deploy or campaign launch) and a Date Marker timestamp.\n3. Set the Scope to project or dashboard item.\n\n## Output\nConfirm the annotation content and the date it was placed on so charts show the marker.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/profound.ts b/apps/sim/blocks/blocks/profound.ts index b57558e465f..63c41fd7adf 100644 --- a/apps/sim/blocks/blocks/profound.ts +++ b/apps/sim/blocks/blocks/profound.ts @@ -475,4 +475,34 @@ export const ProfoundBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'check-brand-visibility', + description: + 'Pull a Profound visibility report to see how a brand surfaces in AI answers for tracked prompts.', + content: + '# Check Brand Visibility\n\nMeasure how often a brand appears in AI engine answers.\n\n## Steps\n1. Use the Visibility Report operation with the Category ID and a Start Date and End Date.\n2. Set Metrics such as share_of_voice, visibility_score, and mentions_count.\n3. Optionally break the data out by Dimensions (date, model) and set a Date Interval.\n4. Compare the latest period against the prior one.\n\n## Output\nThe visibility and share-of-voice scores for the period, broken down by model where requested, with the change versus the previous window.', + }, + { + name: 'track-citation-sources', + description: + 'Pull a Profound citations report to see which sources AI engines cite for brand prompts.', + content: + '# Track Citation Sources\n\nFind the sources AI engines cite when answering about a brand.\n\n## Steps\n1. Use the Citations Report operation with the Category ID, Start Date, and End Date, and set Metrics such as count and citation_share.\n2. For a specific domain, use Citation Prompts with the Domain to see which prompts cite it.\n3. Optionally add Dimensions to group by source domain or page.\n\n## Output\nA ranked list of citing domains and pages with their citation share, highlighting any new sources the content team should target.', + }, + { + name: 'compare-competitor-share', + description: + 'Use Profound visibility metrics to compare a brand against competitors in AI answers.', + content: + '# Compare Competitor Share\n\nBenchmark share-of-voice across competitors.\n\n## Steps\n1. Use the Visibility Report operation for the Category ID over a date window with the share_of_voice metric.\n2. Add Dimensions to break results out by asset or brand name, and apply Filters as JSON to scope to the competitor set.\n3. Rank the brands by share-of-voice.\n\n## Output\nA leaderboard of brands by share-of-voice in AI answers, flagging any competitor that gained or lost notable ground.', + }, + { + name: 'find-content-gaps', + description: + 'Use Profound prompt and answer data to find prompts where the brand is absent from AI answers.', + content: + '# Find Content Gaps\n\nSurface prompts where the brand is missing from AI answers.\n\n## Steps\n1. Use Category Prompts with the Category ID to list tracked prompts, paging with the cursor.\n2. Use Prompt Answers over a date window to see how the brand appears (or does not) for each prompt.\n3. Flag prompts with low or zero visibility as content gaps.\n\n## Output\nA prioritized list of prompts where the brand is absent or weak in AI answers, ready to drive content briefs.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/prospeo.ts b/apps/sim/blocks/blocks/prospeo.ts index 8464aab03a2..f226f4dd4ba 100644 --- a/apps/sim/blocks/blocks/prospeo.ts +++ b/apps/sim/blocks/blocks/prospeo.ts @@ -604,4 +604,33 @@ export const ProspeoBlockMeta = { tags: ['sales', 'research', 'enrichment'], }, ], + skills: [ + { + name: 'find-work-email', + description: + "Find and verify a prospect's work email and optional mobile number with Prospeo.", + content: + '# Find Work Email\n\nGet a deliverable work email for a prospect.\n\n## Steps\n1. Use the Enrich Person operation and provide the strongest match key: a LinkedIn URL, or First and Last Name plus Company Name or Company Website.\n2. Set Only Verified Email to Yes when deliverability matters, and Enrich Mobile to also reveal a phone number.\n3. Read the enriched person object for the email, its verification status, and the mobile if requested.\n\n## Output\nThe verified work email (and mobile if requested) with its status, or a clear note that no match was found and which keys were tried.', + }, + { + name: 'search-prospects', + description: + 'Search Prospeo for people matching an ICP using seniority, title, industry, and company filters.', + content: + '# Search Prospects\n\nBuild a targeted prospect list from the B2B database.\n\n## Steps\n1. Use the Search Person operation and supply a Filters JSON object using documented keys such as person_seniority, person_job_title, company_industry, and company_headcount_range with include or exclude lists.\n2. Avoid using only exclude filters; always include at least one positive filter.\n3. Page through results with the Page field.\n\n## Output\nThe matching prospects with names, titles, and companies, plus the pagination details so the list can be fully retrieved.', + }, + { + name: 'enrich-company', + description: + 'Enrich a company from its website or LinkedIn URL to get Prospeo firmographics.', + content: + '# Enrich Company\n\nPull firmographics for a target account.\n\n## Steps\n1. Use the Enrich Company operation and provide the Company Website or Company LinkedIn URL (most reliable), or a Company Name.\n2. Read the returned company object for size, industry, location, and other firmographic fields.\n3. For many accounts, use Bulk Enrich Company with a JSON array of records, each with an identifier and a match key.\n\n## Output\nThe company firmographics (size, industry, location) for the account, or the matched and not-matched breakdown when running in bulk.', + }, + { + name: 'bulk-enrich-list', + description: 'Enrich a list of people or companies in batches with Prospeo bulk enrichment.', + content: + '# Bulk Enrich List\n\nEnrich up to fifty records per call efficiently.\n\n## Steps\n1. Use Bulk Enrich Person (or Bulk Enrich Company) and pass a JSON array of records, each with a unique identifier and one valid match key set.\n2. Set Only Verified Email or Enrich Mobile as needed for the person variant.\n3. Map results back to inputs using the identifier, and check the not-matched and invalid-datapoints lists.\n\n## Output\nA per-identifier summary of matched records with their enriched fields, the total credit cost, and the identifiers that did not match for retry.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/pulse.ts b/apps/sim/blocks/blocks/pulse.ts index f2d2f253438..337f56c4b7a 100644 --- a/apps/sim/blocks/blocks/pulse.ts +++ b/apps/sim/blocks/blocks/pulse.ts @@ -277,4 +277,26 @@ export const PulseBlockMeta = { tags: ['ocr', 'document-processing', 'automation'], }, ], + skills: [ + { + name: 'extract-document-text', + description: 'Run a PDF, image, or Office file through Pulse OCR and return clean markdown.', + content: + '# Extract Document Text\n\nTurn a document into structured markdown text.\n\n## Steps\n1. Upload the Document (PDF, image, DOCX, PPTX, or XLSX) or provide a file reference.\n2. Optionally set Specific Pages (for example 1-3,5) to limit extraction to part of the document.\n3. Provide the Pulse API Key.\n4. Use the returned markdown as the source for downstream summarization or parsing.\n\n## Output\nThe extracted markdown text and the page count, plus any bounding-box or figure data when available.', + }, + { + name: 'extract-structured-fields', + description: + 'Use Pulse OCR output to pull structured fields like vendor, totals, or dates from a document.', + content: + '# Extract Structured Fields\n\nPull specific data points out of a scanned document.\n\n## Steps\n1. Run the document through Pulse OCR to get the markdown text.\n2. In a following agent step, map the markdown to the target fields (for example invoice vendor, line items, totals, or contract parties and renewal dates).\n3. Validate the parsed values against the source text before using them.\n\n## Output\nA structured record of the requested fields, with a note on any field that could not be confidently extracted from the document.', + }, + { + name: 'chunk-for-knowledge-base', + description: + 'Extract and chunk a document with Pulse OCR so it can be indexed for retrieval.', + content: + '# Chunk For Knowledge Base\n\nPrepare a document for vector indexing.\n\n## Steps\n1. Upload the Document and provide the Pulse API Key.\n2. Set a Chunking Strategy (semantic, header, page, or recursive) and a Chunk Size in characters.\n3. Use the returned chunks as the units to embed and index into a knowledge base.\n\n## Output\nThe chunked content ready for embedding, with each chunk sized per the strategy, plus the total page count for reference.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/qdrant.ts b/apps/sim/blocks/blocks/qdrant.ts index 56f9e407ce1..e495d89102c 100644 --- a/apps/sim/blocks/blocks/qdrant.ts +++ b/apps/sim/blocks/blocks/qdrant.ts @@ -317,4 +317,24 @@ export const QdrantBlockMeta = { alsoIntegrations: ['openai', 'zendesk'], }, ], + skills: [ + { + name: 'upsert-points', + description: 'Insert or update vector points with payload metadata into a Qdrant collection.', + content: + '# Upsert Points\n\nLoad vectors into a Qdrant collection.\n\n## Steps\n1. Use the Upsert operation with the Qdrant URL, Collection name, and API Key.\n2. Provide Points as a JSON array, each with an id, a vector matching the collection dimension, and an optional payload of metadata for later filtering.\n3. Confirm the upserted count from the response.\n\n## Output\nReport how many points were upserted into which collection and surface any payload validation issues.', + }, + { + name: 'search-vectors', + description: 'Run a vector similarity search in Qdrant with optional payload filters.', + content: + '# Search Vectors\n\nFind the nearest points to a query vector.\n\n## Steps\n1. Use the Search operation with the Qdrant URL, Collection, and the Query Vector.\n2. Set the Limit for how many matches to return and choose what Return Data you need (payload only, vector only, both, or none).\n3. Optionally pass a Filter JSON object using must, should, or must_not conditions to scope the search by payload fields.\n\n## Output\nThe top matches with their scores and requested payload or vector data, ordered by similarity.', + }, + { + name: 'fetch-points-by-id', + description: 'Retrieve specific Qdrant points and their payloads by ID.', + content: + '# Fetch Points By ID\n\nLook up known points directly.\n\n## Steps\n1. Use the Fetch operation with the Qdrant URL, Collection, and API Key.\n2. Provide the IDs as a JSON array of the points to retrieve.\n3. Choose the Return Data option to control whether payloads and vectors are included.\n\n## Output\nThe requested points with their payloads (and vectors if requested), plus a note on any IDs that were not found.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/quiver.ts b/apps/sim/blocks/blocks/quiver.ts index c0e76ae7749..8e816e46c8f 100644 --- a/apps/sim/blocks/blocks/quiver.ts +++ b/apps/sim/blocks/blocks/quiver.ts @@ -268,4 +268,24 @@ export const QuiverBlockMeta = { tags: ['design', 'automation'], }, ], + skills: [ + { + name: 'generate-brand-icon', + description: 'Generate a clean SVG icon from a text prompt and save it to the files store.', + content: + '# Generate Brand Icon\n\nTurn a text description into a production-ready SVG icon using Quiver text-to-SVG.\n\n## Steps\n1. Collect the icon concept (for example, a product name plus a brand color and style cues).\n2. Run the text_to_svg operation with a focused prompt that names the subject, color palette, and visual style (flat, line, filled).\n3. Optionally set n greater than 1 to generate several variations to choose from.\n4. Save the returned SVG file to the files store, or pass svgContent downstream for embedding.\n\n## Output\nReport the saved file location and the request id. When multiple variations are generated, list each so the user can pick one.', + }, + { + name: 'vectorize-raster-image', + description: 'Convert an uploaded raster image (PNG or JPG) into a clean editable SVG.', + content: + '# Vectorize Raster Image\n\nConvert a bitmap logo or graphic into a scalable SVG with Quiver image-to-SVG.\n\n## Steps\n1. Accept the raster image upload and pass it as the image input.\n2. Run the image_to_svg operation, optionally setting auto_crop and a target_size to tighten the output.\n3. Inspect svgContent for fidelity; rerun with adjusted instructions if details are lost.\n4. Save the SVG file for use in presentations, exports, or the web.\n\n## Output\nReturn the vectorized SVG file and confirm dimensions. Note any visual elements that did not vectorize cleanly.', + }, + { + name: 'create-data-diagram', + description: 'Generate an SVG diagram that visualizes structured data, then share it.', + content: + '# Create Data Diagram\n\nProduce a clean SVG diagram from structured data and attach it to a message.\n\n## Steps\n1. Read the structured data (for example, rows from a table) that should be visualized.\n2. Summarize the data into a precise prompt describing the diagram type and relationships.\n3. Run the text_to_svg operation to generate the diagram.\n4. Save the SVG file and attach it to the target channel or document.\n\n## Output\nShare the generated diagram file and a one-line description of what it depicts.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/railway.ts b/apps/sim/blocks/blocks/railway.ts index 66f3b6b1296..87085121dc9 100644 --- a/apps/sim/blocks/blocks/railway.ts +++ b/apps/sim/blocks/blocks/railway.ts @@ -713,4 +713,37 @@ export const RailwayBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'monitor-failed-deployments', + description: 'List recent Railway deployments, detect failures, and alert with a summary.', + content: + '# Monitor Failed Deployments\n\nWatch Railway deployments and surface failures fast.\n\n## Steps\n1. Run list_deployments for the target project, service, and environment.\n2. Identify deployments with a failed or crashed status from the returned list.\n3. Summarize each failure: service, environment, commit, and likely cause.\n4. Post an actionable alert (for example to Slack) with a link to the affected service.\n\n## Output\nReturn the count of failed deployments and a concise summary of each. If all healthy, report a clean status.', + }, + { + name: 'deploy-service', + description: 'Trigger a Railway service deployment for a given environment and commit.', + content: + '# Deploy Service\n\nTrigger a deployment of a Railway service.\n\n## Steps\n1. Identify the service id and environment id to deploy (use get_project to look them up if needed).\n2. Run deploy_service, optionally pinning a specific commitSha.\n3. Capture the returned deploymentId.\n4. Optionally poll list_deployments to confirm the deployment reaches a success state.\n\n## Output\nReport the deploymentId, target environment, and final status.', + }, + { + name: 'sync-environment-variables', + description: + 'Upsert Railway environment variables from a reference source and report changes.', + content: + '# Sync Environment Variables\n\nKeep Railway environment variables aligned with a reference list.\n\n## Steps\n1. Read the desired variable set (for example from a table) for each service.\n2. Run list_variables to capture the current state for the project, environment, and service.\n3. For each variable that is missing or differs, run upsert_variable. Use skipDeploys when batching multiple changes.\n4. Trigger a single deploy at the end if needed.\n\n## Output\nReturn a summary of every variable created or changed, grouped by service.', + }, + { + name: 'provision-preview-environment', + description: 'Create an ephemeral Railway environment, seed variables, and deploy it.', + content: + '# Provision Preview Environment\n\nSpin up a fresh Railway environment for a branch or pull request.\n\n## Steps\n1. Run create_environment for the project, optionally cloning from a source environment and marking it ephemeral.\n2. Upsert the required environment variables for the new environment.\n3. Run deploy_service to bring the preview online.\n4. Capture the deployment status and the preview URL.\n\n## Output\nReturn the new environment id and the live preview URL so it can be shared on the PR.', + }, + { + name: 'audit-project-inventory', + description: 'List every Railway project with services and environments for tracking.', + content: + '# Audit Project Inventory\n\nBuild a current inventory of Railway resources.\n\n## Steps\n1. Run list_projects, paginating with first and after until complete.\n2. For each project, run get_project to capture its services and environments.\n3. Optionally run list_project_members to record access.\n4. Compare against a prior snapshot to detect added or removed resources.\n\n## Output\nReturn the full inventory and a diff of any changes since the last run.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/rb2b.ts b/apps/sim/blocks/blocks/rb2b.ts index 3288a0c4fc7..56d1f8ee2f4 100644 --- a/apps/sim/blocks/blocks/rb2b.ts +++ b/apps/sim/blocks/blocks/rb2b.ts @@ -295,4 +295,24 @@ export const RB2BBlockMeta = { tags: ['sales', 'enrichment', 'automation'], }, ], + skills: [ + { + name: 'identify-website-visitor', + description: 'Resolve a visitor IP into a person and company profile for sales follow-up.', + content: + '# Identify Website Visitor\n\nTurn an anonymous visit into a named, enrichable lead.\n\n## Steps\n1. Take the visitor ip_address and run ip_to_company to resolve the firmographic match.\n2. Run ip_to_hem to obtain the hashed email identifier for the person.\n3. Run hem_to_business_profile and hem_to_best_linkedin to build a full contact profile.\n4. Score the lead by company fit and route high-intent matches to sales.\n\n## Output\nReturn the resolved company, person name, title, and LinkedIn. Flag whether the match clears your fit threshold.', + }, + { + name: 'enrich-linkedin-contact', + description: 'Enrich a LinkedIn profile with business email and phone for outreach.', + content: + '# Enrich LinkedIn Contact\n\nTurn a LinkedIn profile into reachable contact details.\n\n## Steps\n1. Provide the LinkedIn URL or slug; use linkedin_slug_search first if you only have a name.\n2. Run linkedin_to_business_profile to capture role and company.\n3. Run linkedin_to_best_personal_email and linkedin_to_mobile_phone for direct contact points.\n4. Push the enriched record into the CRM or an outreach sequence.\n\n## Output\nReturn the contact name, company, best email, and phone. Note any field that could not be resolved.', + }, + { + name: 'check-credit-balance', + description: 'Check the RB2B credit balance before running a batch of enrichment lookups.', + content: + '# Check Credit Balance\n\nVerify enrichment credits remain before a batch run.\n\n## Steps\n1. Run credit_check to read the current balance.\n2. Estimate the credits needed for the planned lookups.\n3. If the balance is insufficient, alert the team rather than starting a partial run.\n\n## Output\nReturn the remaining credit balance and whether the planned batch can proceed.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/rds.ts b/apps/sim/blocks/blocks/rds.ts index 1d08c25390b..ab9c68d3c59 100644 --- a/apps/sim/blocks/blocks/rds.ts +++ b/apps/sim/blocks/blocks/rds.ts @@ -557,4 +557,27 @@ export const RDSBlockMeta = { alsoIntegrations: ['google_bigquery'], }, ], + skills: [ + { + name: 'run-readonly-query', + description: + 'Run a parameterized SELECT against Amazon RDS via the Data API and return the rows.', + content: + '# Run Read-only Query\n\nQuery an RDS database through the Data API to answer a question.\n\n## Steps\n1. Write a SELECT statement that returns only the columns needed.\n2. Use parameters for any user-supplied values instead of string concatenation.\n3. Execute the statement and collect the result rows.\n\n## Output\nThe returned rows in a readable table plus a row count. If the result is large, summarize and note that it was limited.', + }, + { + name: 'lookup-record', + description: + 'Fetch a specific record from Amazon RDS by an identifier and return its fields.', + content: + '# Lookup Record\n\nRetrieve one row from an RDS table by a key.\n\n## Steps\n1. Identify the table and the unique identifier (id, email, order number).\n2. Run a parameterized SELECT filtered by that identifier.\n3. Return the matching row, or report that no record was found.\n\n## Output\nThe record fields if found, or a clear "not found" result. Do not invent field values.', + }, + { + name: 'insert-record', + description: + 'Insert a new row into an Amazon RDS table from provided field values via the Data API.', + content: + '# Insert Record\n\nWrite a new record into an RDS table through the Data API.\n\n## Steps\n1. Identify the target table and map the input values to its columns as key-value pairs.\n2. Run the insert operation with that data object.\n3. To load several rows, repeat the insert for each item, or use the Execute Raw SQL operation with a multi-row INSERT statement.\n\n## Output\nConfirm the table written to and how many rows were inserted. Flag any items skipped for missing required fields.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/reddit.ts b/apps/sim/blocks/blocks/reddit.ts index e7e741416da..c564c19d376 100644 --- a/apps/sim/blocks/blocks/reddit.ts +++ b/apps/sim/blocks/blocks/reddit.ts @@ -972,4 +972,32 @@ export const RedditBlockMeta = { tags: ['marketing', 'content'], }, ], + skills: [ + { + name: 'monitor-subreddit-mentions', + description: + 'Search a subreddit for brand or keyword mentions and summarize what people say.', + content: + '# Monitor Subreddit Mentions\n\nTrack what people say about a topic on Reddit.\n\n## Steps\n1. Run search with the brand or keyword query, scoped to the relevant subreddit when appropriate.\n2. For high-signal threads, run get_comments to pull the discussion.\n3. Summarize sentiment, recurring themes, and notable complaints or praise.\n4. Route urgent or negative threads to the right channel.\n\n## Output\nReturn a digest of top mentions with links, sentiment, and key takeaways.', + }, + { + name: 'surface-trending-posts', + description: + 'Pull top and controversial posts from a subreddit for a content or research brief.', + content: + '# Surface Trending Posts\n\nFind what is rising and contentious in a community.\n\n## Steps\n1. Run get_posts for the subreddit using a hot or top sort to capture momentum.\n2. Run get_controversial to surface divisive discussions.\n3. Read get_comments on the standouts for context.\n4. Cluster the posts into themes.\n\n## Output\nReturn a ranked brief of trending and controversial posts with titles, links, and a one-line takeaway each.', + }, + { + name: 'reply-to-mention', + description: 'Draft and post a helpful, on-brand reply to a Reddit post or comment.', + content: + '# Reply To Mention\n\nRespond to a relevant Reddit thread.\n\n## Steps\n1. Read the target post or comment with get_posts or get_comments for full context.\n2. Draft a concise, non-promotional reply that adds genuine value.\n3. Run reply to post it on the chosen thread.\n4. Optionally save the thread for later follow-up.\n\n## Output\nReturn the posted reply text and a link to the comment. Respect subreddit rules and avoid spammy self-promotion.', + }, + { + name: 'submit-announcement-post', + description: 'Submit a new post to a target subreddit for an announcement or launch.', + content: + '# Submit Announcement Post\n\nShare an announcement on Reddit.\n\n## Steps\n1. Confirm the target subreddit allows the post type and self-promotion rules.\n2. Run submit_post with a clear title and body tailored to the community.\n3. Capture the returned post id and link.\n4. Monitor early get_comments and respond to questions.\n\n## Output\nReturn the new post link and an initial engagement check.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/redis.ts b/apps/sim/blocks/blocks/redis.ts index 3bd05cecb84..8fe4c84639e 100644 --- a/apps/sim/blocks/blocks/redis.ts +++ b/apps/sim/blocks/blocks/redis.ts @@ -389,4 +389,30 @@ export const RedisBlockMeta = { tags: ['devops', 'automation'], }, ], + skills: [ + { + name: 'cache-with-expiry', + description: 'Cache a computed value in Redis with a TTL and read it back on later runs.', + content: + '# Cache With Expiry\n\nStore an expensive result in Redis so later runs reuse it.\n\n## Steps\n1. Run get on the cache key first; if a value is returned, use it and stop.\n2. On a miss, compute the value, then run set with an ex expiry in seconds.\n3. Use setnx instead of set when only the first writer should win.\n4. Return the value to the caller.\n\n## Output\nReport whether the result was a cache hit or a fresh computation, and the key TTL.', + }, + { + name: 'rate-limit-counter', + description: 'Track per-key request counts in Redis with a sliding expiry to enforce limits.', + content: + '# Rate Limit Counter\n\nEnforce a request budget using a Redis counter.\n\n## Steps\n1. Run incr on a counter key derived from the user or client id.\n2. If the returned count is 1, run expire to start the window.\n3. Compare the count to the allowed limit.\n4. Allow or reject the request based on the result.\n\n## Output\nReturn the current count, the limit, and whether the request is allowed. Include ttl for the reset time.', + }, + { + name: 'manage-session-data', + description: 'Store and refresh session context in a Redis hash keyed by token.', + content: + '# Manage Session Data\n\nKeep session state in a Redis hash and keep active sessions alive.\n\n## Steps\n1. On write, run hset to store session fields under the session key.\n2. On read, run hgetall by token to return the full session context.\n3. Run expire to refresh the TTL so active sessions do not lapse.\n4. Run delete on logout to clear the session.\n\n## Output\nReturn the session context and confirm the refreshed expiry, or confirm deletion on logout.', + }, + { + name: 'manage-work-queue', + description: 'Push jobs onto a Redis list and pop them for processing in order.', + content: + '# Manage Work Queue\n\nUse a Redis list as a simple job queue.\n\n## Steps\n1. Run rpush to enqueue a job payload onto the queue key.\n2. Run lpop to dequeue the next job for processing (FIFO).\n3. Check llen to monitor backlog depth.\n4. Use lrange to inspect pending jobs without removing them.\n\n## Output\nReturn the dequeued job, the remaining queue length, and processing status.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/reducto.ts b/apps/sim/blocks/blocks/reducto.ts index b696c1ea1a7..de47bba4318 100644 --- a/apps/sim/blocks/blocks/reducto.ts +++ b/apps/sim/blocks/blocks/reducto.ts @@ -301,4 +301,25 @@ export const ReductoBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'extract-document-text', + description: 'Parse an uploaded PDF into clean text for downstream summarizing or search.', + content: + '# Extract Document Text\n\nTurn a PDF into clean, structured text with Reducto.\n\n## Steps\n1. Pass the uploaded document (file or file path) to the parser.\n2. Optionally limit to specific pages by passing a comma-separated page list.\n3. Capture the extracted text and structure from the result.\n4. Pass the text downstream for summarizing, classification, or indexing.\n\n## Output\nReturn the extracted text and a brief note of the page count processed.', + }, + { + name: 'extract-form-fields', + description: 'Parse an intake form PDF and pull structured fields into a table or record.', + content: + '# Extract Form Fields\n\nLift structured fields out of a form PDF.\n\n## Steps\n1. Run the parser on the uploaded form document.\n2. From the parsed text, identify the target fields (for example name, date, amount, form type).\n3. Map the fields into a structured record and write them to a table.\n4. Route the record to the right reviewer based on form type.\n\n## Output\nReturn the extracted field record and confirm where it was stored or routed. Flag any field that could not be located.', + }, + { + name: 'extract-invoice-tables', + description: + 'Parse an invoice or financial PDF into structured line-item tables for AP automation.', + content: + '# Extract Invoice Tables\n\nPull line-item tables out of invoices, receipts, or statements with Reducto.\n\n## Steps\n1. Run the parser on the uploaded invoice or financial document.\n2. Set the table output format so tables come back in a structured, machine-readable shape.\n3. Limit to the relevant pages with a comma-separated page list when the document is long.\n4. Map header fields and line items into a record and write the rows to a table.\n\n## Output\nReturn the parsed line items and invoice totals. Flag any row or amount that could not be confidently extracted.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/resend.ts b/apps/sim/blocks/blocks/resend.ts index a4a431af74e..0875bc0c4c4 100644 --- a/apps/sim/blocks/blocks/resend.ts +++ b/apps/sim/blocks/blocks/resend.ts @@ -393,4 +393,24 @@ export const ResendBlockMeta = { tags: ['automation', 'communication', 'compliance'], }, ], + skills: [ + { + name: 'send-transactional-email', + description: 'Send a personalized transactional email and confirm delivery via Resend.', + content: + '# Send Transactional Email\n\nSend a one-off transactional email through Resend.\n\n## Steps\n1. Compose the recipient, from address, subject, and HTML or text body, filling in personalization fields.\n2. Run the send operation.\n3. Capture the returned email id.\n4. Optionally run get_email with the id to confirm the delivery status.\n\n## Output\nReturn the email id and delivery status. If sending fails, report the error reason.', + }, + { + name: 'add-contact-to-audience', + description: 'Create or update a Resend contact in an audience for marketing sends.', + content: + '# Add Contact To Audience\n\nKeep a Resend audience in sync with new contacts.\n\n## Steps\n1. Run list_contacts or get_contact to check whether the person already exists.\n2. If new, run create_contact with email and name fields and the subscribed state.\n3. If existing, run update_contact to refresh fields.\n4. Confirm the contact is in the correct audience.\n\n## Output\nReturn the contact id and whether it was created or updated.', + }, + { + name: 'handle-unsubscribe', + description: 'Mark a Resend contact as unsubscribed and send a confirmation email.', + content: + '# Handle Unsubscribe\n\nProcess an opt-out request cleanly.\n\n## Steps\n1. Run get_contact to look up the matching contact by email.\n2. Run update_contact to set unsubscribed to true.\n3. Log the opt-out reason for compliance records.\n4. Run the send operation to deliver a brief confirmation acknowledging the change.\n\n## Output\nConfirm the contact is unsubscribed and the acknowledgement email id.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/revenuecat.ts b/apps/sim/blocks/blocks/revenuecat.ts index a742136f927..8e249b2b487 100644 --- a/apps/sim/blocks/blocks/revenuecat.ts +++ b/apps/sim/blocks/blocks/revenuecat.ts @@ -561,4 +561,30 @@ export const RevenueCatBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'check-subscription-status', + description: 'Look up a customer in RevenueCat and report their active entitlements.', + content: + '# Check Subscription Status\n\nDetermine what a customer is entitled to right now.\n\n## Steps\n1. Run get_customer with the app user id.\n2. Inspect the returned entitlements for active grants and expiration dates.\n3. Determine whether the customer has the entitlement you are gating on.\n4. Return a clear allow or deny decision.\n\n## Output\nReturn the active entitlements, their expiration dates, and whether the gated feature should be unlocked.', + }, + { + name: 'grant-promotional-access', + description: 'Grant a promotional entitlement to a customer for support or a campaign.', + content: + '# Grant Promotional Access\n\nGive a customer temporary access via a promotional entitlement.\n\n## Steps\n1. Confirm the target app user id with get_customer.\n2. Run grant_entitlement with the entitlement identifier and duration.\n3. Verify the grant by re-checking get_customer.\n4. To reverse a grant later, run revoke_entitlement.\n\n## Output\nConfirm the granted entitlement, its duration, and the customer it was applied to.', + }, + { + name: 'process-subscription-refund', + description: 'Refund and revoke a Google Play subscription for a customer support request.', + content: + '# Process Subscription Refund\n\nHandle a refund request for a store subscription.\n\n## Steps\n1. Look up the customer with get_customer to find the relevant subscription.\n2. For Google Play, run refund_google_subscription with the store transaction id.\n3. If access should end immediately, run revoke_google_subscription.\n4. Log the action for the support record.\n\n## Output\nConfirm the refund and revocation status, and the affected customer and product.', + }, + { + name: 'sync-subscriber-attributes', + description: 'Update RevenueCat subscriber attributes to power targeting and analytics.', + content: + '# Sync Subscriber Attributes\n\nKeep RevenueCat subscriber attributes current.\n\n## Steps\n1. Gather the attributes to set (for example email, plan tier, or campaign source).\n2. Run update_subscriber_attributes for the app user id with the attribute map.\n3. Confirm the update with get_customer.\n\n## Output\nReturn the updated attributes and confirm they were applied to the subscriber.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/rippling.ts b/apps/sim/blocks/blocks/rippling.ts index 84a7c612d31..9a06b3c4cf0 100644 --- a/apps/sim/blocks/blocks/rippling.ts +++ b/apps/sim/blocks/blocks/rippling.ts @@ -1545,4 +1545,37 @@ export const RipplingBlockMeta = { tags: ['hr', 'reporting', 'enterprise'], }, ], + skills: [ + { + name: 'lookup-employee-profile', + description: 'Find a Rippling worker and return their role, department, and team details.', + content: + '# Lookup Employee Profile\n\nRetrieve a complete profile for an employee.\n\n## Steps\n1. Run list_workers filtered by name or attributes to find the worker, or list_users if you have a user id.\n2. Run get_worker for the full record once identified.\n3. Enrich with get_department, get_team, and get_title as needed for context.\n4. Assemble the profile.\n\n## Output\nReturn the worker name, title, department, team, and employment type. Note any field that is unavailable.', + }, + { + name: 'department-headcount-report', + description: 'Group Rippling workers by department and employment type to report headcount.', + content: + '# Department Headcount Report\n\nBuild a headcount snapshot across the org.\n\n## Steps\n1. Run list_departments to enumerate departments.\n2. Run list_workers and group by department and employment type.\n3. Compute headcount per group and compare against a prior snapshot for growth.\n4. Write a narrative summary of the changes.\n\n## Output\nReturn headcount per department and employment type, plus week-over-week change where available.', + }, + { + name: 'manage-department', + description: 'Create or update a department record in Rippling for an org change.', + content: + '# Manage Department\n\nKeep the Rippling org structure current.\n\n## Steps\n1. Run list_departments to check whether the department already exists.\n2. If new, run create_department with the name and parent details.\n3. If it exists, run update_department to adjust the record.\n4. Confirm with get_department.\n\n## Output\nReturn the department id and whether it was created or updated.', + }, + { + name: 'sync-custom-object-records', + description: + 'Push external data (training, licenses, assets) onto Rippling custom object records.', + content: + '# Sync Custom Object Records\n\nWrite product data onto Rippling profiles via custom objects.\n\n## Steps\n1. Run list_custom_objects to find the target object, then list_custom_object_fields to confirm its schema.\n2. Build the records to write (for example training completion dates, license assignments, or asset ids).\n3. Use create_custom_object_record or update_custom_object_record for single writes, or bulk_create_custom_object_records and bulk_update_custom_object_records for batches.\n4. Verify with query_custom_object_records or get_custom_object_record_by_external_id.\n\n## Output\nReturn the count of records created or updated and flag any that failed validation.', + }, + { + name: 'run-rippling-report', + description: 'Trigger a Rippling report run and retrieve the completed results.', + content: + '# Run Rippling Report\n\nGenerate and collect a Rippling report for downstream analysis.\n\n## Steps\n1. Run trigger_report_run for the target report id to start a run.\n2. Capture the returned run id.\n3. Poll get_report_run until the run completes.\n4. Pass the results downstream to a table or summary.\n\n## Output\nReturn the report run id, completion status, and a summary of the returned rows.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/rootly.ts b/apps/sim/blocks/blocks/rootly.ts index 1a2bbce7b4f..cb872ba5503 100644 --- a/apps/sim/blocks/blocks/rootly.ts +++ b/apps/sim/blocks/blocks/rootly.ts @@ -1849,4 +1849,38 @@ export const RootlyBlockMeta = { alsoIntegrations: ['langsmith'], }, ], + skills: [ + { + name: 'declare-incident', + description: 'Open a Rootly incident with the right severity, service, and team assigned.', + content: + '# Declare Incident\n\nSpin up a structured Rootly incident from an alert or report.\n\n## Steps\n1. Run list_severities, list_services, and list_teams to resolve the correct ids.\n2. Run create_incident with a clear title, summary, severity, affected service, and owning team.\n3. Capture the returned incident id.\n4. Add an opening timeline note with add_incident_event.\n\n## Output\nReturn the incident id, severity, assigned team, and a link. Confirm the opening event was logged.', + }, + { + name: 'post-incident-update', + description: 'Append a status update event to an active Rootly incident timeline.', + content: + '# Post Incident Update\n\nKeep an incident timeline current.\n\n## Steps\n1. Run get_incident to confirm the current state.\n2. Run add_incident_event with the update text (mitigation steps, customer impact, next checkpoint).\n3. Run update_incident if the severity or status has changed.\n\n## Output\nReturn the appended event and the current incident status.', + }, + { + name: 'triage-alerts', + description: + 'List open Rootly alerts, acknowledge them, and escalate to an incident if needed.', + content: + '# Triage Alerts\n\nWork through the open alert queue.\n\n## Steps\n1. Run list_alerts to pull open alerts.\n2. For each, run get_alert for detail and run acknowledge_alert to claim it.\n3. If an alert warrants response, run create_incident and link it.\n4. Run resolve_alert once the alert is handled.\n\n## Output\nReturn how many alerts were acknowledged, resolved, and escalated to incidents.', + }, + { + name: 'check-on-call', + description: + 'Look up who is currently on call across Rootly schedules and escalation policies.', + content: + '# Check On Call\n\nFind the right person to page right now.\n\n## Steps\n1. Run list_schedules to enumerate on-call schedules.\n2. Run list_on_calls to read the current rotation members.\n3. Cross-reference list_escalation_policies for the escalation path.\n\n## Output\nReturn the current on-call person per schedule and the escalation order.', + }, + { + name: 'track-action-items', + description: 'Create and list retrospective action items tied to a Rootly incident.', + content: + '# Track Action Items\n\nCapture and follow up on postmortem action items.\n\n## Steps\n1. Run get_incident to confirm the incident context.\n2. Run create_action_item for each follow-up with a clear owner and description.\n3. Run list_action_items to review open items for the incident.\n\n## Output\nReturn the created action items and the list of outstanding follow-ups.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/s3.ts b/apps/sim/blocks/blocks/s3.ts index ae2afbab9e1..c0b410880fc 100644 --- a/apps/sim/blocks/blocks/s3.ts +++ b/apps/sim/blocks/blocks/s3.ts @@ -483,4 +483,30 @@ export const S3BlockMeta = { tags: ['content', 'automation'], }, ], + skills: [ + { + name: 'upload-and-share-asset', + description: 'Upload a generated file to an S3 bucket and return its object URL.', + content: + '# Upload And Share Asset\n\nPublish a file to S3 and hand back a usable link.\n\n## Steps\n1. Take the generated image or document as the object body.\n2. Run put_object with the bucket, key, and content type.\n3. Construct or capture the resulting object URL.\n4. Write the link back to the originating record (for example a table row).\n\n## Output\nReturn the object key and URL. Note the bucket and whether the object is publicly accessible.', + }, + { + name: 'fetch-object-contents', + description: 'Download an object from S3 and pass its contents to downstream steps.', + content: + '# Fetch Object Contents\n\nRetrieve a file from S3 for processing.\n\n## Steps\n1. Identify the bucket and object key.\n2. Run get_object to download the file.\n3. Pass the contents downstream for parsing, summarizing, or transformation.\n\n## Output\nReturn the object contents (or a file reference) and confirm the source key.', + }, + { + name: 'list-bucket-objects', + description: 'List objects in an S3 bucket under a prefix for inventory or cleanup.', + content: + '# List Bucket Objects\n\nEnumerate what lives under an S3 prefix.\n\n## Steps\n1. Run list_objects with the bucket and an optional prefix to scope the listing.\n2. Page through results if the listing is truncated.\n3. Filter the keys by name, date, or size as needed.\n\n## Output\nReturn the matching object keys with sizes and last-modified dates.', + }, + { + name: 'archive-object', + description: 'Copy an S3 object to an archive location and delete the original.', + content: + '# Archive Object\n\nMove an object to an archive prefix or bucket.\n\n## Steps\n1. Run copy_object from the source key to the archive destination key.\n2. Verify the copy succeeded.\n3. Run delete_object on the original to complete the move.\n\n## Output\nConfirm the archived destination key and that the original was removed.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/salesforce.ts b/apps/sim/blocks/blocks/salesforce.ts index ae76c84ee2a..5b52d50929c 100644 --- a/apps/sim/blocks/blocks/salesforce.ts +++ b/apps/sim/blocks/blocks/salesforce.ts @@ -739,4 +739,37 @@ export const SalesforceBlockMeta = { tags: ['sales', 'crm', 'automation'], }, ], + skills: [ + { + name: 'capture-inbound-lead', + description: + 'Create or update a Salesforce lead from an inbound signal and assign follow-up.', + content: + '# Capture Inbound Lead\n\nGet an inbound lead into Salesforce cleanly.\n\n## Steps\n1. Run get_leads to check for an existing lead with the same email.\n2. If new, run create_lead with name, company, email, and source; otherwise run update_lead to enrich it.\n3. Run create_task to assign a follow-up to the owner.\n\n## Output\nReturn the lead id, whether it was created or updated, and the follow-up task id.', + }, + { + name: 'log-opportunity-update', + description: 'Advance a Salesforce opportunity stage and record the change for the account.', + content: + '# Log Opportunity Update\n\nKeep a deal current in Salesforce.\n\n## Steps\n1. Run get_opportunities to locate the deal.\n2. Run update_opportunity to set the new stage, amount, or close date.\n3. Run create_task to capture the next action.\n\n## Output\nReturn the opportunity id, its new stage, and the next-step task. Note if the stage moved to closed-won or closed-lost.', + }, + { + name: 'sync-account-contacts', + description: 'Pull a Salesforce account with its contacts for a 360 view.', + content: + '# Sync Account Contacts\n\nAssemble a full picture of an account.\n\n## Steps\n1. Run get_accounts to resolve the target account.\n2. Run get_contacts filtered to the account to list its people.\n3. Optionally run get_opportunities and get_cases for active deals and support context.\n\n## Output\nReturn the account, its contacts with roles, and a summary of open opportunities and cases.', + }, + { + name: 'create-support-case', + description: 'Open a Salesforce case for a customer issue and assign the owner.', + content: + '# Create Support Case\n\nFile a support case in Salesforce.\n\n## Steps\n1. Run get_contacts or get_accounts to link the case to the right record.\n2. Run create_case with subject, description, priority, and origin.\n3. Run create_task for the assigned owner if a follow-up is required.\n\n## Output\nReturn the case id, priority, and linked account or contact.', + }, + { + name: 'run-sales-report', + description: 'Run a Salesforce report and summarize the results for a stakeholder.', + content: + '# Run Sales Report\n\nPull live numbers from a Salesforce report.\n\n## Steps\n1. Run list_reports to find the report, or use a known report id.\n2. Run run_report to execute it and capture the result set.\n3. Summarize the key metrics and notable changes.\n\n## Output\nReturn the headline metrics and a short narrative of what the report shows.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sap_concur.ts b/apps/sim/blocks/blocks/sap_concur.ts index 223d6e35c55..48530bca500 100644 --- a/apps/sim/blocks/blocks/sap_concur.ts +++ b/apps/sim/blocks/blocks/sap_concur.ts @@ -1970,4 +1970,33 @@ export const SapConcurBlockMeta = { alsoIntegrations: ['microsoft_teams'], }, ], + skills: [ + { + name: 'review-expense-reports', + description: + 'List submitted SAP Concur expense reports, inspect line items, and flag policy exceptions.', + content: + '# Review Expense Reports\n\nSurface expense reports that need attention and check them against policy.\n\n## Steps\n1. Run List Expense Reports to pull recently submitted reports, or List Reports To Approve for items awaiting the current approver.\n2. For each report of interest, run Get Expense Report and List Expenses to read the individual line items, then List Exceptions to see Concur policy flags.\n3. Summarize totals, flagged line items, and any missing receipts.\n\n## Output\nReturn a per-report summary with the report ID, owner, total amount, and a list of policy exceptions or anomalies that warrant follow-up.', + }, + { + name: 'route-report-approval', + description: 'Approve or send back a submitted SAP Concur expense report after review.', + content: + '# Route Report Approval\n\nAct on an expense report once a review decision is made.\n\n## Steps\n1. Confirm the report ID and the decision.\n2. To approve, run Approve Expense Report. To return it for correction, run Send Back Expense Report with a clear comment explaining what must change.\n3. Optionally run Create Report Comment first to leave context for the submitter.\n\n## Output\nConfirm the report ID, the action taken (approved or sent back), and the comment provided so the decision is auditable.', + }, + { + name: 'capture-quick-expense', + description: + 'Create a quick expense in SAP Concur from a receipt, attaching the receipt image.', + content: + '# Capture Quick Expense\n\nLog an out-of-pocket expense quickly, with the receipt attached.\n\n## Steps\n1. If you have a receipt image, run Upload Receipt Image and keep the returned receipt ID, or use Create Quick Expense (With Image) to do both in one step.\n2. Run Create Quick Expense with the vendor, amount, currency, and transaction date.\n3. Verify the entry with Get Expense.\n\n## Output\nReport the created quick expense ID, the captured vendor and amount, and confirm the receipt image is attached.', + }, + { + name: 'manage-travel-requests', + description: + 'List and act on SAP Concur travel requests, moving them through the approval workflow.', + content: + '# Manage Travel Requests\n\nHandle pre-trip travel requests through their approval lifecycle.\n\n## Steps\n1. Run List Travel Requests to find pending requests, then Get Travel Request for full detail on a specific one.\n2. Review the expected expenses and any linked cash advance via Get Request Cash Advance.\n3. Run Move Travel Request (Workflow Action) to advance, approve, or send back the request based on the decision.\n\n## Output\nReturn the travel request ID, destination, estimated cost, and the workflow action applied so the trip approval state is clear.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sap_s4hana.ts b/apps/sim/blocks/blocks/sap_s4hana.ts index 0edef6d6e68..9ce4e1a46d2 100644 --- a/apps/sim/blocks/blocks/sap_s4hana.ts +++ b/apps/sim/blocks/blocks/sap_s4hana.ts @@ -1278,4 +1278,34 @@ export const SapS4HanaBlockMeta = { tags: ['finance', 'enterprise', 'automation'], }, ], + skills: [ + { + name: 'look-up-business-partner', + description: + 'Find a customer, supplier, or business partner in SAP S4HANA and return their master data.', + content: + '# Look Up Business Partner\n\nRetrieve master data for a customer, supplier, or general business partner.\n\n## Steps\n1. Run List Business Partners (or List Customers / List Suppliers for the typed view) with a filter on name, ID, or other criteria.\n2. Once the right record is identified, run Get Business Partner, Get Customer, or Get Supplier to pull full detail.\n3. Note key fields such as the partner ID, addresses, roles, and payment terms.\n\n## Output\nReturn the matched partner ID and the relevant master-data fields, and call out if no match or multiple matches were found.', + }, + { + name: 'check-sales-order-status', + description: + 'Look up a SAP S4HANA sales order and trace its related deliveries and billing documents.', + content: + '# Check Sales Order Status\n\nTrace a sales order from creation through delivery and billing.\n\n## Steps\n1. Run List Sales Orders to find the order, or Get Sales Order if you already have the order number.\n2. Run List Outbound Deliveries and List Billing Documents to find the delivery and invoice tied to that order.\n3. Get any specific delivery or billing document for line-level detail.\n\n## Output\nReturn the sales order number, its status, the linked delivery numbers, and billing document numbers so the order-to-cash state is clear.', + }, + { + name: 'create-purchase-requisition', + description: + 'Create a purchase requisition in SAP S4HANA via OData from supplied line-item details.', + content: + '# Create Purchase Requisition\n\nRaise a purchase requisition for procurement.\n\n## Steps\n1. Gather the requisition header and line items: material or product, quantity, plant, and delivery date.\n2. Optionally run List Products and Get Product to confirm material numbers before submitting.\n3. Run Create Purchase Requisition with the assembled payload.\n4. Confirm by running Get Purchase Requisition on the returned number.\n\n## Output\nReport the created purchase requisition number and a summary of its line items, and surface any OData validation error verbatim.', + }, + { + name: 'check-material-stock', + description: + 'Read current material stock and recent material documents for an item in SAP S4HANA.', + content: + '# Check Material Stock\n\nReport on-hand stock and recent inventory movements for a material.\n\n## Steps\n1. Run List Material Stock filtered by the material and plant to read current quantities.\n2. Run List Material Documents to see recent goods movements for that material, and Get Material Document for line detail on a specific posting.\n3. Compare on-hand stock against expected levels.\n\n## Output\nReturn the material number, plant, current stock quantity, and a short list of recent material movements with their document numbers.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/secrets_manager.ts b/apps/sim/blocks/blocks/secrets_manager.ts index 2855b8b41f4..823dac9aacb 100644 --- a/apps/sim/blocks/blocks/secrets_manager.ts +++ b/apps/sim/blocks/blocks/secrets_manager.ts @@ -353,4 +353,34 @@ export const SecretsManagerBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'rotate-secret-value', + description: + 'Update a stored secret in AWS Secrets Manager with a new value as part of a rotation flow. Use to push refreshed credentials without manual console edits.', + content: + '# Rotate Secret Value\n\nUpdate a secret with a new value.\n\n## Steps\n1. Confirm the target secret exists by getting it (do not log the returned value).\n2. Obtain the new secret value to store, as a string or JSON key/value payload.\n3. Update the secret with the new value, creating a new version.\n4. Verify by getting the secret and checking the updated version metadata, not the raw value.\n\n## Output\nConfirm the secret name and that a new version was created. Never print the secret value itself.', + }, + { + name: 'audit-secret-inventory', + description: + 'List secrets in AWS Secrets Manager and report metadata like last-changed and rotation status. Use for hygiene checks and finding stale secrets.', + content: + '# Audit Secret Inventory\n\nReport on the secrets that exist without exposing their values.\n\n## Steps\n1. List secrets to enumerate names, descriptions, and tags.\n2. For each secret of interest, read metadata such as last changed and last rotated dates.\n3. Flag secrets that are stale, undescribed, or appear unused.\n4. Summarize without ever fetching or printing secret values.\n\n## Output\nAn inventory summary: secret names with last-changed and rotation status, and stale or unrotated secrets called out. No secret values.', + }, + { + name: 'store-new-secret', + description: + 'Create a new secret in AWS Secrets Manager from a provided credential or generated value. Use to register app credentials, API keys, or DB passwords centrally.', + content: + '# Store New Secret\n\nRegister a new credential in Secrets Manager.\n\n## Steps\n1. Choose a clear hierarchical name for the secret, such as my-app/prod/db-password.\n2. Assemble the value to store — a plain string, or a JSON object of key/value pairs for structured credentials.\n3. Create the secret with that name, value, and a description of what it is and where it is used.\n4. Confirm creation by reading back the version metadata, not the value.\n\n## Output\nConfirm the secret name, ARN, and new version ID. Never echo the stored secret value back.', + }, + { + name: 'decommission-secret', + description: + 'Schedule deletion of a secret in AWS Secrets Manager with a recovery window so it can be restored if needed. Use to retire unused or rotated-out credentials safely.', + content: + '# Decommission Secret\n\nRetire a secret without permanently losing it immediately.\n\n## Steps\n1. Confirm the target secret and that nothing still depends on it.\n2. Schedule deletion with a recovery window (e.g. 30 days) so it can be restored during that period; reserve force delete for confirmed-orphaned secrets only.\n3. Record the scheduled deletion date.\n4. Re-list secrets to confirm it is marked for deletion.\n\n## Output\nConfirm the secret name and the scheduled deletion date, or that immediate deletion was requested. Do not print the secret value.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sendgrid.ts b/apps/sim/blocks/blocks/sendgrid.ts index f9b066f6f3a..5ecf9c623b5 100644 --- a/apps/sim/blocks/blocks/sendgrid.ts +++ b/apps/sim/blocks/blocks/sendgrid.ts @@ -756,4 +756,34 @@ export const SendGridBlockMeta = { tags: ['marketing', 'automation', 'sync'], }, ], + skills: [ + { + name: 'send-transactional-email', + description: + 'Send a transactional email through SendGrid, optionally using a dynamic template and variables.', + content: + '# Send Transactional Email\n\nSend a single transactional email (receipt, confirmation, password reset) through SendGrid.\n\n## Steps\n1. Set the verified From address and the recipient To address.\n2. For a one-off message, set the Subject and Content (choose HTML or plain text). For a templated message, set the Template ID and provide Dynamic Template Data as a JSON object whose keys match the template variables.\n3. Add CC, BCC, or Reply-To addresses if needed, and attach files via Attachments.\n4. Run the Send Mail operation and capture the returned message ID.\n\n## Output\nReport whether the send succeeded and include the SendGrid message ID for later delivery tracking and audit.', + }, + { + name: 'sync-contacts-to-list', + description: + 'Add or update marketing contacts and place them on a specific SendGrid list for a campaign segment.', + content: + '# Sync Contacts to List\n\nUpsert marketing contacts and assign them to a SendGrid list so a segment is ready to receive a campaign.\n\n## Steps\n1. If the target list does not exist, run Create List with a descriptive name and keep the returned list ID.\n2. Build a JSON array of contacts, each with at least an email plus optional first name, last name, and custom fields.\n3. Run Add Contacts to List with the list ID and the contacts array.\n4. Optionally run Remove Contacts from List to drop addresses that no longer qualify for the segment.\n\n## Output\nReport the list ID, the count of contacts added, and the job ID returned for the async upsert.', + }, + { + name: 'clean-contact-list', + description: + 'Search SendGrid marketing contacts for invalid or unwanted addresses and remove them.', + content: + '# Clean Contact List\n\nFind and remove low-quality marketing contacts using SendGrid Query Language.\n\n## Steps\n1. Run Search Contacts with an SGQL query that targets the unwanted records (for example addresses matching a bad domain or stale by created date).\n2. Collect the contact IDs from the results.\n3. Run Delete Contacts with the comma-separated contact IDs, or Remove Contacts from List to drop them only from a specific segment.\n4. Record what was removed for a cleanup report.\n\n## Output\nReport the search criteria used, the number of contacts found, and how many were deleted or removed from the list.', + }, + { + name: 'create-dynamic-template', + description: + 'Create a SendGrid dynamic template and an active version with HTML and a subject line.', + content: + '# Create Dynamic Template\n\nStand up a reusable SendGrid dynamic template for a recurring transactional message.\n\n## Steps\n1. Run Create Template with a descriptive name and the dynamic generation.\n2. Keep the returned template ID.\n3. Run Create Template Version against that template ID, supplying a version name, the Template Subject (Handlebars variables allowed), and the HTML content. Set the version active so it is used on send.\n4. Optionally supply plain text content as a fallback.\n\n## Output\nReport the template ID and version, and confirm the active version is ready to reference from Send Mail operations.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sentry.ts b/apps/sim/blocks/blocks/sentry.ts index 011f1c58bf3..612ed838c21 100644 --- a/apps/sim/blocks/blocks/sentry.ts +++ b/apps/sim/blocks/blocks/sentry.ts @@ -770,4 +770,34 @@ export const SentryBlockMeta = { alsoIntegrations: ['github', 'slack'], }, ], + skills: [ + { + name: 'triage-unresolved-errors', + description: + 'List unresolved Sentry issues, rank them by impact, and summarize the most urgent errors to fix.', + content: + '# Triage Unresolved Errors\n\nProduce a prioritized view of the Sentry errors that most need attention.\n\n## Steps\n1. Run List Issues with the query is:unresolved, sorting by frequency or user count and setting a stats period such as 24h or 7d.\n2. For the top issues, run Get Issue to pull the title, culprit, event count, and number of affected users.\n3. Rank by a blend of event volume, affected users, and recency.\n\n## Output\nReturn a ranked list of issues with their ID, title, event count, affected users, and a one-line recommendation for each. Link each issue so an engineer can open it directly.', + }, + { + name: 'resolve-or-assign-issue', + description: + 'Update a Sentry issue to change status, assign an owner, or bookmark it for follow-up.', + content: + '# Resolve or Assign Issue\n\nAct on a specific Sentry issue once a decision has been made.\n\n## Steps\n1. Identify the issue ID (from a triage step or a notification).\n2. Run Update Issue, setting the new status (resolved, ignored, or resolved in next release) as appropriate.\n3. To route ownership, set Assign To with a user ID or email. Bookmark or subscribe if the team wants to track it.\n\n## Output\nConfirm the issue ID, its new status, and the assignee, so the change is auditable.', + }, + { + name: 'investigate-issue-events', + description: + 'Pull the events behind a Sentry issue to inspect impacted users, environments, and context.', + content: + '# Investigate Issue Events\n\nDrill into the raw events for an issue to understand who and what is affected.\n\n## Steps\n1. Run List Events for the project, optionally filtering by an issue ID and an events search query (for example user.email or environment filters).\n2. Run Get Event on a representative event ID to retrieve the full payload: tags, breadcrumbs, request context, and stack trace.\n3. Group findings by environment, release, browser, or OS.\n\n## Output\nSummarize the affected environments and users, the common context across events, and the likely trigger, citing the specific event IDs examined.', + }, + { + name: 'track-release-and-deploy', + description: + 'Create a Sentry release for a version and mark a deploy to an environment for regression tracking.', + content: + '# Track Release and Deploy\n\nRegister a new version in Sentry so errors can be attributed to the release that introduced them.\n\n## Steps\n1. Run Create Release with the version string and the comma-separated project slugs. Add the git ref, release URL, and commits JSON if available so Sentry can associate suspect commits.\n2. Run Create Deploy with the same version and the target environment (for example production), including start and finish times.\n3. Optionally run List Releases afterward to confirm the version is registered.\n\n## Output\nReport the created release version, the deploy environment, and confirm both were recorded for regression monitoring.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/serper.ts b/apps/sim/blocks/blocks/serper.ts index 73b5d8d072e..0b8ab75c8b6 100644 --- a/apps/sim/blocks/blocks/serper.ts +++ b/apps/sim/blocks/blocks/serper.ts @@ -168,4 +168,34 @@ export const SerperBlockMeta = { tags: ['marketing', 'analysis'], }, ], + skills: [ + { + name: 'research-web-topic', + description: + 'Run a Serper web search on a topic and synthesize the top organic results into a sourced summary.', + content: + '# Research Web Topic\n\nGather current web results on a topic and turn them into a concise, sourced briefing.\n\n## Steps\n1. Run the search operation with a focused query. Set the country and language for the target audience and choose a result count (10 to 100) appropriate to the depth needed.\n2. Read the organic results, titles, snippets, and any answer box or knowledge graph data.\n3. Synthesize the findings, noting agreement and disagreement across sources.\n\n## Output\nReturn a short summary of what the web says about the topic, each key claim linked to the result URL it came from.', + }, + { + name: 'monitor-news-mentions', + description: + 'Search recent news for a brand, person, or topic via Serper and summarize the coverage.', + content: + '# Monitor News Mentions\n\nTrack what the news is saying about a brand, competitor, person, or topic.\n\n## Steps\n1. Run the news operation with the entity or topic as the query, setting country and language to scope the coverage.\n2. Collect the headlines, sources, publish dates, and snippets.\n3. Group the coverage by sentiment or theme and highlight the most recent and most prominent items.\n\n## Output\nReturn a dated list of news items with source and headline, plus a short overall read on tone and notable developments.', + }, + { + name: 'compare-regional-rankings', + description: + 'Run the same Serper query across multiple regions to compare search rankings by geography.', + content: + '# Compare Regional Rankings\n\nSee how search results differ for the same query across countries.\n\n## Steps\n1. Pick the target keyword and the set of countries to compare.\n2. Run the search operation once per country, varying only the country (and language where relevant), keeping the result count consistent.\n3. Line up the top organic results per region and note which domains rank where.\n\n## Output\nReturn a per-region ranking comparison for the keyword, calling out domains that rank strongly in some regions but not others.', + }, + { + name: 'find-local-businesses', + description: + 'Use the Serper places operation to find local businesses for a query and area, and rank them.', + content: + '# Find Local Businesses\n\nPull Google Maps style local results for a query in a target area.\n\n## Steps\n1. Run the places operation with a query that includes the business type and location (for example coffee shops in Seattle), setting the country and language to scope results.\n2. Read each place result: name, address, rating, review count, category, and phone or website where present.\n3. Rank or filter the results by rating, review volume, or proximity to the target area.\n\n## Output\nReturn a ranked list of local businesses with name, address, rating, and review count, noting the top candidates for the query.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/servicenow.ts b/apps/sim/blocks/blocks/servicenow.ts index e79a854d03e..2d05c2c36ea 100644 --- a/apps/sim/blocks/blocks/servicenow.ts +++ b/apps/sim/blocks/blocks/servicenow.ts @@ -350,4 +350,27 @@ export const ServiceNowBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'create-incident', + description: + 'Create a new ServiceNow incident record with the right category, priority, and description.', + content: + '# Create Incident\n\nFile a new ServiceNow incident from a reported issue.\n\n## Steps\n1. Use the Create Record operation against the incident table.\n2. Populate the field values: a clear short description, the longer description, category, and priority or impact and urgency.\n3. Set caller or assignment group fields when known.\n\n## Output\nReturn the created record sys_id and incident number so the reporter can track it, and echo the category and priority that were set.', + }, + { + name: 'search-records', + description: + 'Query a ServiceNow table for records matching a condition and return the matching rows.', + content: + '# Search Records\n\nFind records in any ServiceNow table that match a condition.\n\n## Steps\n1. Use the Read Records operation against the target table (for example incident, change_request, or sc_task).\n2. Provide an encoded query to filter (for example active incidents in a category) and limit the number of rows returned.\n3. Choose the display-value setting so returned fields are human-readable rather than raw sys_ids when needed.\n\n## Output\nReturn the matched records with their key fields and sys_ids, and report how many matched the query.', + }, + { + name: 'update-record-status', + description: + 'Update fields on an existing ServiceNow record, such as state, assignment, or work notes.', + content: + '# Update Record Status\n\nModify an existing ServiceNow record once a decision or action is taken.\n\n## Steps\n1. Identify the record by its sys_id (from a search step or a notification).\n2. Use the Update Record operation against the correct table, supplying only the fields to change such as state, assigned_to, or work_notes.\n3. Confirm the change by reading the record back.\n\n## Output\nConfirm the record number, the fields that changed, and their new values so the update is auditable.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/ses.ts b/apps/sim/blocks/blocks/ses.ts index fa35d5c7f4f..cde2a20589e 100644 --- a/apps/sim/blocks/blocks/ses.ts +++ b/apps/sim/blocks/blocks/ses.ts @@ -567,4 +567,34 @@ export const SESBlockMeta = { tags: ['marketing', 'automation', 'content'], }, ], + skills: [ + { + name: 'send-notification-email', + description: + 'Send a transactional email through AWS SES to one or more recipients. Use for alerts, confirmations, and one-off notifications from a workflow.', + content: + '# Send Notification Email\n\nSend a transactional email via SES.\n\n## Steps\n1. Determine the verified sender identity, the recipients, subject, and body.\n2. Choose a plain-text or HTML body to match the message.\n3. Send the email, including reply-to or CC recipients if needed.\n4. Confirm the send succeeded and capture the message ID.\n\n## Output\nReport the SES message ID and the recipients. If the send was rejected, surface the SES error (for example, an unverified sender or sandbox restriction).', + }, + { + name: 'send-templated-campaign', + description: + 'Send a templated SES email to many recipients with per-recipient personalization. Use for newsletters, onboarding sequences, and bulk notifications.', + content: + "# Send Templated Campaign\n\nSend personalized emails using an SES template.\n\n## Steps\n1. Confirm the template exists with get template, or create it first.\n2. Assemble the recipient list with each recipient's template data for personalization.\n3. Use send bulk email for many recipients, or send templated email for a single message.\n4. Collect per-recipient send status.\n\n## Output\nReport how many messages were accepted versus failed, with message IDs and the reason for any failures.", + }, + { + name: 'manage-email-templates', + description: + 'Create, fetch, list, and delete reusable email templates in AWS SES. Use to maintain a consistent, version-controlled template library.', + content: + '# Manage Email Templates\n\nMaintain the SES template library.\n\n## Steps\n1. To add a template, create it with a name, subject, and HTML and text parts using placeholder variables.\n2. To review, get a template by name or list templates.\n3. To retire one, delete the template by name.\n4. Keep template names descriptive so they are easy to reference when sending.\n\n## Output\nReport the template name affected and the action taken, or the template contents for a fetch.', + }, + { + name: 'check-sending-health', + description: + 'Inspect AWS SES account sending limits, quota usage, and verified identities. Use to confirm capacity and deliverability readiness before a send.', + content: + '# Check Sending Health\n\nVerify SES is ready to send.\n\n## Steps\n1. Get the account to read the sending quota, send rate, and whether the account is out of the sandbox.\n2. List identities to confirm the intended sender domain or address is verified.\n3. Compare planned volume against the remaining 24-hour quota.\n4. Flag any blockers — sandbox mode, unverified senders, or quota nearly exhausted.\n\n## Output\nReport sending enabled status, quota used versus max, and any unverified identities that would block the send.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sharepoint.ts b/apps/sim/blocks/blocks/sharepoint.ts index 02b7b980c5e..a0523adcd47 100644 --- a/apps/sim/blocks/blocks/sharepoint.ts +++ b/apps/sim/blocks/blocks/sharepoint.ts @@ -1124,4 +1124,31 @@ export const SharepointBlockMeta = { alsoIntegrations: ['confluence'], }, ], + skills: [ + { + name: 'publish-site-page', + description: 'Create a new SharePoint page on a site with a title and content body.', + content: + '# Publish Site Page\n\nCreate a new page on a SharePoint site, for example an announcement or knowledge article.\n\n## Steps\n1. Run List Sites to find the target site and note its identifier.\n2. Run Create Page on that site with a clear title and the page content body.\n3. Optionally run Read Page afterward to confirm the page was created as intended.\n\n## Output\nReturn the created page title and its URL or identifier so the page can be shared.', + }, + { + name: 'append-list-items', + description: + 'Add rows to a SharePoint list, creating the list first if it does not yet exist.', + content: + '# Append List Items\n\nWrite structured rows into a SharePoint list.\n\n## Steps\n1. Run List Sites to locate the site, then Read List to confirm the target list and its column schema.\n2. If the list does not exist, run Create List with the needed columns.\n3. Run Add List Items with the field values mapped to the list columns.\n\n## Output\nReturn the list name and the number of items added, and confirm the field values matched the list schema.', + }, + { + name: 'read-list-data', + description: 'Read items from a SharePoint list and summarize the rows for downstream use.', + content: + '# Read List Data\n\nPull the contents of a SharePoint list into the workflow.\n\n## Steps\n1. Run List Sites to find the site, then Read List against the target list.\n2. Inspect the returned items and their column values.\n3. Filter or summarize the rows as needed for the task.\n\n## Output\nReturn the list items with their relevant column values and a count of rows read.', + }, + { + name: 'upload-file-to-site', + description: 'Upload a file to a SharePoint site document library from a previous block.', + content: + '# Upload File to Site\n\nStore a file in a SharePoint document library.\n\n## Steps\n1. Run List Sites to identify the destination site.\n2. Provide the file from a previous block and run Upload File to the target site library.\n3. Confirm the upload completed.\n\n## Output\nReturn the uploaded file name and its location on the SharePoint site.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/shopify.ts b/apps/sim/blocks/blocks/shopify.ts index 0dbe3305df5..b4978cbb188 100644 --- a/apps/sim/blocks/blocks/shopify.ts +++ b/apps/sim/blocks/blocks/shopify.ts @@ -1102,4 +1102,37 @@ export const ShopifyBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'create-product-listing', + description: 'Create a new Shopify product with title, description, status, and variants.', + content: + '# Create Product Listing\n\nAdd a new product to the Shopify store.\n\n## Steps\n1. Run Create Product with the title, body description, vendor, and product type.\n2. Set the status (active, draft, or archived) so the product publishes only when ready.\n3. Verify with Get Product on the returned product ID.\n\n## Output\nReturn the new product ID, title, and status, and confirm the listing was created as draft or active as intended.', + }, + { + name: 'process-recent-orders', + description: + 'List recent Shopify orders and summarize them by status, value, or fulfillment need.', + content: + '# Process Recent Orders\n\nReview the latest orders to triage fulfillment and flag anything unusual.\n\n## Steps\n1. Run List Orders filtered by status (open, closed, cancelled, or any) and a recent time window.\n2. For orders needing detail, run Get Order to read line items, customer, and shipping address.\n3. Group orders by fulfillment status and total value.\n\n## Output\nReturn a summary of recent orders with their order numbers, totals, and status, highlighting any that need immediate fulfillment or review.', + }, + { + name: 'fulfill-order', + description: 'Create a fulfillment for a Shopify order and update its status.', + content: + '# Fulfill Order\n\nMark an order as fulfilled once it has shipped.\n\n## Steps\n1. Run Get Order to confirm the order and its line items, and List Locations to identify the fulfilling location.\n2. Run Create Fulfillment for the order, supplying the location and tracking details if available.\n3. Optionally run Update Order to record any notes.\n\n## Output\nConfirm the order number, the fulfillment created, and any tracking number supplied.', + }, + { + name: 'adjust-inventory', + description: 'Check and adjust Shopify inventory levels for an item at a location.', + content: + '# Adjust Inventory\n\nReconcile stock levels for an inventory item.\n\n## Steps\n1. Run List Inventory Items and List Locations to identify the item and the location.\n2. Run Get Inventory Level to read the current available quantity.\n3. Run Adjust Inventory with the delta needed to reach the correct count.\n\n## Output\nReport the inventory item, the location, the previous and new quantities, and the adjustment applied.', + }, + { + name: 'manage-customer-record', + description: 'Create, look up, or update a Shopify customer record.', + content: + '# Manage Customer Record\n\nMaintain a customer profile in Shopify.\n\n## Steps\n1. To find an existing customer, run List Customers with a filter or Get Customer by ID.\n2. To add a new one, run Create Customer with name, email, and any tags.\n3. To change details, run Update Customer with only the fields to modify.\n\n## Output\nReturn the customer ID, name, and email, and note whether the record was created, found, or updated.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/similarweb.ts b/apps/sim/blocks/blocks/similarweb.ts index 2202418611f..d90e0bab764 100644 --- a/apps/sim/blocks/blocks/similarweb.ts +++ b/apps/sim/blocks/blocks/similarweb.ts @@ -270,4 +270,27 @@ export const SimilarwebBlockMeta = { tags: ['sales', 'research', 'analysis'], }, ], + skills: [ + { + name: 'profile-website-traffic', + description: + 'Pull a Similarweb website overview and traffic metrics for a domain and summarize its scale.', + content: + '# Profile Website Traffic\n\nBuild a quick traffic profile for a single domain.\n\n## Steps\n1. Run Website Overview for the domain to get a high-level snapshot.\n2. Run Traffic Visits, Bounce Rate, Pages Per Visit, and Visit Duration for deeper engagement metrics, setting the country (or worldwide) to scope the data.\n3. Interpret the numbers together: high visits with a low bounce rate and long duration indicates strong engagement.\n\n## Output\nReturn a concise profile of the domain: estimated monthly visits, bounce rate, pages per visit, and average visit duration, with a one-line read on overall traffic health.', + }, + { + name: 'compare-competitor-domains', + description: + 'Pull Similarweb traffic metrics for several domains and rank them for a competitive view.', + content: + '# Compare Competitor Domains\n\nBenchmark a set of competing domains on traffic and engagement.\n\n## Steps\n1. For each domain, run Website Overview and Traffic Visits using the same country scope so the numbers are comparable.\n2. Optionally add Bounce Rate and Pages Per Visit for an engagement dimension.\n3. Rank the domains by visits and engagement.\n\n## Output\nReturn a ranked table of the domains with their visits, bounce rate, and engagement metrics, and a short read on which competitor leads.', + }, + { + name: 'score-prospect-domains', + description: + 'Score a list of prospect domains by Similarweb traffic size to prioritize outreach.', + content: + '# Score Prospect Domains\n\nPrioritize sales prospects by the size of their web traffic.\n\n## Steps\n1. For each prospect domain, run Website Overview and Traffic Visits in the relevant region.\n2. Assign a score based on monthly visits and any visible growth trend.\n3. Sort the prospects from highest to lowest score.\n\n## Output\nReturn the prospect domains ranked by score, each with its estimated monthly visits, so the sales team can prioritize the biggest-traffic targets.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sixtyfour.ts b/apps/sim/blocks/blocks/sixtyfour.ts index 475258eec5f..989bfd01a0b 100644 --- a/apps/sim/blocks/blocks/sixtyfour.ts +++ b/apps/sim/blocks/blocks/sixtyfour.ts @@ -369,4 +369,26 @@ export const SixtyfourBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'enrich-lead', + description: + 'Enrich a single lead with Sixtyfour AI research to fill in role, company, and contact context.', + content: + '# Enrich Lead\n\nTurn a thin lead record into a researched profile.\n\n## Steps\n1. Run Enrich Lead with whatever you know about the person: name, company, email, or LinkedIn.\n2. Request only the fields you need to keep credit usage down.\n3. Review the returned profile: title, seniority, company, and any social or contact data.\n\n## Output\nReturn the enriched lead profile with the discovered role, company, and context, and note any fields the research could not resolve.', + }, + { + name: 'find-contact-details', + description: 'Find a verified email or phone number for a prospect using Sixtyfour AI.', + content: + '# Find Contact Details\n\nLocate a reachable email or phone number for a prospect.\n\n## Steps\n1. Provide the person identity you have: name plus company or domain.\n2. Run Find Email to discover a work email, or Find Phone for a phone number. Choose the professional or personal type as appropriate.\n3. Validate that the result matches the intended person before using it.\n\n## Output\nReturn the discovered email or phone number with its type, and clearly state if no verified contact could be found.', + }, + { + name: 'enrich-company', + description: + 'Research a company with Sixtyfour AI to build a firmographic and account-context profile.', + content: + '# Enrich Company\n\nBuild an account profile for a target company.\n\n## Steps\n1. Run Enrich Company with the company name or domain.\n2. Request the firmographic fields you need: industry, size, location, funding, and technologies in use.\n3. Use the result to qualify the account against your ideal customer profile.\n\n## Output\nReturn the company profile with industry, size, location, and notable signals, plus a short note on how well it fits the target profile.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index 129ba3a6d0b..7df1cb771b0 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -2060,4 +2060,33 @@ export const SlackBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'daily-standup-summary', + description: + 'Read a standup channel and post a structured recap of progress, plans, and blockers.', + content: + '# Daily Standup Summary\n\nRead the messages posted in the standup channel since the last working day and produce a concise team recap.\n\n## Steps\n1. Collect every standup update in the channel from the relevant window (skip bot and off-topic messages).\n2. Group the content into three sections:\n - **Done** — what was completed.\n - **Today** — what each person plans to work on.\n - **Blockers** — anything waiting on someone else, with the owner @-mentioned.\n3. Call out anyone who did not post an update.\n\n## Output\nPost a single threaded message with the three sections as bullet lists. Keep each bullet to one line. Lead with blockers if any exist so they are not missed.', + }, + { + name: 'channel-catch-up', + description: 'Summarize what happened in a busy Slack channel so you can catch up fast.', + content: + '# Channel Catch-Up\n\nSummarize recent activity in a Slack channel for someone who has been away.\n\n## Steps\n1. Pull messages from the requested time range (default: since the user was last active, or the last 24 hours).\n2. Cluster the conversation into topics or threads rather than listing messages chronologically.\n3. For each topic, capture: the gist, any decision reached, and open questions still unanswered.\n\n## Output\n- A 1-sentence TL;DR.\n- A bulleted list of topics, each with **Decision:** and **Open:** lines where relevant.\n- A final "Needs your input" list of items where the user was @-mentioned or a question is unresolved.\nLink to the source thread for each topic.', + }, + { + name: 'slack-question-responder', + description: + 'Watch a channel for questions and draft sourced, in-thread answers from your knowledge base.', + content: + '# Slack Question Responder\n\nMonitor a support or help channel and answer incoming questions.\n\n## Steps\n1. Detect when a message is a genuine question (ends in a question mark, asks "how/where/can someone", or is a help request).\n2. Search the connected knowledge base for the answer.\n3. If a confident answer exists, draft a concise reply in the thread with the answer and a citation/link to the source.\n4. If no confident answer exists, do not guess — post a short note that a human should help, and @-mention the channel owner.\n\n## Guidance\n- Always reply in-thread, never in the main channel.\n- Keep answers to 2–4 sentences plus the source link.\n- Never fabricate links or policy.', + }, + { + name: 'escalate-urgent-messages', + description: + 'Scan a channel for urgent or at-risk messages and surface them to the right owner.', + content: + '# Escalate Urgent Messages\n\nTriage a channel for messages that need fast attention.\n\n## Steps\n1. Review recent messages and classify each as **Urgent**, **Today**, or **FYI** based on signals like "blocked", "down", "ASAP", customer impact, or an unanswered direct ask.\n2. For Urgent items, identify the most likely owner from the channel topic or message context.\n3. Skip resolved threads (those with a ✅ reaction or a clear answer).\n\n## Output\nPost a short escalation summary listing only Urgent and Today items: each as a one-line description, an @-mention of the owner, and a link to the message. If nothing is urgent, say so in one line.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sqs.ts b/apps/sim/blocks/blocks/sqs.ts index 0bb3a067580..05df3c5fd37 100644 --- a/apps/sim/blocks/blocks/sqs.ts +++ b/apps/sim/blocks/blocks/sqs.ts @@ -225,4 +225,20 @@ export const SQSBlockMeta = { tags: ['devops', 'automation', 'infrastructure'], }, ], + skills: [ + { + name: 'enqueue-job-message', + description: + 'Send a structured job message to an Amazon SQS queue to hand off background work.', + content: + '# Enqueue Job Message\n\nPublish a task onto an SQS queue for a worker to process asynchronously.\n\n## Steps\n1. Identify the target queue URL.\n2. Build the message body as JSON describing the job (type, payload, identifiers).\n3. For a FIFO queue, set the message group and deduplication IDs.\n4. Send the message.\n\n## Output\nConfirm the message was sent with its message ID and the queue it was placed on.', + }, + { + name: 'send-ordered-fifo-message', + description: + 'Send a message to an Amazon SQS FIFO queue with a message group ID and deduplication ID for ordered, exactly-once delivery.', + content: + '# Send Ordered FIFO Message\n\nDispatch a message to a FIFO queue when ordering within a stream and de-duplication matter.\n\n## Steps\n1. Identify the FIFO queue URL.\n2. Build the JSON message body.\n3. Set the message group ID so messages in the same group stay ordered, and set a deduplication ID to prevent duplicate sends.\n4. Send the message.\n\n## Output\nConfirm the message was sent with its message ID, group ID, and the queue it was placed on.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/stagehand.ts b/apps/sim/blocks/blocks/stagehand.ts index 83c3316d71d..08446264f16 100644 --- a/apps/sim/blocks/blocks/stagehand.ts +++ b/apps/sim/blocks/blocks/stagehand.ts @@ -490,4 +490,27 @@ export const StagehandBlockMeta = { tags: ['automation', 'research', 'agentic'], }, ], + skills: [ + { + name: 'extract-structured-data', + description: + 'Use Stagehand to extract structured fields from a web page into a typed result.', + content: + '# Extract Structured Data\n\nPull clean, structured data off a single web page.\n\n## Steps\n1. Run the Extract Data operation with the target URL.\n2. Describe exactly what to extract and the shape you want (for example product name, price, and availability), so Stagehand returns typed fields rather than raw HTML.\n3. Choose the LLM provider for the extraction.\n\n## Output\nReturn the extracted fields as a structured object, and note any field the page did not contain so downstream steps can handle gaps.', + }, + { + name: 'run-browser-agent-task', + description: + 'Hand Stagehand a natural-language goal and let its agent navigate and act on a site autonomously.', + content: + '# Run Browser Agent Task\n\nDelegate a multi-step web task to the Stagehand agent.\n\n## Steps\n1. Run the Run Agent operation with a clear natural-language goal (for example find the latest pricing on a vendor site and capture it).\n2. Provide the starting URL and pick the execution mode (DOM, hybrid, or CUA) and the LLM provider appropriate to the task.\n3. Let the agent navigate, click, and read pages to complete the goal.\n\n## Output\nReturn the agent result, the key data it captured, and any screenshots, plus a short note if the goal could not be fully completed.', + }, + { + name: 'monitor-page-for-changes', + description: + 'Periodically extract a value from a web page with Stagehand and report when it changes.', + content: + '# Monitor Page for Changes\n\nWatch a specific value on a web page over time.\n\n## Steps\n1. Run the Extract Data operation against the target URL, extracting just the value to watch (price, stock status, headline).\n2. Compare the extracted value against the last known value stored from a previous run.\n3. Decide whether the value changed beyond a meaningful threshold.\n\n## Output\nReport the current extracted value, whether it changed since the last check, and the old and new values when a change is detected.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/stripe.ts b/apps/sim/blocks/blocks/stripe.ts index 0a1f11f86d2..57440514dfa 100644 --- a/apps/sim/blocks/blocks/stripe.ts +++ b/apps/sim/blocks/blocks/stripe.ts @@ -917,4 +917,32 @@ export const StripeBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'collect-payment', + description: + 'Create and confirm a Stripe payment intent to collect a charge from a customer.', + content: + '# Collect Payment\n\nCharge a customer by creating and confirming a payment intent.\n\n## Steps\n1. Run Create Payment Intent with the amount, currency, and customer.\n2. Confirm the intent with Confirm Payment Intent, or Capture Payment Intent if it was created for manual capture.\n3. If a charge needs to be aborted, run Cancel Payment Intent instead.\n\n## Output\nReturn the payment intent ID, its status (succeeded, requires action, or canceled), and the captured amount.', + }, + { + name: 'manage-subscription', + description: 'Create, update, pause, or cancel a Stripe subscription for a customer.', + content: + '# Manage Subscription\n\nHandle the lifecycle of a recurring subscription.\n\n## Steps\n1. To start a subscription, run Create Subscription with the customer and price items.\n2. To change a plan, run Update Subscription with the new items. To pause and later restart, use Cancel Subscription or Resume Subscription as appropriate.\n3. Confirm the current state with Retrieve Subscription.\n\n## Output\nReturn the subscription ID, its status, current period end, and the plan items, and note exactly what changed.', + }, + { + name: 'issue-invoice', + description: 'Create, finalize, and send a Stripe invoice to a customer, then track payment.', + content: + '# Issue Invoice\n\nBill a customer with a Stripe invoice.\n\n## Steps\n1. Run Create Invoice for the customer with the line items.\n2. Run Finalize Invoice to lock it, then Send Invoice to deliver it to the customer.\n3. Track payment with Retrieve Invoice, or run Pay Invoice to charge a saved payment method. Use Void Invoice to cancel an unpaid invoice.\n\n## Output\nReturn the invoice ID, its status (draft, open, paid, or void), the amount due, and the hosted invoice URL when available.', + }, + { + name: 'find-customer-activity', + description: + 'Look up a Stripe customer and search their charges and payments for a financial summary.', + content: + '# Find Customer Activity\n\nBuild a payment history view for a single customer.\n\n## Steps\n1. Run Search Customers or Retrieve Customer to identify the customer and their ID.\n2. Run Search Charges or List Charges filtered to that customer to pull their transactions.\n3. Optionally run Search Payment Intents and List Invoices for a complete picture.\n\n## Output\nReturn the customer ID and email plus a summary of their charges and invoices, including total amount, successful versus failed payments, and any refunds.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/sts.ts b/apps/sim/blocks/blocks/sts.ts index 7e797504b3b..eee90522176 100644 --- a/apps/sim/blocks/blocks/sts.ts +++ b/apps/sim/blocks/blocks/sts.ts @@ -319,4 +319,34 @@ export const STSBlockMeta = { alsoIntegrations: ['identity_center', 'slack'], }, ], + skills: [ + { + name: 'assume-cross-account-role', + description: + 'Call AWS STS to assume a role and obtain temporary credentials for a target account. Use for cross-account access in a workflow.', + content: + '# Assume Cross-Account Role\n\nObtain temporary credentials by assuming an IAM role.\n\n## Steps\n1. Identify the role ARN to assume and a descriptive session name.\n2. Set the session duration and any external ID required by the trust policy.\n3. Call assume role to receive temporary access key, secret key, and session token.\n4. Pass the temporary credentials to the downstream step that needs cross-account access.\n\n## Output\nConfirm the assumed role ARN and credential expiration. Never print the secret access key or session token in plain logs.', + }, + { + name: 'verify-caller-identity', + description: + 'Use AWS STS get caller identity to confirm which account, user, or role the current credentials resolve to. Use to validate setup and debug auth issues.', + content: + '# Verify Caller Identity\n\nConfirm which AWS identity the workflow is operating as.\n\n## Steps\n1. Call get caller identity with the active credentials.\n2. Read the returned account ID, user ID, and principal ARN.\n3. Compare against the expected account and role for the task.\n4. If it does not match, flag a likely credential or assume-role misconfiguration.\n\n## Output\nReport the account ID and ARN of the active identity, and whether it matches the expected principal.', + }, + { + name: 'mint-mfa-session-token', + description: + 'Use AWS STS to mint short-lived session credentials, optionally backed by an MFA token, for IAM-user workflows that require MFA. Use for time-boxed elevated sessions.', + content: + '# Mint MFA Session Token\n\nIssue temporary credentials, optionally enforcing MFA.\n\n## Steps\n1. Decide the session duration the downstream task needs.\n2. If MFA is required, supply the MFA device serial number and the current token code.\n3. Call get session token to receive a temporary access key, secret key, and session token.\n4. Hand the temporary credentials to the step that needs them and let them expire naturally.\n\n## Output\nConfirm that a session token was issued and its expiration time. Never print the secret access key or session token value.', + }, + { + name: 'identify-access-key-owner', + description: + 'Use AWS STS get access key info to resolve which account an access key ID belongs to. Use for incident triage of leaked or unexpected keys.', + content: + '# Identify Access Key Owner\n\nFind out which account owns an access key ID.\n\n## Steps\n1. Take the access key ID under investigation (for example, one found in a leak or an unexpected log).\n2. Call get access key info to resolve the owning AWS account ID.\n3. Compare the account against your known and expected accounts.\n4. If it belongs to an unexpected account, escalate for investigation.\n\n## Output\nReport the access key ID (never the secret) and its owning account ID, plus whether that account is expected.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/supabase.ts b/apps/sim/blocks/blocks/supabase.ts index 3065e74e33f..632af3b67c7 100644 --- a/apps/sim/blocks/blocks/supabase.ts +++ b/apps/sim/blocks/blocks/supabase.ts @@ -1296,4 +1296,33 @@ export const SupabaseBlockMeta = { alsoIntegrations: ['algolia'], }, ], + skills: [ + { + name: 'query-table-rows', + description: + 'Read rows from a Supabase table with PostgREST filters, ordering, and pagination.', + content: + '# Query Supabase Table Rows\n\nFetch records from a Supabase table using PostgREST filters so downstream steps work with exactly the rows they need.\n\n## Steps\n1. Use the Get Many Rows operation with the project ID, service role secret, and target table.\n2. Set Select Columns to the fields you need (for example id,name,email) instead of returning every column.\n3. Add a PostgREST Filter such as status=eq.active or created_at=gte.2024-01-01 to narrow the result set.\n4. Set Order By (for example created_at DESC) plus Limit and Offset for predictable pagination.\n5. For a single record use Get a Row with a filter like id=eq.123.\n\n## Output\nReturn the matched rows as structured JSON. Note how many rows came back and surface the key fields each consumer needs.', + }, + { + name: 'upsert-record', + description: + 'Insert a new Supabase row or update it if it already exists in one idempotent call.', + content: + '# Upsert a Supabase Record\n\nWrite a record without first checking whether it exists, so repeated runs stay idempotent.\n\n## Steps\n1. Choose the Upsert a Row operation with the project ID, service role secret, and table.\n2. Provide the Data as a JSON object whose keys match the table columns, including the conflict key (such as id or email).\n3. Supabase inserts the row when the conflict key is new and updates the existing row otherwise.\n4. For a guaranteed new row use Create a Row instead; for a known existing row use Update a Row with a filter like id=eq.123.\n\n## Output\nConfirm whether the row was inserted or updated and report the resulting record fields back to the caller.', + }, + { + name: 'semantic-vector-search', + description: + 'Run pgvector similarity search against a Supabase table to retrieve the closest embeddings.', + content: + '# Semantic Vector Search in Supabase\n\nFind the most relevant rows by embedding similarity, the retrieval step for a RAG agent.\n\n## Steps\n1. Generate an embedding for the query text with your model and capture it as a numeric array.\n2. Use the Vector Search operation, pointing Function Name at your pgvector match function (for example match_documents).\n3. Pass the embedding into Query Embedding as a JSON array like [0.1, 0.2, 0.3].\n4. Tune Match Threshold (for example 0.78) and Match Count (for example 10) to balance precision and recall.\n\n## Output\nReturn the matched rows with their similarity scores, ordered by closeness, ready to feed an answer-generation step.', + }, + { + name: 'upload-file-to-storage', + description: 'Upload a file to a Supabase Storage bucket and return a public or signed URL.', + content: + '# Upload a File to Supabase Storage\n\nStore a generated or received file in a bucket and hand back a shareable link.\n\n## Steps\n1. Use Storage: Upload File with the bucket name, file name, and the file reference from a previous block.\n2. Set an optional Folder Path and Content Type, and enable Upsert if you want to overwrite an existing object.\n3. For a permanent link on a public bucket use Storage: Get Public URL with the file path.\n4. For private buckets use Storage: Create Signed URL with an Expires In value such as 3600 seconds.\n\n## Output\nReturn the stored object path plus the public or signed URL so later steps can reference or share the file.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/tailscale.ts b/apps/sim/blocks/blocks/tailscale.ts index a13c40de32b..1663cfae5a2 100644 --- a/apps/sim/blocks/blocks/tailscale.ts +++ b/apps/sim/blocks/blocks/tailscale.ts @@ -411,4 +411,26 @@ export const TailscaleBlockMeta = { tags: ['legal', 'enterprise'], }, ], + skills: [ + { + name: 'audit-tailnet-devices', + description: + 'List every device in the tailnet and flag stale, unauthorized, or update-pending nodes.', + content: + '# Audit Tailnet Devices\n\nProduce a clean inventory of the devices on your tailnet and surface the ones that need attention.\n\n## Steps\n1. Use the List Devices operation with your API key and tailnet (use "-" for the default tailnet).\n2. For each device review lastSeen, authorized, updateAvailable, and the assigned tags.\n3. Flag nodes not seen in 30+ days, devices still pending authorization, and any with an update available.\n4. Use Get Device with a deviceId to pull full detail on anything suspicious.\n\n## Output\nReturn a table of devices with hostname, user, OS, last seen, and authorization status, plus a short list of nodes that need review.', + }, + { + name: 'provision-auth-key', + description: + 'Create a scoped Tailscale auth key with the right tags, reusability, and expiry for onboarding.', + content: + '# Provision a Tailscale Auth Key\n\nGenerate an auth key so a new device or user can join the tailnet with the correct access.\n\n## Steps\n1. Use the Create Auth Key operation with your API key and tailnet.\n2. Set Tags (for example tag:server,tag:production) so devices joining with the key get the intended ACL access.\n3. Choose Reusable, Ephemeral, and Preauthorized values to match the use case (ephemeral for short-lived CI nodes).\n4. Set an Expiry in seconds (for example 7776000 for 90 days) and a clear Description.\n\n## Output\nReturn the generated key value once (it is only shown at creation), the key ID, its tags, and the expiry timestamp.', + }, + { + name: 'offboard-device', + description: 'Deauthorize or remove a departing user device and revoke its auth keys.', + content: + '# Offboard a Tailscale Device\n\nRemove a device from the tailnet during offboarding so access is cut cleanly.\n\n## Steps\n1. Use List Devices to find the deviceId tied to the departing user.\n2. To immediately cut access use Authorize Device set to Deauthorize, or Delete Device to remove it entirely.\n3. Use List Auth Keys to find any keys the user created, then Delete Auth Key for each.\n4. Capture the device detail with Get Device before deletion if you need an audit record.\n\n## Output\nConfirm the device was deauthorized or deleted and list the revoked auth keys for the offboarding audit log.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/tavily.ts b/apps/sim/blocks/blocks/tavily.ts index 96ba3e4f2dc..926e81ad8b0 100644 --- a/apps/sim/blocks/blocks/tavily.ts +++ b/apps/sim/blocks/blocks/tavily.ts @@ -438,4 +438,33 @@ export const TavilyBlockMeta = { tags: ['research', 'web-scraping', 'automation'], }, ], + skills: [ + { + name: 'answer-with-web-citations', + description: + 'Search the web with Tavily and return a grounded answer with linked source citations.', + content: + '# Answer a Question with Web Citations\n\nGround an answer in fresh web results so it is current and verifiable.\n\n## Steps\n1. Use the Search operation with the question as the Search Query.\n2. Set Include Answer to Advanced, Search Depth to advanced, and Max Results to about 5 for good coverage.\n3. Pick the Topic (news or finance) when the question is time-sensitive, and set Time Range (day, week, month) to keep results recent.\n4. Use Include Domains or Exclude Domains to keep results on trusted sources.\n\n## Output\nReturn the synthesized answer followed by a numbered list of the source titles and URLs used to support it.', + }, + { + name: 'extract-article-content', + description: + 'Pull clean main content from one or more URLs with Tavily Extract for summarization.', + content: + '# Extract Clean Article Content\n\nTurn a messy web page into clean text or markdown that an agent can summarize.\n\n## Steps\n1. Use the Extract Content operation and pass the page URL into the URL field.\n2. Set Extract Depth to advanced for content-heavy pages and choose Markdown or Text as the Format.\n3. Enable Include Images only if downstream steps need the media.\n4. Feed the extracted content to an agent to summarize the key points.\n\n## Output\nReturn the page title, source URL, and the cleaned content, plus any failed URLs so they can be retried.', + }, + { + name: 'crawl-site-section', + description: + 'Crawl a website section with Tavily and gather page content matching path rules.', + content: + '# Crawl a Website Section\n\nWalk a site beginning at a root URL and collect content from matching pages.\n\n## Steps\n1. Use the Crawl Website operation with the root Website URL.\n2. Give natural-language Instructions describing what to collect (for example "gather all product documentation pages").\n3. Bound the crawl with Max Depth, Max Breadth, and Limit so it stays focused.\n4. Use Select Paths and Exclude Paths regex patterns (for example /docs/.* to include, /admin/.* to exclude) to target the right section.\n\n## Output\nReturn the crawled pages with their URLs and extracted content, ready to index into a knowledge base or summarize.', + }, + { + name: 'map-site-structure', + description: 'Map a website URL structure with Tavily without extracting full page content.', + content: + '# Map a Website Structure\n\nDiscover the URL layout of a site quickly without pulling full page bodies.\n\n## Steps\n1. Use the Map Website operation with the root Website URL.\n2. Set Max Depth and Max Breadth to control how far the mapper explores.\n3. Apply Select Paths or Exclude Paths regex patterns to focus on the sections you care about.\n4. Toggle Allow External Links only if you want links that leave the root domain.\n\n## Output\nReturn the discovered list of URLs so you can pick targets for a later crawl or extract pass.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/telegram.ts b/apps/sim/blocks/blocks/telegram.ts index ad291ae1eec..96d71f86c55 100644 --- a/apps/sim/blocks/blocks/telegram.ts +++ b/apps/sim/blocks/blocks/telegram.ts @@ -498,4 +498,25 @@ export const TelegramBlockMeta = { alsoIntegrations: ['whatsapp'], }, ], + skills: [ + { + name: 'send-alert-message', + description: 'Post a formatted alert or notification to a Telegram chat or channel.', + content: + '# Send a Telegram Alert\n\nDeliver a timely notification to a Telegram chat, group, or channel.\n\n## Steps\n1. Use the Send Message operation with your Bot Token and the target Chat ID.\n2. Compose the Message with the essentials up front: what happened, severity, and a link for follow-up.\n3. To find a Chat ID, add the bot to the chat, send a message, then read the chat field from the getUpdates response.\n4. For recurring alerts, build the message from upstream block outputs so each notification carries live context.\n\n## Output\nReturn the sent message ID and chat ID so the run can be traced or the message later deleted.', + }, + { + name: 'send-media-message', + description: + 'Send a photo, video, document, or audio file to a Telegram chat with a caption.', + content: + '# Send Media to Telegram\n\nDeliver a file such as a chart, report, or image to a Telegram chat.\n\n## Steps\n1. Pick the matching operation: Send Photo, Send Video, Send Audio, Send Animation, or Send Document.\n2. Provide the Bot Token and Chat ID.\n3. Upload the file directly, or reference a file produced by a previous block (for example a generated PDF or chart image).\n4. Add an optional Caption describing the attachment.\n\n## Output\nConfirm delivery and return the message ID so the media post can be referenced later.', + }, + { + name: 'route-incoming-message', + description: 'Trigger a workflow when a Telegram message arrives and act on its content.', + content: + '# Route an Incoming Telegram Message\n\nUse Telegram as a trigger so the workflow runs whenever a user messages the bot.\n\n## Steps\n1. Enable the Telegram webhook trigger so incoming messages start the workflow.\n2. Read the trigger outputs: text, from_username, chat_id, and chat_type.\n3. Branch on the message content (for example detect a command or a support question) to decide the next action.\n4. Reply with the Send Message operation using the chat_id from the trigger.\n\n## Output\nReturn the parsed incoming message fields and confirm the reply that was sent back to the user.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/textract.ts b/apps/sim/blocks/blocks/textract.ts index d788afdc90f..a48ed1738d2 100644 --- a/apps/sim/blocks/blocks/textract.ts +++ b/apps/sim/blocks/blocks/textract.ts @@ -363,4 +363,27 @@ export const TextractBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'extract-invoice-fields', + description: + 'Run an invoice or receipt through AWS Textract and return clean structured fields (vendor, date, totals, line items). Use when you need to digitize finance documents.', + content: + '# Extract Invoice Fields\n\nUse AWS Textract to pull structured data from an invoice or receipt image/PDF.\n\n## Steps\n1. Choose the processing mode: Single Page for JPEG, PNG, or one-page PDF; Multi-Page for multi-page PDF/TIFF staged in S3.\n2. Provide the document (upload, file reference, or S3 URI) and enable Extract Forms and Extract Tables so key-value pairs and line items are captured.\n3. Run the extraction and read the returned blocks (KEY_VALUE_SET, TABLE, CELL, LINE).\n4. Map key-value pairs to fields: vendor, invoice number, invoice date, due date, subtotal, tax, and total.\n5. Reconstruct line items from the TABLE/CELL blocks into rows with description, quantity, unit price, and amount.\n\n## Output\nReturn a clean JSON record with the header fields and a line-items array. Flag any field where Textract confidence is low or the totals do not reconcile so a human can review.', + }, + { + name: 'extract-form-key-values', + description: + 'Turn a scanned form into structured key-value pairs and tables using AWS Textract. Use for intake forms, applications, and contracts.', + content: + '# Extract Form Key-Values\n\nDigitize a scanned form into structured data.\n\n## Steps\n1. Select Single Page mode for an image or one-page PDF, or Multi-Page mode with an S3 URI for longer documents.\n2. Enable Extract Forms (key-value pairs) and, if the form has tables, Extract Tables. Enable Analyze Document Layout for complex multi-column forms.\n3. Run the extraction and parse the KEY_VALUE_SET blocks into field-name to field-value pairs.\n4. Normalize field names (trim labels, lowercase keys) and coerce values like dates and numbers.\n\n## Output\nReturn a flat object of normalized field names to values, plus any extracted tables as arrays of rows. Note pages or fields with low confidence for review.', + }, + { + name: 'ocr-document-to-text', + description: + 'Convert a scanned document or image into plain readable text with AWS Textract OCR. Use to digitize handwritten notes, faxes, or image-only PDFs for indexing or search.', + content: + '# OCR Document To Text\n\nExtract readable text from a scanned or image-only document.\n\n## Steps\n1. Pick the processing mode that matches the file: Single Page for an image or one-page PDF, Multi-Page (S3) for multi-page documents.\n2. Provide the document and run the extraction. Plain OCR does not require the Forms or Tables features.\n3. Read the LINE and WORD blocks and join LINE blocks in reading order to reconstruct the text.\n4. Preserve paragraph and page breaks using the PAGE blocks.\n\n## Output\nReturn the full extracted text as clean Markdown, grouped by page. Include the page count from document metadata and surface any low-confidence lines so they can be reviewed before indexing.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/tinybird.ts b/apps/sim/blocks/blocks/tinybird.ts index 7ab562ff9b8..cd04e889999 100644 --- a/apps/sim/blocks/blocks/tinybird.ts +++ b/apps/sim/blocks/blocks/tinybird.ts @@ -457,4 +457,33 @@ export const TinybirdBlockMeta = { alsoIntegrations: ['gmail'], }, ], + skills: [ + { + name: 'ingest-events', + description: 'Stream JSON or NDJSON events into a Tinybird Data Source via the Events API.', + content: + '# Ingest Events into Tinybird\n\nStream realtime events into a Data Source so they are queryable within seconds.\n\n## Steps\n1. Use the Send Events operation with your Base URL and API Token.\n2. Set the Data Source name that matches your target table.\n3. Provide the events in the Data field, using NDJSON (one JSON object per line) for batches or JSON for a single object.\n4. Enable Wait for Acknowledgment when you need confirmation the rows landed before continuing.\n\n## Output\nReturn the count of successful_rows and quarantined_rows so you can confirm ingestion and catch rows that failed validation.', + }, + { + name: 'query-pipe-endpoint', + description: + 'Call a published Tinybird Pipe API Endpoint with dynamic parameters and return the result.', + content: + '# Query a Tinybird Pipe Endpoint\n\nCall a published Pipe by name to get analytics results shaped by dynamic parameters.\n\n## Steps\n1. Use the Query Pipe Endpoint operation with the Base URL, API Token, and the Pipe Name (for example top_pages).\n2. Pass dynamic Parameters as a JSON object whose keys match the parameters the Pipe expects (for example start_date and limit).\n3. Optionally add SQL on top of the Pipe result using the advanced SQL field, selecting from _ to post-process.\n\n## Output\nReturn the result rows as JSON along with the column metadata and row count, ready to write to a table or summarize.', + }, + { + name: 'run-sql-query', + description: + 'Run an ad-hoc SQL query against Tinybird with the Query API and return results.', + content: + '# Run a Tinybird SQL Query\n\nExecute SQL directly against your Tinybird data for ad-hoc analysis.\n\n## Steps\n1. Use the Query operation with the Base URL and API Token.\n2. Write the SQL Query and append FORMAT JSON to get structured rows back (other formats return raw text).\n3. Reference Data Sources or Pipes by name in the FROM clause.\n\n## Output\nReturn the result data as an array of objects plus the column metadata, row count, and execution statistics.', + }, + { + name: 'manage-datasource-rows', + description: + 'Append from a URL, truncate, or delete rows by condition in a Tinybird Data Source.', + content: + "# Manage Tinybird Data Source Rows\n\nMaintain a Data Source by loading, clearing, or pruning its rows.\n\n## Steps\n1. To load data, use Append Data Source (from URL) with the Data Source name, a Source File URL, and the source format (CSV, NDJSON, or Parquet).\n2. To clear everything, use Truncate Data Source with the Data Source name.\n3. To remove specific rows, use Delete Data Source Rows with a SQL Delete Condition such as event_date < '2024-01-01'.\n4. Enable Dry Run on a delete first to preview how many rows would be removed.\n\n## Output\nReturn the job ID and status for append and delete operations so you can poll for completion, or confirm the truncate succeeded.", + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/trello.ts b/apps/sim/blocks/blocks/trello.ts index a5cb2b42000..9ef80da0fb0 100644 --- a/apps/sim/blocks/blocks/trello.ts +++ b/apps/sim/blocks/blocks/trello.ts @@ -598,4 +598,31 @@ export const TrelloBlockMeta = { tags: ['hr', 'automation'], }, ], + skills: [ + { + name: 'create-card', + description: 'Create a Trello card in a list with a description, due date, and labels.', + content: + '# Create a Trello Card\n\nAdd a new card to a list so work is captured on the right board.\n\n## Steps\n1. Use the Create Card operation and select your Trello account.\n2. Provide the List ID where the card should land and the Card Name.\n3. Add an optional Description, a Due Date (natural language like "next Friday" works), and Label IDs.\n4. Set Position to top or bottom to control where the card appears in the list.\n\n## Output\nReturn the created card including its id, url, and list, so it can be linked or updated later.', + }, + { + name: 'triage-and-move-cards', + description: + 'List cards on a board or list, classify them, and move each to the correct list.', + content: + '# Triage and Route Trello Cards\n\nRead incoming cards, decide where each belongs, and route them automatically.\n\n## Steps\n1. Use Get Lists with the Board ID to learn the available lists and their IDs.\n2. Use List Cards with the board or list ID to pull the cards needing triage.\n3. Classify each card by its name and description (topic, priority, owner).\n4. Use Update Card with the Move to List ID to route each card to its destination list.\n\n## Output\nReturn a summary of how many cards were moved and the destination list for each.', + }, + { + name: 'comment-on-card', + description: 'Add a comment to a Trello card to leave a note, nudge, or status update.', + content: + '# Comment on a Trello Card\n\nLeave a comment on a card to record context or nudge an owner.\n\n## Steps\n1. Use the Add Comment operation and select your Trello account.\n2. Provide the Card ID of the target card.\n3. Write the Comment text, including any links or mentions the team needs.\n\n## Output\nReturn the created comment action with its id and date so the note can be referenced.', + }, + { + name: 'review-card-activity', + description: 'Pull the recent action history for a Trello board or card and summarize it.', + content: + '# Review Trello Card Activity\n\nInspect what has happened recently on a board or card to build a digest or audit.\n\n## Steps\n1. Use the Get Actions operation with either a Board ID or a Card ID (one or the other, not both).\n2. Set an Action Filter such as commentCard,updateCard,createCard to focus on the events you care about.\n3. Use Board Action Limit and Action Page to page through longer histories.\n\n## Output\nReturn the actions with their type, date, author, and text, summarized into a short activity recap.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/twilio.ts b/apps/sim/blocks/blocks/twilio.ts index 3b08877ca42..5b501385076 100644 --- a/apps/sim/blocks/blocks/twilio.ts +++ b/apps/sim/blocks/blocks/twilio.ts @@ -145,4 +145,25 @@ export const TwilioSMSBlockMeta = { tags: ['messaging', 'automation', 'team'], }, ], + skills: [ + { + name: 'send-sms-notification', + description: 'Send an SMS notification to one or more phone numbers via Twilio.', + content: + '# Send an SMS Notification\n\nDeliver a text message to one or more recipients through your Twilio number.\n\n## Steps\n1. Enter the Recipient Phone Numbers in E.164 format with country code (for example +14155551234), one per line for multiple recipients.\n2. Write the Message text, keeping it concise since long messages split into multiple segments.\n3. Provide your Twilio Account SID, Auth Token, and the verified From Twilio Phone Number.\n\n## Output\nReturn the success status, the Twilio message SID, and the delivery status (queued, sent, delivered) so the send can be confirmed.', + }, + { + name: 'send-personalized-reminder', + description: + 'Send a personalized SMS reminder built from upstream data such as appointment or order details.', + content: + '# Send a Personalized SMS Reminder\n\nText each recipient a reminder tailored with their own details.\n\n## Steps\n1. Pull the recipient details from an upstream block (a table row, CRM record, or order event).\n2. Build the Message using those fields, for example the appointment time or tracking number, plus any link.\n3. Set the Recipient Phone Numbers to the customer number from the source record.\n4. Provide the Account SID, Auth Token, and From Twilio Phone Number.\n\n## Output\nReturn the message SID and status for each send so delivery can be logged back to the source record.', + }, + { + name: 'send-verification-code', + description: 'Send a one-time verification code over SMS for two-factor authentication.', + content: + '# Send a Verification Code over SMS\n\nDeliver a one-time code to a user for two-factor authentication or confirmation.\n\n## Steps\n1. Generate or receive the one-time code from an upstream step.\n2. Compose the Message with the code and a short note (for example "Your code is 482913. It expires in 10 minutes.").\n3. Set the Recipient Phone Numbers to the user number and provide the Account SID, Auth Token, and From number.\n4. Log the send outcome for audit.\n\n## Output\nReturn the message SID and delivery status so the verification send can be tracked and audited.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/twilio_voice.ts b/apps/sim/blocks/blocks/twilio_voice.ts index fab9b7ea1e0..511608b8ac3 100644 --- a/apps/sim/blocks/blocks/twilio_voice.ts +++ b/apps/sim/blocks/blocks/twilio_voice.ts @@ -484,4 +484,32 @@ export const TwilioVoiceBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'place-outbound-call', + description: + 'Place an outbound Twilio Voice call that speaks a message or plays audio via TwiML.', + content: + '# Place an Outbound Voice Call\n\nDial a number and play a spoken message or audio using TwiML.\n\n## Steps\n1. Use the Make Call operation with your Account SID and Auth Token.\n2. Set the To Phone Number and the From Twilio Number, both in E.164 format.\n3. Provide TwiML Instructions describing what the call should say or do (use square brackets like [Say]Hello[/Say]), or point a TwiML URL at hosted instructions.\n4. Enable Record Call and set a Timeout if you need the recording or a ring limit, and add Machine Detection to handle voicemail.\n\n## Output\nReturn the call SID and status so the call can be tracked or its recording retrieved later.', + }, + { + name: 'collect-keypad-response', + description: + 'Place a call that asks a question and captures the caller keypad or speech response.', + content: + '# Collect a Keypad or Speech Response\n\nCall a recipient, ask a question, and capture their response for branching logic.\n\n## Steps\n1. Use the Make Call operation with the To and From numbers and your credentials.\n2. In the TwiML Instructions, use [Gather] to collect input, for example [Gather input="dtmf" numDigits="1"][Say]Press 1 to confirm, 2 to cancel[/Say][/Gather].\n3. For surveys, gather a rating digit; for confirmations, gather a single yes or no digit.\n4. Enable Record Call when you also want the audio.\n\n## Output\nReturn the captured digits or speech result from the webhook so a later step can branch on the caller response.', + }, + { + name: 'retrieve-call-recording', + description: 'Fetch a Twilio Voice call recording and its transcription by recording SID.', + content: + '# Retrieve a Call Recording\n\nPull the recording and transcript of a completed call for QA or CRM logging.\n\n## Steps\n1. Use the Get Recording operation with your Account SID and Auth Token.\n2. Provide the Recording SID (it begins with RE) from the call you want.\n3. If the original call TwiML used [Record transcribe="true"], the transcription text is returned alongside the audio.\n\n## Output\nReturn the media URL to download the recording, its duration, and the transcription text and status so the call can be summarized or archived.', + }, + { + name: 'review-recent-calls', + description: 'List recent Twilio Voice calls filtered by number, status, and date range.', + content: + '# Review Recent Voice Calls\n\nPull a filtered list of calls to build a report or feed a follow-up workflow.\n\n## Steps\n1. Use the List Calls operation with your Account SID and Auth Token.\n2. Filter by To Number, From Number, or Status (for example completed or no-answer).\n3. Narrow the window with After and Before dates (natural language like "last week" works), and set a Page Size.\n\n## Output\nReturn the array of matching calls with their SIDs, status, direction, and duration, plus the total count for reporting.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/typeform.ts b/apps/sim/blocks/blocks/typeform.ts index 3272f2ff52c..f6f7f4d800a 100644 --- a/apps/sim/blocks/blocks/typeform.ts +++ b/apps/sim/blocks/blocks/typeform.ts @@ -529,4 +529,30 @@ export const TypeformBlockMeta = { tags: ['product', 'research'], }, ], + skills: [ + { + name: 'retrieve-form-responses', + description: 'Fetch Typeform responses for a form with date and completion filters.', + content: + '# Retrieve Typeform Responses\n\nPull submitted responses from a form so an agent can analyze or route them.\n\n## Steps\n1. Use the Retrieve Responses operation with the Form ID and your personal access token.\n2. Filter with Since and Until dates (natural language like "last week" works) to get only recent submissions.\n3. Set Completed to Only Completed to skip partial responses, and set Page Size for batch size.\n4. Use the Before and After cursor tokens to page through large result sets.\n\n## Output\nReturn the response items with their answers and metadata, plus the total count, ready for analysis or logging.', + }, + { + name: 'analyze-survey-responses', + description: 'Pull form responses and categorize them by theme and sentiment for a digest.', + content: + '# Analyze Survey Responses\n\nTurn raw form submissions into structured insights.\n\n## Steps\n1. Use Retrieve Responses with the Form ID, narrowing by Since to the new batch.\n2. For each response, classify the free-text answers by theme and sentiment with an agent.\n3. Aggregate counts per theme and capture notable quotes.\n4. Optionally use Form Insights to pull completion and drop-off metrics for context.\n\n## Output\nReturn a structured summary of themes, sentiment breakdown, and standout responses suitable for a table row or a Slack digest.', + }, + { + name: 'create-form', + description: 'Create a new Typeform form or quiz with fields and settings.', + content: + '# Create a Typeform Form\n\nSpin up a new form or quiz programmatically.\n\n## Steps\n1. Use the Create Form operation with your personal access token.\n2. Set the Form Title and choose the Form Type (form or quiz).\n3. Provide Fields as a JSON array of field objects (type, title, ref, validations) and optional Settings as JSON.\n4. Set a Workspace ID and Theme ID to place and style the form.\n\n## Output\nReturn the new form id and its links so you can share it or store the reference.', + }, + { + name: 'download-uploaded-file', + description: 'Download a file a respondent uploaded through a Typeform file-upload field.', + content: + '# Download an Uploaded Typeform File\n\nRetrieve a file that a respondent attached in their submission.\n\n## Steps\n1. Use the Download File operation with the Form ID and your personal access token.\n2. Provide the Response ID (the response token), the file-upload Field ID, and the exact Filename.\n3. Use these IDs from a Retrieve Responses result that contains file-upload answers.\n\n## Output\nReturn the downloaded file and its content type so it can be stored, forwarded, or processed by a later step.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/upstash.ts b/apps/sim/blocks/blocks/upstash.ts index ec007b9afec..c88d7038aa9 100644 --- a/apps/sim/blocks/blocks/upstash.ts +++ b/apps/sim/blocks/blocks/upstash.ts @@ -419,4 +419,33 @@ export const UpstashBlockMeta = { alsoIntegrations: ['dynamodb'], }, ], + skills: [ + { + name: 'cache-value-with-ttl', + description: + 'Store a value in Upstash Redis under a key with an expiration so it auto-evicts.', + content: + '# Cache a Value with TTL\n\nWrite a computed or fetched value into Redis so hot paths read it fast and it expires automatically.\n\n## Steps\n1. Use the Set operation with your REST URL and REST Token.\n2. Provide the Key (for example user:123:profile) and the Value to store.\n3. Set the Expiration (seconds) so the entry self-evicts after the TTL.\n4. To avoid overwriting an existing entry, use SETNX instead, which only sets when the key is absent.\n\n## Output\nReturn the set result so the cache write can be confirmed before downstream reads.', + }, + { + name: 'read-cached-value', + description: 'Read a value from Upstash Redis by key, returning a cache hit or miss.', + content: + '# Read a Cached Value\n\nLook up a key in Redis and branch on whether it is present.\n\n## Steps\n1. Use the Get operation with the REST URL, REST Token, and the Key.\n2. To check presence first without fetching, use EXISTS, or use TTL to see how long the entry has left.\n3. On a cache miss (no value), fall through to recompute and write it back with Set.\n\n## Output\nReturn the retrieved value, or an empty result on a miss, so the workflow can serve cached data or recompute.', + }, + { + name: 'increment-counter', + description: + 'Atomically increment an Upstash Redis counter for rate limits or usage metering.', + content: + '# Increment a Redis Counter\n\nMaintain an atomic counter for usage tracking, rate limiting, or tallies.\n\n## Steps\n1. Use the INCR operation with the REST URL, REST Token, and the counter Key to add one.\n2. Use INCRBY with an Increment amount to add (or subtract with a negative value) a specific number.\n3. Pair with the EXPIRE operation on the key to create a time-windowed counter (for example per-minute rate limits).\n\n## Output\nReturn the new counter value after the increment so the workflow can check it against a threshold.', + }, + { + name: 'push-and-read-list', + description: + 'Push items onto an Upstash Redis list and read a range back for a simple queue.', + content: + '# Push and Read a Redis List\n\nUse a Redis list as a lightweight queue or activity log.\n\n## Steps\n1. Use the LPUSH operation with the REST URL, REST Token, Key, and Value to add an item to the list head.\n2. Use the LRANGE operation with a Start Index (0) and Stop Index (-1 for all) to read items back.\n3. For raw or unsupported operations, use the Command operation with a JSON array like ["RPOP", "myqueue"].\n\n## Output\nReturn the list length after a push and the list elements from a range read so the workflow can process queued items.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/vercel.ts b/apps/sim/blocks/blocks/vercel.ts index 2309b77763e..0f304126f05 100644 --- a/apps/sim/blocks/blocks/vercel.ts +++ b/apps/sim/blocks/blocks/vercel.ts @@ -1121,4 +1121,30 @@ export const VercelBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'monitor-deployments', + description: 'List recent Vercel deployments, surface failed builds, and pull their logs.', + content: + '# Monitor Vercel Deployments\n\nKeep an eye on builds so failures are caught fast.\n\n## Steps\n1. Use the List Deployments operation with your access token, optionally filtering by Project ID, Target (production), and State (ERROR).\n2. For any failed or stuck deployment, use Get Deployment Logs with the Deployment ID to pull the build events.\n3. Summarize the failure cause from the log events.\n4. Use Get Deployment for full detail including the deployment URL and state.\n\n## Output\nReturn the list of deployments with their state, plus a short summary of any failed build and a link to investigate.', + }, + { + name: 'rollback-deployment', + description: 'Redeploy the last known good Vercel deployment to recover from a bad release.', + content: + '# Roll Back a Vercel Deployment\n\nRecover production by redeploying a previous good build.\n\n## Steps\n1. Use List Deployments filtered to the project, Target production, and State READY to find the last good deployment.\n2. Use the Create Deployment operation with Redeploy From set to that good deployment ID and Target set to production.\n3. Optionally use Cancel Deployment on the broken build that is still running.\n\n## Output\nReturn the new deployment ID, URL, and state so the rollback can be confirmed and announced.', + }, + { + name: 'manage-env-vars', + description: 'Read, create, or update environment variables on a Vercel project.', + content: + '# Manage Vercel Environment Variables\n\nKeep a project configuration correct across environments.\n\n## Steps\n1. Use Get Environment Variables with the Project ID to read the current variables.\n2. To add one, use Create Environment Variable with the Key, Value, Target Environments (for example production,preview), and Variable Type.\n3. To change one, use Update Environment Variable with the Env Variable ID and the new value.\n4. Use Delete Environment Variable with the Env Variable ID to remove a stale key.\n\n## Output\nReturn the resulting variable list or confirmation of the create, update, or delete so configuration changes are auditable.', + }, + { + name: 'audit-domains-and-dns', + description: 'Inventory Vercel domains and DNS records and manage records for a domain.', + content: + '# Audit Vercel Domains and DNS\n\nTrack domains and DNS so changes never go unnoticed.\n\n## Steps\n1. Use List Domains for the account inventory, and List DNS Records with a Domain to see its records.\n2. To add a record, use Create DNS Record with the Domain, Record Name, Record Type (A, CNAME, TXT, etc.), and Value.\n3. To remove one, use Delete DNS Record with the Domain and Record ID.\n4. Use Get Domain Config to verify a domain is correctly configured.\n\n## Output\nReturn the domain and DNS record inventory, or confirmation of any record change, for the tracking log.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/wealthbox.ts b/apps/sim/blocks/blocks/wealthbox.ts index 0a52b24b867..d14a9b5527d 100644 --- a/apps/sim/blocks/blocks/wealthbox.ts +++ b/apps/sim/blocks/blocks/wealthbox.ts @@ -347,4 +347,32 @@ export const WealthboxBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'log-client-note', + description: 'Write a note to a Wealthbox contact record to capture meeting or call details.', + content: + '# Log a Wealthbox Client Note\n\nRecord a note on a client record so the interaction history stays complete.\n\n## Steps\n1. Use the Write Note operation and select your Wealthbox account.\n2. Select the Contact the note belongs to (or enter the Contact ID in advanced mode).\n3. Write the note Content, summarizing the meeting, call, or decision.\n\n## Output\nReturn the created note with its ID and linked contact so the entry can be referenced later.', + }, + { + name: 'create-followup-task', + description: 'Create a follow-up task on a Wealthbox contact with a title and due date.', + content: + '# Create a Wealthbox Follow-up Task\n\nAdd a task to a client record so an advisor follow-up is not missed.\n\n## Steps\n1. Use the Write Task operation and select your Wealthbox account.\n2. Select the Contact the task is for.\n3. Set the Title, the Content describing the work, and a Due Date (natural language like "tomorrow at 2pm" works).\n\n## Output\nReturn the created task with its ID and due date so it can be tracked to completion.', + }, + { + name: 'upsert-contact', + description: + 'Create or read a Wealthbox contact with name, email, and background information.', + content: + '# Manage a Wealthbox Contact\n\nAdd a new client or pull an existing client record.\n\n## Steps\n1. To add a client, use the Write Contact operation with First Name, Last Name, and optionally Email Address and Background Information.\n2. To read a client, use the Read Contact operation and select the Contact or enter its Contact ID.\n3. Select your Wealthbox account for either operation.\n\n## Output\nReturn the contact record including name, email, and background info so downstream steps can use it.', + }, + { + name: 'prepare-client-brief', + description: + 'Read a Wealthbox contact plus their recent notes and tasks to build a meeting brief.', + content: + '# Prepare a Wealthbox Client Brief\n\nGather everything about a client ahead of a meeting.\n\n## Steps\n1. Use Read Contact with the Contact ID to pull the client profile and background.\n2. Use Read Note to retrieve recent notes for the contact.\n3. Use Read Task to pull open and recent tasks tied to the client.\n4. Have an agent synthesize the records into a concise prep brief.\n\n## Output\nReturn a brief covering the client profile, recent notes, and outstanding tasks, ready to email to the advisor.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/webflow.ts b/apps/sim/blocks/blocks/webflow.ts index b7702b6f63d..1e03bd220f4 100644 --- a/apps/sim/blocks/blocks/webflow.ts +++ b/apps/sim/blocks/blocks/webflow.ts @@ -329,4 +329,27 @@ export const WebflowBlockMeta = { alsoIntegrations: ['loops', 'hubspot'], }, ], + skills: [ + { + name: 'publish-cms-item', + description: + 'Create a new item in a Webflow CMS collection from supplied or generated field data.', + content: + '# Publish a Webflow CMS Item\n\nTurn structured content into a live Webflow CMS collection item.\n\n## Steps\n1. Identify the target site and collection. If unknown, list collections to confirm the collection ID and its field schema.\n2. Map the incoming content to the collection fields, including required fields like name and slug. Generate a URL-safe slug if one is not provided.\n3. Call the create-item operation with the assembled fieldData JSON.\n4. Confirm the new item ID and slug returned by the API.\n\n## Output\nReport the created item ID, slug, and the live or staged URL. If a required field was missing, name it explicitly rather than guessing a value.', + }, + { + name: 'update-cms-item', + description: + 'Find a Webflow CMS item and update specific fields without disturbing the rest.', + content: + '# Update a Webflow CMS Item\n\nApply targeted edits to an existing collection item.\n\n## Steps\n1. Resolve the item by ID, or list items in the collection and match on slug or name.\n2. Get the current item so existing field values are known.\n3. Build fieldData containing only the fields that change, merged onto the current values so untouched fields are preserved.\n4. Call the update-item operation and confirm the change took effect.\n\n## Output\nList exactly which fields changed and their new values. Note the item ID and whether the change is live or staged.', + }, + { + name: 'audit-collection-content', + description: + 'List items in a Webflow collection and flag missing or stale fields for cleanup.', + content: + '# Audit a Webflow Collection\n\nReview a CMS collection for content-quality gaps.\n\n## Steps\n1. List all items in the target collection, paging through with offset and limit until complete.\n2. For each item, check for empty required fields such as meta description, image, or publish date.\n3. Flag items that are missing key SEO or display fields, or whose dates look stale.\n4. Summarize the findings as a remediation backlog.\n\n## Output\nReturn a table of flagged items with item ID, slug, and the specific gap found. End with a short prioritized list of what to fix first.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/whatsapp.ts b/apps/sim/blocks/blocks/whatsapp.ts index 96afd800a35..7b2e74bb6b7 100644 --- a/apps/sim/blocks/blocks/whatsapp.ts +++ b/apps/sim/blocks/blocks/whatsapp.ts @@ -249,4 +249,27 @@ export const WhatsAppBlockMeta = { alsoIntegrations: ['zoom'], }, ], + skills: [ + { + name: 'send-appointment-reminder', + description: + 'Send a WhatsApp message reminding a contact of an upcoming appointment or booking.', + content: + '# Send a WhatsApp Appointment Reminder\n\nNotify a contact about an upcoming appointment over WhatsApp.\n\n## Steps\n1. Gather the recipient phone number in full international format (country code, no plus sign or spaces as the API expects).\n2. Compose a short, clear message with the date, time, location or link, and any action the contact should take.\n3. Send the message with the WhatsApp send operation.\n4. Capture the returned message ID and delivery state.\n\n## Output\nConfirm the recipient, the message sent, and the message ID. If the send was rejected, report the reason rather than retrying blindly.', + }, + { + name: 'send-order-update', + description: + 'Notify a customer over WhatsApp about an order status change such as shipment or delivery.', + content: + '# Send a WhatsApp Order Update\n\nKeep a customer informed about their order via WhatsApp.\n\n## Steps\n1. Collect the customer phone number in full international format and the order details (number, status, tracking, ETA).\n2. Write a concise update that states what changed and includes the tracking link if available.\n3. Send the message and record the message ID and delivery state.\n\n## Output\nReport which customer was notified, the order referenced, and the message ID. Flag any number that could not be reached.', + }, + { + name: 'broadcast-to-segment', + description: + 'Send a personalized WhatsApp message to each contact in an audience list, one at a time.', + content: + '# Broadcast a WhatsApp Message to a Segment\n\nDeliver a personalized message to every contact in a list.\n\n## Steps\n1. Read the audience list, each row holding a phone number and any personalization fields.\n2. For each contact, build the message by filling in their name and relevant details.\n3. Send messages one per contact, pacing them to stay within WhatsApp rate and template limits.\n4. Track which sends succeeded and which failed.\n\n## Output\nReturn counts of messages sent and failed, plus a short list of failed recipients with the failure reason.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/wikipedia.ts b/apps/sim/blocks/blocks/wikipedia.ts index d8cf0f2243a..f1d76b48418 100644 --- a/apps/sim/blocks/blocks/wikipedia.ts +++ b/apps/sim/blocks/blocks/wikipedia.ts @@ -176,4 +176,26 @@ export const WikipediaBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'research-topic-brief', + description: 'Search Wikipedia for a topic and assemble a concise, sourced background brief.', + content: + '# Build a Wikipedia Topic Brief\n\nProduce a quick, reliable background brief on a subject.\n\n## Steps\n1. Search pages for the topic to find the best-matching article title.\n2. Get the page summary for a fast overview, then get full page content if more depth is needed.\n3. Extract the key facts, dates, and definitions, ignoring tangential detail.\n4. Assemble a short brief in your own words.\n\n## Output\nReturn a brief with a one-line definition, three to five key points, and the Wikipedia page title used as the source.', + }, + { + name: 'disambiguate-entity', + description: + 'Resolve an ambiguous name to the correct Wikipedia entity using surrounding context.', + content: + '# Disambiguate an Entity via Wikipedia\n\nPick the right Wikipedia entity for an ambiguous name.\n\n## Steps\n1. Search pages for the name to retrieve candidate matches.\n2. For the top candidates, get the page summary.\n3. Compare each summary against the context provided (industry, location, role) and choose the best fit.\n4. If nothing matches confidently, say so rather than forcing a choice.\n\n## Output\nReturn the chosen canonical page title with a one-line justification, plus a confidence note and any close alternatives.', + }, + { + name: 'verify-claim', + description: + 'Check whether a stated claim is supported by Wikipedia content and flag unsupported claims.', + content: + '# Verify a Claim Against Wikipedia\n\nFact-check a claim using Wikipedia as a reference source.\n\n## Steps\n1. Identify the entity or topic the claim is about and search for its page.\n2. Get the page summary or content covering the relevant section.\n3. Compare the claim against the article text and decide if it is supported, contradicted, or not addressed.\n\n## Output\nReturn a verdict of supported, contradicted, or unverified, with the supporting sentence quoted and the page title cited. Do not treat absence of mention as proof either way.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/wiza.ts b/apps/sim/blocks/blocks/wiza.ts index 292a9b8a9d0..bf9a1ea63d0 100644 --- a/apps/sim/blocks/blocks/wiza.ts +++ b/apps/sim/blocks/blocks/wiza.ts @@ -697,4 +697,26 @@ export const WizaBlockMeta = { alsoIntegrations: ['hubspot'], }, ], + skills: [ + { + name: 'find-prospects', + description: + 'Run a Wiza prospect search with filters to build a list of verified B2B contacts.', + content: + '# Find B2B Prospects with Wiza\n\nBuild a targeted list of verified prospects from an ideal-customer profile.\n\n## Steps\n1. Translate the ideal-customer profile into Wiza filters: job title, seniority, company size, industry, and location.\n2. Run the prospect-search operation with those filters and a sensible result limit.\n3. Choose how much contact data to reveal (email only, phone, or full) based on the outreach plan and credit budget.\n4. Collect the returned prospects with their verified contact fields.\n\n## Output\nReturn the matched prospects with name, title, company, and verified email or phone. Note the total matches and how many credits the reveal consumed.', + }, + { + name: 'enrich-company', + description: 'Enrich a company by domain or name to retrieve firmographic data from Wiza.', + content: + '# Enrich a Company with Wiza\n\nFill in firmographic detail for a target account.\n\n## Steps\n1. Gather the company identifier you have, typically a domain or company name.\n2. Call the company-enrichment operation.\n3. Extract the returned firmographics: industry, size, location, revenue band, and website.\n\n## Output\nReturn the enriched company record as structured fields. If the company could not be matched, say so and report the input used.', + }, + { + name: 'reveal-contact-details', + description: + 'Reveal verified email and phone for a known individual using Wiza individual reveal.', + content: + '# Reveal a Contact with Wiza\n\nGet verified contact details for a specific person.\n\n## Steps\n1. Provide the person identifiers you have, such as name and company or a LinkedIn profile.\n2. Decide the reveal level needed: email only, phone, or full contact.\n3. Call the individual-reveal operation.\n4. Capture the verified email, phone, and current role returned.\n\n## Output\nReturn the verified contact fields with a note on validation status. If credits are low, check the get-credits operation first and warn before spending.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/wordpress.ts b/apps/sim/blocks/blocks/wordpress.ts index 02fccee8fdc..c2bec55b385 100644 --- a/apps/sim/blocks/blocks/wordpress.ts +++ b/apps/sim/blocks/blocks/wordpress.ts @@ -1085,4 +1085,33 @@ export const WordPressBlockMeta = { tags: ['marketing', 'content', 'automation'], }, ], + skills: [ + { + name: 'publish-blog-post', + description: + 'Create a WordPress post from a draft, assign categories and tags, and set its publish state.', + content: + '# Publish a WordPress Post\n\nTurn a finished draft into a WordPress post.\n\n## Steps\n1. Prepare the title, body HTML, and excerpt for the post.\n2. Resolve or create the categories and tags by listing existing ones and matching by name.\n3. Decide the status: draft for review or publish to go live.\n4. Call the create-post operation with the content, taxonomy, and status.\n\n## Output\nReport the new post ID, status, and the post URL. List the categories and tags applied. If publishing directly, confirm the live link.', + }, + { + name: 'update-existing-post', + description: + 'Find a WordPress post and update its content, status, or taxonomy without overwriting the rest.', + content: + '# Update a WordPress Post\n\nApply targeted edits to a published or draft post.\n\n## Steps\n1. Locate the post by ID, or list or search posts and match on title.\n2. Get the current post to know its existing content and metadata.\n3. Build an update containing only the fields that change, such as body, status, or tags.\n4. Call the update-post operation and confirm the change.\n\n## Output\nState which fields changed and the post ID. Confirm the resulting status and URL.', + }, + { + name: 'upload-and-attach-media', + description: 'Upload an image or file to the WordPress media library for use in a post.', + content: + '# Upload Media to WordPress\n\nAdd an image or file to the media library.\n\n## Steps\n1. Provide the file to upload along with a descriptive title and alt text.\n2. Call the upload-media operation.\n3. Capture the returned media ID and source URL.\n4. If the media is for a specific post, reference the media ID or URL when creating or updating that post.\n\n## Output\nReturn the media ID, the file URL, and the alt text set. Note whether it was attached to a post.', + }, + { + name: 'moderate-comments', + description: + 'List recent WordPress comments and approve, hold, spam, or trash them by policy.', + content: + '# Moderate WordPress Comments\n\nKeep the comment queue clean and on-policy.\n\n## Steps\n1. List comments, optionally filtering by status such as hold.\n2. For each comment, judge it against the moderation policy: legitimate, spam, or abusive.\n3. Update each comment to the right status: approved, hold, spam, or trash.\n\n## Output\nReturn a summary of how many comments were approved, held, marked spam, or trashed, with the comment IDs grouped by action taken.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/workday.ts b/apps/sim/blocks/blocks/workday.ts index 562a916cef2..5e1461d9b23 100644 --- a/apps/sim/blocks/blocks/workday.ts +++ b/apps/sim/blocks/blocks/workday.ts @@ -533,4 +533,33 @@ export const WorkdayBlockMeta = { tags: ['hr', 'automation', 'team'], }, ], + skills: [ + { + name: 'look-up-worker', + description: 'Find a worker in Workday and return their core profile and employment details.', + content: + '# Look Up a Worker in Workday\n\nRetrieve a worker record for HR review or downstream use.\n\n## Steps\n1. Resolve the worker by ID, or list workers and match on name or email.\n2. Call the get-worker operation for the matched worker.\n3. Extract the relevant fields: name, position, organization, manager, and status.\n\n## Output\nReturn the worker profile as structured fields. If multiple workers matched the search, list the candidates and ask which one before fetching full detail.', + }, + { + name: 'onboard-new-hire', + description: + 'Create a pre-hire, hire the employee, and assign an onboarding plan in Workday.', + content: + '# Onboard a New Hire in Workday\n\nMove a candidate from pre-hire to onboarded employee.\n\n## Steps\n1. Create the pre-hire record with the candidate personal and contact details.\n2. Hire the employee using the pre-hire, setting position, organization, start date, and worker type.\n3. Assign the onboarding plan for the new worker.\n4. Confirm each step succeeded before moving to the next.\n\n## Output\nReport the new worker ID, position, start date, and the onboarding plan assigned. Stop and surface the error if any step fails rather than continuing.', + }, + { + name: 'process-job-change', + description: + 'Apply a job change such as a transfer or promotion to an existing Workday worker.', + content: + '# Process a Job Change in Workday\n\nUpdate a worker position with a transfer, promotion, or reassignment.\n\n## Steps\n1. Look up the worker and confirm their current position and organization.\n2. Determine the new position, organization, or compensation involved in the change.\n3. Call the change-job operation with the change details and effective date.\n4. Optionally fetch compensation to confirm the new package.\n\n## Output\nReport the worker ID, the old and new position, the effective date, and confirmation the change was recorded.', + }, + { + name: 'update-worker-info', + description: + 'Update a Workday worker personal information record with validated field changes.', + content: + '# Update Worker Personal Information\n\nApply validated personal-information changes for a worker.\n\n## Steps\n1. Look up the worker to confirm the record and current values.\n2. Validate the requested changes against expected formats before applying.\n3. Build the fields JSON with only the values that change.\n4. Call the update-worker operation and confirm acceptance.\n\n## Output\nReport which fields changed for the worker ID and confirm the update succeeded. Reject and explain any field that failed validation.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/x.ts b/apps/sim/blocks/blocks/x.ts index ef6a9100897..9bc7c517719 100644 --- a/apps/sim/blocks/blocks/x.ts +++ b/apps/sim/blocks/blocks/x.ts @@ -827,4 +827,33 @@ export const XBlockMeta = { tags: ['research', 'content', 'individual'], }, ], + skills: [ + { + name: 'post-tweet', + description: + 'Compose and publish a tweet on X, optionally as a reply or with reply restrictions.', + content: + '# Post a Tweet on X\n\nPublish a single tweet or a reply.\n\n## Steps\n1. Draft the tweet text, keeping it within the character limit and on-brand.\n2. If it is a reply, identify the tweet ID being replied to. Set reply restrictions if the post should be limited to following or mentioned users.\n3. Call the create-tweet operation.\n4. Capture the returned tweet ID.\n\n## Output\nReturn the posted tweet text and its tweet ID with a link. Confirm whether it was a standalone post or a reply.', + }, + { + name: 'monitor-mentions', + description: 'Fetch recent mentions of a user on X and summarize what needs a response.', + content: + '# Monitor X Mentions\n\nTrack who is talking to a profile and surface what matters.\n\n## Steps\n1. Resolve the target user, using get-my-profile or search-users to confirm the user ID.\n2. Call get-user-mentions to fetch recent mentions.\n3. Classify each mention: question, complaint, praise, or noise.\n4. Highlight mentions that need a reply.\n\n## Output\nReturn a grouped summary of mentions by type, with the tweet IDs and authors for any that need a human response, ranked by urgency.', + }, + { + name: 'search-and-analyze-tweets', + description: + 'Search X for tweets matching a query and summarize themes, sentiment, and notable posts.', + content: + '# Search and Analyze Tweets on X\n\nUnderstand the conversation around a topic or keyword.\n\n## Steps\n1. Build a focused search query and choose recency or relevancy sorting.\n2. Call search-tweets with a sensible result limit.\n3. Read the results and identify recurring themes, overall sentiment, and high-engagement posts.\n\n## Output\nReturn a short report: dominant themes, sentiment split, and a few notable tweets with their IDs. Note the query and time window covered.', + }, + { + name: 'curate-bookmarks-digest', + description: + 'Pull saved X bookmarks, group them by theme, and produce a curated reading digest.', + content: + '# Curate an X Bookmarks Digest\n\nTurn saved bookmarks into an organized reading list.\n\n## Steps\n1. Call get-bookmarks to retrieve saved tweets.\n2. Fetch the full text of each bookmarked tweet where needed using get-tweets-by-IDs.\n3. Group the bookmarks by theme and write a short note on why each cluster matters.\n4. Optionally delete-bookmark for items once they are processed.\n\n## Output\nReturn a themed digest with each tweet linked by ID and a one-line takeaway per item. State how many bookmarks were processed.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/youtube.ts b/apps/sim/blocks/blocks/youtube.ts index 62941c3661a..60925ab082d 100644 --- a/apps/sim/blocks/blocks/youtube.ts +++ b/apps/sim/blocks/blocks/youtube.ts @@ -630,4 +630,27 @@ export const YouTubeBlockMeta = { alsoIntegrations: ['notion'], }, ], + skills: [ + { + name: 'find-videos-on-topic', + description: + 'Search YouTube for videos on a topic with filters for duration, recency, and quality.', + content: + '# Find YouTube Videos on a Topic\n\nSurface the most relevant videos for a subject.\n\n## Steps\n1. Build a search query and choose filters: order (relevance, date, view count), duration, and definition.\n2. Call the search operation with a result limit.\n3. For promising results, get video details to read title, channel, view count, and publish date.\n4. Rank the results by relevance and signal.\n\n## Output\nReturn a ranked list of videos with title, channel, URL, view count, and publish date. Note the query and filters applied.', + }, + { + name: 'analyze-channel', + description: + 'Pull a YouTube channel profile and recent uploads to summarize its content and cadence.', + content: + '# Analyze a YouTube Channel\n\nProfile a channel and its recent output.\n\n## Steps\n1. Get channel info to retrieve subscriber count, total views, and description.\n2. Get channel videos to list recent uploads.\n3. Summarize the content themes, upload cadence, and the best-performing recent videos.\n\n## Output\nReturn a channel summary with key stats, dominant content themes, posting frequency, and the top recent videos by views. Cite the channel and video IDs used.', + }, + { + name: 'summarize-video-comments', + description: + 'Fetch comments on a YouTube video and summarize sentiment, questions, and recurring feedback.', + content: + '# Summarize YouTube Video Comments\n\nUnderstand audience reaction to a video.\n\n## Steps\n1. Identify the video ID, searching or using video details if only a title is known.\n2. Call the comments operation to fetch top or recent comments.\n3. Group comments into sentiment, recurring questions, and feature or content requests.\n\n## Output\nReturn a summary with sentiment breakdown, the most common questions, and notable feedback themes. Quote a few representative comments and cite the video ID.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/zendesk.ts b/apps/sim/blocks/blocks/zendesk.ts index 70cc0a18528..9d70eadfe64 100644 --- a/apps/sim/blocks/blocks/zendesk.ts +++ b/apps/sim/blocks/blocks/zendesk.ts @@ -768,4 +768,34 @@ export const ZendeskBlockMeta = { alsoIntegrations: ['salesforce'], }, ], + skills: [ + { + name: 'triage-new-ticket', + description: + 'Read a Zendesk ticket, classify it, and update priority, tags, and assignee accordingly.', + content: + '# Triage a Zendesk Ticket\n\nClassify an incoming ticket and route it correctly.\n\n## Steps\n1. Get the ticket by ID to read the subject, description, and requester.\n2. Classify the issue type, urgency, and the team or queue it belongs to.\n3. Update the ticket with the right priority, tags, and assignee or group.\n4. Optionally add an internal note explaining the triage decision.\n\n## Output\nReport the ticket ID, the classification, and the priority, tags, and assignee set. Note anything that needs human review.', + }, + { + name: 'create-support-ticket', + description: + 'Create a Zendesk ticket from an inbound request, linking it to the right requester.', + content: + '# Create a Zendesk Ticket\n\nLog an inbound issue as a support ticket.\n\n## Steps\n1. Gather the subject, description, and requester details.\n2. Look up the requester with search-users, creating the user if they do not exist.\n3. Call create-ticket with the subject, body, requester, priority, and any tags.\n4. Capture the new ticket ID.\n\n## Output\nReturn the created ticket ID, its priority, and the requester it is linked to. Confirm whether a new user was created.', + }, + { + name: 'search-tickets', + description: + 'Run a Zendesk search to find tickets matching status, requester, or keyword criteria.', + content: + '# Search Zendesk Tickets\n\nFind tickets that match a set of conditions.\n\n## Steps\n1. Express the criteria as a Zendesk search query, for example status, tags, requester, or keyword.\n2. Call the search operation, choosing the right sort order.\n3. Read the results and pull the fields needed for the task.\n\n## Output\nReturn the matching tickets with ID, subject, status, priority, and assignee. State the query used and the total count via search-count if a volume figure is needed.', + }, + { + name: 'sync-organization', + description: + 'Create or update a Zendesk organization and its associated users for account hygiene.', + content: + '# Sync a Zendesk Organization\n\nKeep an organization record and its users accurate.\n\n## Steps\n1. Look up the organization with get-organizations or autocomplete-organizations to check if it exists.\n2. Create the organization, or update it with the latest name, domains, and details.\n3. Reconcile the associated users, creating or updating them so they map to the organization.\n\n## Output\nReport the organization ID and whether it was created or updated, plus a count of users created or updated. List any conflicts found.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/zep.ts b/apps/sim/blocks/blocks/zep.ts index 69cd6c0d8d9..404284cd298 100644 --- a/apps/sim/blocks/blocks/zep.ts +++ b/apps/sim/blocks/blocks/zep.ts @@ -371,4 +371,27 @@ export const ZepBlockMeta = { alsoIntegrations: ['slack'], }, ], + skills: [ + { + name: 'persist-conversation-turn', + description: + 'Record the latest user and agent messages into a Zep thread so memory builds over time.', + content: + '# Persist a Conversation Turn in Zep\n\nSave each exchange so the agent remembers it later.\n\n## Steps\n1. Ensure a user exists for the person, adding the user if this is their first interaction.\n2. Ensure a thread exists for this conversation, creating one if needed and tying it to the user.\n3. Add the latest messages to the thread, tagging roles as user or assistant.\n4. Confirm the messages were stored.\n\n## Output\nReturn the thread ID and user ID used, and confirm how many messages were added. These IDs are reused on the next turn.', + }, + { + name: 'recall-user-context', + description: + 'Fetch the assembled memory context for a Zep thread to ground the next agent response.', + content: + '# Recall User Context from Zep\n\nPull relevant long-term memory before the agent replies.\n\n## Steps\n1. Identify the thread for the current conversation, and the user behind it.\n2. Call get-context for the thread, choosing summary mode for natural language or basic mode for raw facts.\n3. Use the returned context block to inform the next response, since it spans all of this user prior threads.\n\n## Output\nReturn the context block as relevant facts and history about the user. Note the thread and user it was drawn from, and feed it into the agent prompt rather than echoing it to the user.', + }, + { + name: 'review-user-memory', + description: + 'List a user threads and messages in Zep to inspect what the agent remembers about them.', + content: + '# Review What Zep Remembers\n\nInspect the stored memory for a user.\n\n## Steps\n1. Get the user to confirm they exist and read their profile.\n2. Get the user threads to see every conversation tied to them.\n3. Get messages from a thread of interest to read the stored history.\n\n## Output\nReturn a summary of the user threads with counts and key facts surfaced, plus the messages from any thread inspected. Cite the user ID and thread IDs.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/zoom.ts b/apps/sim/blocks/blocks/zoom.ts index b50490d8387..cdac222fdd0 100644 --- a/apps/sim/blocks/blocks/zoom.ts +++ b/apps/sim/blocks/blocks/zoom.ts @@ -743,4 +743,27 @@ export const ZoomBlockMeta = { alsoIntegrations: ['telegram'], }, ], + skills: [ + { + name: 'schedule-meeting', + description: + 'Create a Zoom meeting with a topic, time, and settings, and return the join details.', + content: + '# Schedule a Zoom Meeting\n\nBook a meeting and capture its join link.\n\n## Steps\n1. Gather the host user ID, meeting topic, start time, duration, and timezone.\n2. Choose the meeting type, typically scheduled, and set options like recording and waiting room.\n3. Call the create-meeting operation.\n4. Capture the meeting ID, join URL, and passcode returned.\n\n## Output\nReturn the meeting ID, join URL, passcode, and start time. If you need formatted invite text, fetch the meeting invitation.', + }, + { + name: 'reschedule-meeting', + description: + 'Find a Zoom meeting and update its time, topic, or settings without recreating it.', + content: + '# Reschedule a Zoom Meeting\n\nMove or adjust an existing meeting.\n\n## Steps\n1. Locate the meeting by ID, or list meetings for the host and match on topic.\n2. Get the meeting to read its current settings.\n3. Call update-meeting with only the fields that change, such as start time or duration.\n4. Confirm the update and re-fetch the join details if they changed.\n\n## Output\nReport the meeting ID, the old and new time, and confirm the join URL is unchanged or updated. Note who should be re-notified.', + }, + { + name: 'fetch-meeting-recordings', + description: + 'Retrieve cloud recordings for a past Zoom meeting and return the download links.', + content: + '# Fetch Zoom Meeting Recordings\n\nCollect the recordings from a completed meeting.\n\n## Steps\n1. Identify the meeting ID, or use list-recordings to find recent recorded meetings.\n2. Call get-meeting-recordings for the chosen meeting.\n3. Collect the recording files, their types (video, audio, transcript), and download URLs.\n\n## Output\nReturn each recording file with its type, size, and download URL, plus the meeting topic and date. Note if no recordings exist for the meeting.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/blocks/zoominfo.ts b/apps/sim/blocks/blocks/zoominfo.ts index eaa166fb747..9014dcb21d7 100644 --- a/apps/sim/blocks/blocks/zoominfo.ts +++ b/apps/sim/blocks/blocks/zoominfo.ts @@ -622,4 +622,34 @@ export const ZoomInfoBlockMeta = { tags: ['sales', 'research'], }, ], + skills: [ + { + name: 'enrich-contact', + description: + 'Enrich a known person with ZoomInfo to fill in verified title, email, and company data.', + content: + '# Enrich a Contact with ZoomInfo\n\nFill in verified detail for a known person.\n\n## Steps\n1. Gather the identifiers you have, such as name and company, email, or a profile URL.\n2. Call the enrich-contacts operation.\n3. Extract the returned fields: verified email, direct phone, title, seniority, and company.\n\n## Output\nReturn the enriched contact as structured fields with a match-confidence note. If no match was found, report the input used rather than fabricating values.', + }, + { + name: 'build-target-account-list', + description: + 'Search ZoomInfo companies by firmographic filters to build a list of target accounts.', + content: + '# Build a Target Account List with ZoomInfo\n\nAssemble accounts that fit the ideal-customer profile.\n\n## Steps\n1. Translate the profile into company filters: industry, revenue band, employee size, and location.\n2. Call search-companies with those filters and a result limit, choosing a sort order.\n3. For top accounts, optionally enrich-companies to pull full firmographics.\n\n## Output\nReturn the matched accounts with company name, domain, industry, size, and revenue band. State the filters used and the total match count.', + }, + { + name: 'find-decision-makers', + description: + 'Search ZoomInfo contacts at a target company by title and seniority to find decision makers.', + content: + '# Find Decision Makers with ZoomInfo\n\nLocate the right people inside a target account.\n\n## Steps\n1. Identify the company, then set contact filters for title, department, and seniority.\n2. Call search-contacts scoped to that company.\n3. Enrich the chosen contacts to retrieve verified email and phone.\n\n## Output\nReturn the decision makers with name, title, seniority, and verified contact details. Group by department and note which contacts have verified direct dials.', + }, + { + name: 'compile-account-briefing', + description: + 'Combine ZoomInfo firmographics, intent signals, and news into a pre-meeting account brief.', + content: + '# Compile a ZoomInfo Account Briefing\n\nProduce a one-page brief before an account meeting.\n\n## Steps\n1. Enrich the company to pull firmographics: size, revenue, industry, and location.\n2. Search intent signals for the account to see what topics they are researching.\n3. Search news for recent company developments.\n4. Synthesize these into a concise briefing.\n\n## Output\nReturn a brief with company snapshot, top intent topics, recent news headlines, and two or three suggested talking points. Cite the company referenced.', + }, + ], } as const satisfies BlockMeta diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index e7a83a28ac1..9b39c27b0c8 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -301,7 +301,13 @@ import { ZendeskBlock, ZendeskBlockMeta } from '@/blocks/blocks/zendesk' import { ZepBlock, ZepBlockMeta } from '@/blocks/blocks/zep' import { ZoomBlock, ZoomBlockMeta } from '@/blocks/blocks/zoom' import { ZoomInfoBlock, ZoomInfoBlockMeta } from '@/blocks/blocks/zoominfo' -import type { BlockCategory, BlockConfig, BlockMeta, BlockTemplate } from '@/blocks/types' +import type { + BlockCategory, + BlockConfig, + BlockMeta, + BlockTemplate, + SuggestedSkill, +} from '@/blocks/types' /** All block configs keyed by block type. The execution source of truth. */ const BLOCK_REGISTRY: Record = { @@ -948,6 +954,20 @@ export function getTemplatesForBlock(type: string): ScopedBlockTemplate[] { return collected } +/** + * Popular, ready-to-add skills for a block type. Curated skills live on the + * base integration's meta, but a versioned catalog type (e.g. `notion_v2`) has + * its own meta entry that {@link getBlockMeta} resolves first and which may omit + * skills — so fall back to the stripped base meta. Returns an empty array when + * the integration has no curated skills. + */ +export function getSuggestedSkillsForBlock(type: string): readonly SuggestedSkill[] { + const direct = getBlockMeta(type)?.skills + if (direct && direct.length > 0) return direct + const base = stripVersionSuffix(normalizeType(type)) + return BLOCK_META_REGISTRY[base]?.skills ?? [] +} + /** * Raw block registry map keyed by block type. Prefer the typed accessors * (`getBlock`, `getAllBlocks`, `getCanonicalBlocksByCategory`); this alias is diff --git a/apps/sim/blocks/types.ts b/apps/sim/blocks/types.ts index dd781a17746..b48ead0699f 100644 --- a/apps/sim/blocks/types.ts +++ b/apps/sim/blocks/types.ts @@ -140,10 +140,27 @@ export interface BlockTemplate { alsoIntegrations?: readonly string[] } +/** + * A research-backed, ready-to-add skill suggestion surfaced on an integration's + * detail page. Adding one creates a workspace skill with these exact fields, so + * the shape mirrors `skillUpsertItemSchema` (name is kebab-case, content is + * markdown). Never read by the executor. + */ +export interface SuggestedSkill { + /** kebab-case identifier; becomes the created skill's `name`. */ + name: string + /** One-line summary of what the skill does and when to use it. */ + description: string + /** Skill instructions in markdown; becomes the created skill's `content`. */ + content: string +} + /** Presentation/catalog data for a block. Never read by the executor. */ export interface BlockMeta { tags: readonly IntegrationTag[] templates?: readonly BlockTemplate[] + /** Popular, ready-to-add skills for this integration, shown on its detail page. */ + skills?: readonly SuggestedSkill[] } // Authentication modes for sub-blocks and summaries diff --git a/apps/sim/lib/posthog/events.ts b/apps/sim/lib/posthog/events.ts index a1e0ff734eb..dad68cdf073 100644 --- a/apps/sim/lib/posthog/events.ts +++ b/apps/sim/lib/posthog/events.ts @@ -591,6 +591,18 @@ export interface PostHogEventMap { expanded: boolean } + /** + * A curated "suggested skill" was added to the workspace from an integration's + * detail page. `position` is the skill's index within the integration's list. + */ + integration_skill_added: { + workspace_id: string + integration_type: string + skill_name: string + position: number + skill_count: number + } + workflow_imported: { workspace_id: string workflow_count: number From c85de13180488a97d2cb2b5dc1fa4eead9192113 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 14:53:34 -0700 Subject: [PATCH 2/6] fix(integrations): flip suggested-skill row to Added immediately after add The row derived Added state solely from the useSkills cache, so between a successful create and the list refetch the row still showed Add and could be clicked again, hitting the server duplicate-name check. Track added names in local state so the row reflects the add immediately. --- .../integrations/[block]/integration-skills-section.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx index 7decdf24ac9..1386a5a5cb7 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx @@ -68,6 +68,7 @@ export function IntegrationSkillsSection({ const { data: existingSkills = [] } = useSkills(workspaceId) const createSkill = useCreateSkill() const [pendingName, setPendingName] = useState(null) + const [optimisticAdded, setOptimisticAdded] = useState>(new Set()) const existingNames = useMemo(() => new Set(existingSkills.map((s) => s.name)), [existingSkills]) @@ -75,6 +76,9 @@ export function IntegrationSkillsSection({ setPendingName(skill.name) try { await createSkill.mutateAsync({ workspaceId, skill }) + // Mark added locally so the row flips to "Added" immediately — the list + // refetch that backs `existingNames` lands after this mutation resolves. + setOptimisticAdded((prev) => new Set(prev).add(skill.name)) captureEvent(posthog, 'integration_skill_added', { workspace_id: workspaceId, integration_type: integrationType, @@ -96,7 +100,7 @@ export function IntegrationSkillsSection({ handleAdd(skill, index)} /> From e3e23527ee4516a829d29aaa6a355f8cb12fe304 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 15:11:10 -0700 Subject: [PATCH 3/6] fix(integrations): harden suggested-skill add flow; document skill authoring Address PR review feedback on the suggested-skills section: - Make useSkills the single source of truth for Added state by writing the created skill into the React Query cache onSuccess (fixes stale Added that survived a delete, and the lag that allowed a duplicate click) - Track in-flight adds in a Set so concurrent adds keep independent pending state and cannot be double-submitted - Surface failures with toast.error instead of swallowing the rejection - Extract the duplicated SkillTile into a shared workspace component Also document the new BlockMeta.skills field in the add-block and validate-integration skills (+ blocks AGENTS.md): skills must be grounded in the block's tools.access and sourced from real online use cases, never invented. --- .agents/skills/add-block/SKILL.md | 19 +++++++++ .agents/skills/validate-integration/SKILL.md | 6 +++ .claude/commands/add-block.md | 15 +++++++ .claude/commands/validate-integration.md | 2 + .cursor/commands/validate-integration.md | 1 + .../[workspaceId]/components/index.ts | 1 + .../components/skill-tile/index.ts | 1 + .../components/skill-tile/skill-tile.tsx | 16 ++++++++ .../[block]/integration-skills-section.tsx | 40 ++++++++----------- .../workspace/[workspaceId]/skills/skills.tsx | 12 +----- apps/sim/blocks/AGENTS.md | 1 + apps/sim/hooks/queries/skills.ts | 13 +++++- 12 files changed, 92 insertions(+), 35 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/components/skill-tile/index.ts create mode 100644 apps/sim/app/workspace/[workspaceId]/components/skill-tile/skill-tile.tsx diff --git a/.agents/skills/add-block/SKILL.md b/.agents/skills/add-block/SKILL.md index d65cc549ee0..9563e2785fb 100644 --- a/.agents/skills/add-block/SKILL.md +++ b/.agents/skills/add-block/SKILL.md @@ -651,6 +651,14 @@ export const {Service}BlockMeta = { alsoIntegrations: ['slack'], // Other blocks referenced in the prompt (optional) }, ], + skills: [ // Optional but strongly encouraged + { + name: 'summarize-thread', // kebab-case, becomes the created skill's name + description: 'One line: what it does and when to use it.', + content: + '# Summarize Thread\n\n...\n\n## Steps\n1. ...\n\n## Output\n...', // markdown + }, + ], } as const satisfies BlockMeta ``` @@ -665,6 +673,16 @@ export const {Service}BlockMeta = { - **`alsoIntegrations`** names other block types (e.g. `'slack'`, `'linear'`) referenced in the template prompt — helps the catalog surface this template when those blocks are selected - Place the export **after** the main `{Service}Block` export, at the very bottom of the file +#### `skills` — curated, ready-to-add agent skills + +`skills` is an optional array of `SuggestedSkill` (`{ name, description, content }`) shown on the integration's detail page; users click **Add** to create the skill in their workspace. Aim for 3–5 skills for mainstream services, 2–3 for niche/low-level ones. + +- **`name`** — kebab-case, lowercase letters/numbers/hyphens, ≤ 64 chars, unique within the integration, verb-led (e.g. `summarize-thread`). +- **`description`** — one line, ≤ 1024 chars: what it does and when to use it. +- **`content`** — markdown instructions for the agent (literal `\n` for newlines): a `# Title`, then `## Steps` and an output/guidance section. Keep ~600–2000 chars. +- **Ground every skill in operations the block actually exposes.** Cross-check each skill's steps against the block's `tools.access` list — never describe an action the integration cannot perform (e.g. "receive messages" when the block only sends). +- **Skills MUST be derived from real, popular use cases found online — never invented.** Before adding a skill, web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles). If you cannot source a use case as something people genuinely do with the service, do not add it. Do not hallucinate skills. + ### Register in the blocksMeta object After adding `{Service}BlockMeta` to the block file, register it in `apps/sim/blocks/registry.ts`: @@ -888,6 +906,7 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU - [ ] Outputs match tool outputs - [ ] Block registered in `registry.ts` blocks object (alphabetically) - [ ] `{Service}BlockMeta` exported at bottom of block file with `tags` and `templates` +- [ ] `skills` added to `{Service}BlockMeta`, each grounded in the block's `tools.access` and derived from a real online-sourced use case (not invented) - [ ] `BlockMeta` imported from `@/blocks/types` alongside `BlockConfig` - [ ] Block meta registered in `registry.ts` blocksMeta object (alphabetically) - [ ] If icon missing: asked user to provide SVG diff --git a/.agents/skills/validate-integration/SKILL.md b/.agents/skills/validate-integration/SKILL.md index 2ec88151f15..456294278c3 100644 --- a/.agents/skills/validate-integration/SKILL.md +++ b/.agents/skills/validate-integration/SKILL.md @@ -207,6 +207,12 @@ For **each tool** in `tools.access`: - [ ] `authMode` is set correctly (`AuthMode.OAuth` or `AuthMode.ApiKey`) - [ ] Block is registered in `blocks/registry.ts` alphabetically +### BlockMeta Skills (catalog) +- [ ] `{Service}BlockMeta.skills` is present (3–5 for mainstream services, 2–3 for niche/low-level) +- [ ] **Every skill is grounded** — its steps only use operations the block exposes in `tools.access`; flag any skill that implies an unsupported action (e.g. "receive messages" when the block only sends) +- [ ] **Every skill is real, not hallucinated** — web-search the service and confirm each skill maps to a popular use case attested online (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles). Rewrite or remove any skill you cannot source as something people genuinely do with the service. +- [ ] Each skill has a kebab-case `name` (≤64 chars, unique), a one-line `description`, and markdown `content` with `# Title` + `## Steps` + an output/guidance section + ### Block Inputs - [ ] `inputs` section lists all subBlock params that the block accepts - [ ] Input types match the subBlock types diff --git a/.claude/commands/add-block.md b/.claude/commands/add-block.md index e80a309f0f5..e2f8cd4b745 100644 --- a/.claude/commands/add-block.md +++ b/.claude/commands/add-block.md @@ -807,11 +807,25 @@ export const {Service}BlockMeta = { }, // ... at least 6 more ], + skills: [ // SuggestedSkill[] — 3–5 mainstream, 2–3 niche + { + name: 'summarize-thread', // kebab-case, ≤64 chars, unique, verb-led + description: 'One line: what it does and when to use it.', // ≤1024 chars + content: + '# Summarize Thread\n\n...\n\n## Steps\n1. ...\n\n## Output\n...', // markdown + }, + // ... more + ], } as const satisfies BlockMeta ``` Derive templates from the service's real use cases. Each prompt should name a concrete trigger, transformation, and output — not a generic description of what the service does. +`skills` are curated, ready-to-add agent skills shown on the integration's detail page (users click **Add** to create them in their workspace). Two hard rules: + +- **Ground every skill in operations the block actually exposes** — cross-check each skill's steps against `tools.access`. Never describe an action the integration cannot perform. +- **Derive skills from real, popular use cases found online — never invent them.** Web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles) and only add a skill you can source as something people genuinely do with the service. Do not hallucinate skills. + ## Checklist Before Finishing - [ ] `integrationType` is set to the correct `IntegrationType` enum value @@ -831,6 +845,7 @@ Derive templates from the service's real use cases. Each prompt should name a co - [ ] Optional/rarely-used fields set to `mode: 'advanced'` - [ ] Timestamps and complex inputs have `wandConfig` enabled - [ ] Exported `{Service}BlockMeta` with at least 7 templates +- [ ] `skills` added to `{Service}BlockMeta`, each grounded in `tools.access` and sourced from a real online use case (not invented) ## Final Validation (Required) diff --git a/.claude/commands/validate-integration.md b/.claude/commands/validate-integration.md index c1a9cfe1207..ee188565415 100644 --- a/.claude/commands/validate-integration.md +++ b/.claude/commands/validate-integration.md @@ -197,6 +197,8 @@ For **each tool** in `tools.access`: - [ ] Has at least 7 templates, each with `icon`, `title`, `prompt`, `modules`, `category`, and `tags` - [ ] Prompts describe concrete use cases, not generic descriptions of what the service does - [ ] `alsoIntegrations` is set on any template whose prompt references another service +- [ ] `skills` present (3–5 mainstream, 2–3 niche), each grounded in `tools.access` — flag any skill implying an unsupported action +- [ ] **Each skill is real, not hallucinated** — web-search and confirm it maps to a popular use case attested online (vendor use-case pages, official docs describing the workflow, reputable "top automations" articles); rewrite/remove any you cannot source ### Block Inputs - [ ] `inputs` section lists all subBlock params that the block accepts diff --git a/.cursor/commands/validate-integration.md b/.cursor/commands/validate-integration.md index 8a5c5d2073b..668e6bc741b 100644 --- a/.cursor/commands/validate-integration.md +++ b/.cursor/commands/validate-integration.md @@ -186,6 +186,7 @@ For **each tool** in `tools.access`: - [ ] `icon` references the correct icon component from `@/components/icons` - [ ] `authMode` is set correctly (`AuthMode.OAuth` or `AuthMode.ApiKey`) - [ ] Block is registered in `blocks/registry.ts` alphabetically +- [ ] `{Service}BlockMeta.skills` present (3–5 mainstream, 2–3 niche), each grounded in `tools.access` and confirmed via web search to be a real, popular use case (not hallucinated) — rewrite/remove any you cannot source ### Block Inputs - [ ] `inputs` section lists all subBlock params that the block accepts diff --git a/apps/sim/app/workspace/[workspaceId]/components/index.ts b/apps/sim/app/workspace/[workspaceId]/components/index.ts index d0876513a64..19e2cbd893d 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/index.ts +++ b/apps/sim/app/workspace/[workspaceId]/components/index.ts @@ -27,3 +27,4 @@ export type { SelectableConfig, } from './resource/resource' export { EMPTY_CELL_PLACEHOLDER, Resource, ResourceTable } from './resource/resource' +export { SkillTile } from './skill-tile' diff --git a/apps/sim/app/workspace/[workspaceId]/components/skill-tile/index.ts b/apps/sim/app/workspace/[workspaceId]/components/skill-tile/index.ts new file mode 100644 index 00000000000..e720a00f80c --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/components/skill-tile/index.ts @@ -0,0 +1 @@ +export { SkillTile } from './skill-tile' diff --git a/apps/sim/app/workspace/[workspaceId]/components/skill-tile/skill-tile.tsx b/apps/sim/app/workspace/[workspaceId]/components/skill-tile/skill-tile.tsx new file mode 100644 index 00000000000..7839dac4554 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/components/skill-tile/skill-tile.tsx @@ -0,0 +1,16 @@ +import { AgentSkillsIcon } from '@/components/icons' + +/** + * Square tile bearing the agent-skills glyph. Shared chrome for any surface + * that lists a skill (the Skills page and integration detail pages) so the two + * do not drift. + */ +export function SkillTile() { + return ( +
+
+ +
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx index 1386a5a5cb7..523722c4ba1 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx @@ -3,9 +3,9 @@ import { useMemo, useState } from 'react' import { Check, Plus } from 'lucide-react' import { usePostHog } from 'posthog-js/react' -import { Chip } from '@/components/emcn' -import { AgentSkillsIcon } from '@/components/icons' +import { Chip, toast } from '@/components/emcn' import { captureEvent } from '@/lib/posthog/client' +import { SkillTile } from '@/app/workspace/[workspaceId]/components' import type { SuggestedSkill } from '@/blocks/types' import { useCreateSkill, useSkills } from '@/hooks/queries/skills' @@ -15,16 +15,6 @@ interface IntegrationSkillsSectionProps { integrationType: string } -function SkillTile() { - return ( -
-
- -
-
- ) -} - interface SkillRowProps { skill: SuggestedSkill added: boolean @@ -56,8 +46,8 @@ function SkillRow({ skill, added, pending, onAdd }: SkillRowProps) { /** * Curated, research-backed skills for an integration. Each row adds the skill * to the workspace via the same `useCreateSkill` mutation the Skills page uses; - * a skill already present in the workspace (matched by name) renders as - * "Added" instead of an add button. + * `useSkills` is the single source of truth for the "Added" state, so a skill + * removed elsewhere correctly reverts to "Add". */ export function IntegrationSkillsSection({ skills, @@ -67,18 +57,16 @@ export function IntegrationSkillsSection({ const posthog = usePostHog() const { data: existingSkills = [] } = useSkills(workspaceId) const createSkill = useCreateSkill() - const [pendingName, setPendingName] = useState(null) - const [optimisticAdded, setOptimisticAdded] = useState>(new Set()) + const [pendingNames, setPendingNames] = useState>(new Set()) const existingNames = useMemo(() => new Set(existingSkills.map((s) => s.name)), [existingSkills]) const handleAdd = async (skill: SuggestedSkill, position: number) => { - setPendingName(skill.name) + // Track each in-flight add independently so concurrent adds keep their own + // "Adding..." state and cannot be double-submitted. + setPendingNames((prev) => new Set(prev).add(skill.name)) try { await createSkill.mutateAsync({ workspaceId, skill }) - // Mark added locally so the row flips to "Added" immediately — the list - // refetch that backs `existingNames` lands after this mutation resolves. - setOptimisticAdded((prev) => new Set(prev).add(skill.name)) captureEvent(posthog, 'integration_skill_added', { workspace_id: workspaceId, integration_type: integrationType, @@ -86,8 +74,14 @@ export function IntegrationSkillsSection({ position, skill_count: skills.length, }) + } catch { + toast.error(`Failed to add "${skill.name}" — please try again`) } finally { - setPendingName(null) + setPendingNames((prev) => { + const next = new Set(prev) + next.delete(skill.name) + return next + }) } } @@ -100,8 +94,8 @@ export function IntegrationSkillsSection({ handleAdd(skill, index)} /> ))} diff --git a/apps/sim/app/workspace/[workspaceId]/skills/skills.tsx b/apps/sim/app/workspace/[workspaceId]/skills/skills.tsx index 9834538adcf..f45db472b7a 100644 --- a/apps/sim/app/workspace/[workspaceId]/skills/skills.tsx +++ b/apps/sim/app/workspace/[workspaceId]/skills/skills.tsx @@ -14,7 +14,7 @@ import { ChipModalHeader, Search, } from '@/components/emcn' -import { AgentSkillsIcon } from '@/components/icons' +import { SkillTile } from '@/app/workspace/[workspaceId]/components' import { IntegrationTabsHeader } from '@/app/workspace/[workspaceId]/integrations/components/integration-tabs-header' import { ShowcaseWithExplore } from '@/app/workspace/[workspaceId]/integrations/components/showcase-with-explore' import { SkillModal } from '@/app/workspace/[workspaceId]/skills/components/skill-modal' @@ -29,16 +29,6 @@ const logger = createLogger('SkillsSettings') const SKILLS_LABEL = 'Skills' -function SkillTile() { - return ( -
-
- -
-
- ) -} - interface SkillItemProps { name: string description: string diff --git a/apps/sim/blocks/AGENTS.md b/apps/sim/blocks/AGENTS.md index c82d65915ba..26d76a69a48 100644 --- a/apps/sim/blocks/AGENTS.md +++ b/apps/sim/blocks/AGENTS.md @@ -10,3 +10,4 @@ These rules apply to block definitions under `apps/sim/blocks/**`. - Put type coercion in `tools.config.params`, never in `tools.config.tool`. - When supporting file inputs, follow the basic/advanced pattern and normalize with `normalizeFileInput`. - Keep block outputs aligned with what the referenced tools actually return. +- `{Service}BlockMeta.skills` (curated, one-click-add agent skills shown on the integration detail page) must be grounded in operations the block exposes via `tools.access` and derived from real, popular use cases found online — web-search and source each one; never invent or hallucinate skills. diff --git a/apps/sim/hooks/queries/skills.ts b/apps/sim/hooks/queries/skills.ts index 4fc4b3baf11..81d3846bb87 100644 --- a/apps/sim/hooks/queries/skills.ts +++ b/apps/sim/hooks/queries/skills.ts @@ -74,7 +74,18 @@ export function useCreateSkill() { logger.info(`Created skill: ${s.name}`) return data }, - onSuccess: (_data, variables) => { + onSuccess: (data, variables) => { + // Merge the created skill into the list cache so consumers (e.g. the + // integration detail page's "Added" state) reflect it immediately, + // rather than waiting for the invalidation refetch to land. + queryClient.setQueryData( + skillsKeys.list(variables.workspaceId), + (prev) => { + const byId = new Map((prev ?? []).map((skill) => [skill.id, skill])) + for (const skill of data) byId.set(skill.id, skill) + return Array.from(byId.values()) + } + ) queryClient.invalidateQueries({ queryKey: skillsKeys.list(variables.workspaceId) }) }, }) From 68ea5a07337e176c32d62253c63c5b57c1bf4015 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 15:19:14 -0700 Subject: [PATCH 4/6] fix(integrations): synchronous in-flight guard for skill add; align cursor docs - Guard handleAdd with a ref so two rapid clicks cannot both fire a create before the disabled state re-renders (pendingNames is async) - Fold the create-cache-merge rationale into the hook's TSDoc and drop non-TSDoc inline comments to match the repo convention - Align .cursor add-block/validate-integration command docs with the newer .claude/.agents versions: BlockMeta section + skills authoring/validation guidance (grounded in tools.access, sourced from real online use cases) --- .cursor/commands/add-block.md | 43 +++++++++++++++++++ .cursor/commands/validate-integration.md | 9 +++- .../[block]/integration-skills-section.tsx | 9 ++-- apps/sim/hooks/queries/skills.ts | 7 ++- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/.cursor/commands/add-block.md b/.cursor/commands/add-block.md index 11123168eb5..2ac3c20c9f9 100644 --- a/.cursor/commands/add-block.md +++ b/.cursor/commands/add-block.md @@ -793,6 +793,47 @@ Use `wandConfig` for fields that are hard to fill out manually, such as timestam All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MUST use `snake_case` (e.g., `x_create_tweet`, `slack_send_message`). Never use camelCase or PascalCase. +## BlockMeta (Required) + +Every block file must export a `{Service}BlockMeta` alongside the block — **minimum 7 templates**. Look at existing examples in `apps/sim/blocks/blocks/` (e.g. `browser_use.ts`, `google_sheets.ts`) for the pattern. + +```typescript +import type { BlockMeta } from '@/blocks/types' + +export const {Service}BlockMeta = { + tags: ['tag1', 'tag2'], // IntegrationTag[] + templates: [ + { + icon: {Service}Icon, + title: '{Service} ', // 2–5 words + prompt: 'Build a workflow that...', // specific use case, 1–3 sentences + modules: ['agent', 'workflows'], // 'agent' | 'workflows' | 'tables' | 'files' | 'scheduled' | 'knowledge-base' + category: 'operations', // 'operations' | 'marketing' | 'sales' | 'engineering' | 'productivity' | 'support' | 'popular' + tags: ['automation'], + alsoIntegrations: ['slack'], // optional — other block IDs referenced in the prompt + featured: true, // optional + }, + // ... at least 6 more + ], + skills: [ // SuggestedSkill[] — 3–5 mainstream, 2–3 niche + { + name: 'summarize-thread', // kebab-case, ≤64 chars, unique, verb-led + description: 'One line: what it does and when to use it.', // ≤1024 chars + content: + '# Summarize Thread\n\n...\n\n## Steps\n1. ...\n\n## Output\n...', // markdown + }, + // ... more + ], +} as const satisfies BlockMeta +``` + +Derive templates from the service's real use cases. Each prompt should name a concrete trigger, transformation, and output — not a generic description of what the service does. + +`skills` are curated, ready-to-add agent skills shown on the integration's detail page (users click **Add** to create them in their workspace). Two hard rules: + +- **Ground every skill in operations the block actually exposes** — cross-check each skill's steps against `tools.access`. Never describe an action the integration cannot perform. +- **Derive skills from real, popular use cases found online — never invent them.** Web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles) and only add a skill you can source as something people genuinely do with the service. Do not hallucinate skills. + ## Checklist Before Finishing - [ ] `integrationType` is set to the correct `IntegrationType` enum value @@ -811,6 +852,8 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU - [ ] If triggers exist: `triggers` config set, trigger subBlocks spread - [ ] Optional/rarely-used fields set to `mode: 'advanced'` - [ ] Timestamps and complex inputs have `wandConfig` enabled +- [ ] Exported `{Service}BlockMeta` with at least 7 templates +- [ ] `skills` added to `{Service}BlockMeta`, each grounded in `tools.access` and sourced from a real online use case (not invented) ## Final Validation (Required) diff --git a/.cursor/commands/validate-integration.md b/.cursor/commands/validate-integration.md index 668e6bc741b..2d0b91e91f5 100644 --- a/.cursor/commands/validate-integration.md +++ b/.cursor/commands/validate-integration.md @@ -186,7 +186,14 @@ For **each tool** in `tools.access`: - [ ] `icon` references the correct icon component from `@/components/icons` - [ ] `authMode` is set correctly (`AuthMode.OAuth` or `AuthMode.ApiKey`) - [ ] Block is registered in `blocks/registry.ts` alphabetically -- [ ] `{Service}BlockMeta.skills` present (3–5 mainstream, 2–3 niche), each grounded in `tools.access` and confirmed via web search to be a real, popular use case (not hallucinated) — rewrite/remove any you cannot source + +### BlockMeta +- [ ] `{Service}BlockMeta` is exported in the same file as the block +- [ ] Has at least 7 templates, each with `icon`, `title`, `prompt`, `modules`, `category`, and `tags` +- [ ] Prompts describe concrete use cases, not generic descriptions of what the service does +- [ ] `alsoIntegrations` is set on any template whose prompt references another service +- [ ] `skills` present (3–5 mainstream, 2–3 niche), each grounded in `tools.access` — flag any skill implying an unsupported action +- [ ] **Each skill is real, not hallucinated** — web-search and confirm it maps to a popular use case attested online (vendor use-case pages, official docs describing the workflow, reputable "top automations" articles); rewrite/remove any you cannot source ### Block Inputs - [ ] `inputs` section lists all subBlock params that the block accepts diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx index 523722c4ba1..ca6f86302e4 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx @@ -1,6 +1,6 @@ 'use client' -import { useMemo, useState } from 'react' +import { useMemo, useRef, useState } from 'react' import { Check, Plus } from 'lucide-react' import { usePostHog } from 'posthog-js/react' import { Chip, toast } from '@/components/emcn' @@ -58,12 +58,14 @@ export function IntegrationSkillsSection({ const { data: existingSkills = [] } = useSkills(workspaceId) const createSkill = useCreateSkill() const [pendingNames, setPendingNames] = useState>(new Set()) + /** Synchronous in-flight guard — `pendingNames` state updates async, so two rapid clicks could both pass the `disabled` check before a re-render. */ + const inFlightRef = useRef>(new Set()) const existingNames = useMemo(() => new Set(existingSkills.map((s) => s.name)), [existingSkills]) const handleAdd = async (skill: SuggestedSkill, position: number) => { - // Track each in-flight add independently so concurrent adds keep their own - // "Adding..." state and cannot be double-submitted. + if (inFlightRef.current.has(skill.name)) return + inFlightRef.current.add(skill.name) setPendingNames((prev) => new Set(prev).add(skill.name)) try { await createSkill.mutateAsync({ workspaceId, skill }) @@ -77,6 +79,7 @@ export function IntegrationSkillsSection({ } catch { toast.error(`Failed to add "${skill.name}" — please try again`) } finally { + inFlightRef.current.delete(skill.name) setPendingNames((prev) => { const next = new Set(prev) next.delete(skill.name) diff --git a/apps/sim/hooks/queries/skills.ts b/apps/sim/hooks/queries/skills.ts index 81d3846bb87..aff18855eac 100644 --- a/apps/sim/hooks/queries/skills.ts +++ b/apps/sim/hooks/queries/skills.ts @@ -46,7 +46,9 @@ export function useSkills(workspaceId: string) { } /** - * Create skill mutation + * Create skill mutation. On success the created skill is merged into the list + * cache so consumers (e.g. the integration detail page's "Added" state) reflect + * it immediately, before the invalidation refetch lands. */ interface CreateSkillParams { workspaceId: string @@ -75,9 +77,6 @@ export function useCreateSkill() { return data }, onSuccess: (data, variables) => { - // Merge the created skill into the list cache so consumers (e.g. the - // integration detail page's "Added" state) reflect it immediately, - // rather than waiting for the invalidation refetch to land. queryClient.setQueryData( skillsKeys.list(variables.workspaceId), (prev) => { From e448e639f3cad8e657853f0b55d1f15c416c573c Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 15:25:39 -0700 Subject: [PATCH 5/6] fix(integrations): gate skill Add/Added on authoritative workspace skills MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useSkills uses keepPreviousData, so during initial load or a workspace switch the list could be empty or a prior workspace's placeholder — making rows show a misleading Add (duplicate-submittable) or a false Added. Derive skillsReady from !isPending && !isPlaceholderData, only mark Added when ready, and disable Add until the current workspace's list has loaded. --- .../[block]/integration-skills-section.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx index ca6f86302e4..30345b73318 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx @@ -19,10 +19,11 @@ interface SkillRowProps { skill: SuggestedSkill added: boolean pending: boolean + disabled: boolean onAdd: () => void } -function SkillRow({ skill, added, pending, onAdd }: SkillRowProps) { +function SkillRow({ skill, added, pending, disabled, onAdd }: SkillRowProps) { return (
@@ -35,7 +36,7 @@ function SkillRow({ skill, added, pending, onAdd }: SkillRowProps) { Added ) : ( - + {pending ? 'Adding...' : 'Add'} )} @@ -55,8 +56,10 @@ export function IntegrationSkillsSection({ integrationType, }: IntegrationSkillsSectionProps) { const posthog = usePostHog() - const { data: existingSkills = [] } = useSkills(workspaceId) + const { data: existingSkills = [], isPending, isPlaceholderData } = useSkills(workspaceId) const createSkill = useCreateSkill() + /** List is authoritative for this workspace only once loaded and not `keepPreviousData` placeholder from a prior one. */ + const skillsReady = !isPending && !isPlaceholderData const [pendingNames, setPendingNames] = useState>(new Set()) /** Synchronous in-flight guard — `pendingNames` state updates async, so two rapid clicks could both pass the `disabled` check before a re-render. */ const inFlightRef = useRef>(new Set()) @@ -97,8 +100,9 @@ export function IntegrationSkillsSection({ handleAdd(skill, index)} /> ))} From 04ca966d8b678b1fbc796d006c033cef54d986ba Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 8 Jun 2026 15:27:15 -0700 Subject: [PATCH 6/6] chore(integrations): drop local-variable comments in skills section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep to the repo's TSDoc-on-declarations convention — the in-flight guard and skillsReady derivation are self-evident from naming. --- .../integrations/[block]/integration-skills-section.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx index 30345b73318..91cb688b9c7 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section.tsx @@ -58,10 +58,8 @@ export function IntegrationSkillsSection({ const posthog = usePostHog() const { data: existingSkills = [], isPending, isPlaceholderData } = useSkills(workspaceId) const createSkill = useCreateSkill() - /** List is authoritative for this workspace only once loaded and not `keepPreviousData` placeholder from a prior one. */ const skillsReady = !isPending && !isPlaceholderData const [pendingNames, setPendingNames] = useState>(new Set()) - /** Synchronous in-flight guard — `pendingNames` state updates async, so two rapid clicks could both pass the `disabled` check before a re-render. */ const inFlightRef = useRef>(new Set()) const existingNames = useMemo(() => new Set(existingSkills.map((s) => s.name)), [existingSkills])