Swirls

SWIRLS_

  • How it works
  • Pricing

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6
← Client OperationsScheduleView on GitHub

CRM Enrichment

Finds Attio companies missing a description, researches each on the web, and writes the findings back onto the record.

integrationmapsearchai

Source

/**
 * CRM enrichment. Once a week it walks the companies in Attio, finds the
 * ones missing a description, researches each on the web, and writes the
 * description and industry back onto the record.
 *
 * Setup:
 *   1. swirls add attio query_records update_record
 *   2. Deploy, then authorize the Attio connection in Cloud -> Connections.
 */

connection team_attio {
  label: "Attio CRM"
  provider: attio
}

schedule weekly_enrichment {
  label: "Weekly Enrichment"
  cron: "0 6 * * 1"
}

workflow enrich_companies {
  label: "Enrich Companies"
  description: "Research companies missing a description in Attio and fill in description and industry."

  root {
    type: code
    label: "Start"
    code: @ts { return { batchSize: 25 } }
    outputSchema: @json {
      {
        "type": "object",
        "properties": { "batchSize": { "type": "number" } }
      }
    }
  }

  node fetch_companies {
    type: integration
    label: "Fetch companies"
    connection: team_attio
    action: attio_query_records
    params: @ts {
      return {
        object: "companies",
        limit: context.nodes.root.output.batchSize
      }
    }
  }

  node enrich_each {
    type: map
    label: "Enrich each company"
    items: @ts {
      const rows = context.nodes.fetch_companies.output.data || []
      return rows.map(r => {
        const values = r.values || {}
        const nameEntry = (values.name && values.name[0]) || {}
        const domainEntry = (values.domains && values.domains[0]) || {}
        const descEntry = (values.description && values.description[0]) || {}
        return {
          record_id: r.id ? r.id.record_id : "",
          name: nameEntry.value || "",
          domain: domainEntry.domain || "",
          description: descEntry.value || ""
        }
      }).filter(c => c.record_id && c.name && !c.description)
    }
    maxItems: 25

    subgraph {
      root {
        type: code
        label: "Company"
        inputSchema: @json {
          {
            "type": "object",
            "properties": {
              "record_id": { "type": "string" },
              "name": { "type": "string" },
              "domain": { "type": "string" }
            }
          }
        }
        code: @ts { return context.iteration.item }
        outputSchema: @json {
          {
            "type": "object",
            "properties": {
              "record_id": { "type": "string" },
              "name": { "type": "string" },
              "domain": { "type": "string" }
            }
          }
        }
      }

      node research {
        type: search
        label: "Research company"
        query: @ts {
          const c = context.nodes.root.output
          return c.name + " " + c.domain + " company overview"
        }
        limit: 5
      }

      node summarize {
        type: ai
        label: "Summarize"
        kind: object
        model: "google/gemini-2.5-flash"
        prompt: @ts {
          const c = context.nodes.root.output
          const results = (context.nodes.research.output.results || [])
            .map(r => "- " + (r.title || "") + ": " + (r.description || ""))
            .join("\n")
          return "Write a two-sentence factual description of the company " + c.name + " (" + c.domain + ") and name its industry in a few words. Only state what the search results support.\n\nSearch results:\n" + results
        }
        schema: @json {
          {
            "type": "object",
            "required": ["description", "industry"],
            "properties": {
              "description": { "type": "string" },
              "industry": { "type": "string" }
            }
          }
        }
      }

      node update_company {
        type: integration
        label: "Update record"
        connection: team_attio
        action: attio_update_record
        params: @ts {
          const c = context.nodes.root.output
          const s = context.nodes.summarize.output
          return {
            object: "companies",
            record_id: c.record_id,
            data: {
              values: {
                description: s.description + " Industry: " + s.industry
              }
            }
          }
        }
      }

      node done {
        type: code
        label: "Record result"
        code: @ts {
          return { name: context.nodes.root.output.name, enriched: true }
        }
      }

      flow {
        root -> research
        research -> summarize
        summarize -> update_company
        update_company -> done
      }
    }
  }

  node summarize_run {
    type: code
    label: "Summarize run"
    code: @ts {
      const rows = (context.nodes.enrich_each.output || []).map(r => r.done).filter(Boolean)
      return { enriched: rows.length, companies: rows.map(r => r.name) }
    }
  }

  flow {
    root -> fetch_companies
    fetch_companies -> enrich_each
    enrich_each -> summarize_run
  }
}

trigger on_weekly_enrichment {
  schedule:weekly_enrichment -> enrich_companies
  enabled: true
}

Flow

Trigger to workflow

weekly_enrichmentschedule
enrich_companies
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

Workflow nodes

CODE
Code Node
Start
INTEGRATION
Integration Node
Fetch companies
MAP
Map Node
Enrich each company
CODE
Code Node
Summarize run
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.