Skip to content

CLI reference

Every command reads saved connections from ~/.solomo/connections.toml. Snowflake and Salesforce commands use the primary connection of each type unless you pass --snowflake NAME or --salesforce NAME.

Run lht <command> --help for the same text shown here, or use python -m lht in place of lht.

Common recipes

# Sync one object, then keep it fresh incrementally
lht sync --sobject Opportunity --table OPPORTUNITY --schema RAW

# Rebuild a table from scratch
lht sync --sobject Account --table ACCOUNT --force-full-sync

# Push a Snowflake query into Salesforce, matching on an external ID
lht retl upsert --sobject Account --match-field External_Id__c --sql-file account_scores.sql

# Clear fields in Salesforce where the query returns NULL
lht retl update --sobject Contact --sql "SELECT Id, Title FROM STAGE.CONTACT_FIXES" --clear-nulls

# Preview a merge without changing anything
lht merge --sobject Account --sql-file dedupe_pairs.sql --dry-run

lht create-connection

usage: lht create-connection [-h] (--snowflake | --salesforce)

Create and save a new connection configuration

options:
  -h, --help    show this help message and exit
  --snowflake   Create a Snowflake connection
  --salesforce  Create a Salesforce connection

lht list-connections

usage: lht list-connections [-h]

Display all saved connection configurations

options:
  -h, --help  show this help message and exit

lht edit-connection

usage: lht edit-connection [-h]

Edit an existing connection configuration

options:
  -h, --help  show this help message and exit

lht set-primary

usage: lht set-primary [-h] connection_name

Set a connection as the primary/default connection for Snowflake or Salesforce

positional arguments:
  connection_name  Name of the connection to set as primary

options:
  -h, --help       show this help message and exit

lht connect

usage: lht connect [-h] connection_name

Verify a saved connection by attempting to connect and perform a basic
operation

positional arguments:
  connection_name  Name of the connection to verify

options:
  -h, --help       show this help message and exit

lht sync

usage: lht sync [-h] --sobject SOBJECT --table TABLE [--schema SCHEMA]
                [--database DATABASE] [--snowflake NAME] [--salesforce NAME]
                [--match-field MATCH_FIELD] [--use-stage]
                [--stage-name STAGE_NAME] [--force-full-sync]
                [--force-bulk-api] [--existing-job-id EXISTING_JOB_ID]
                [--no-delete-job] [--where WHERE]

Synchronize a Salesforce SObject to a Snowflake table

options:
  -h, --help            show this help message and exit
  --sobject SOBJECT     Salesforce object name (e.g., Account, Contact)
  --table TABLE         Snowflake table name
  --schema SCHEMA       Snowflake schema (defaults to connection if available)
  --database DATABASE   Snowflake database (defaults to connection if
                        available)
  --snowflake NAME      Snowflake connection name (defaults to primary
                        connection)
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --match-field MATCH_FIELD
                        Field to use for matching records (default: ID)
  --use-stage           Use Snowflake stage for large datasets
  --stage-name STAGE_NAME
                        Snowflake stage name (required if --use-stage is
                        specified)
  --force-full-sync     Force a full sync regardless of previous sync status
  --force-bulk-api      Force use of Bulk API 2.0 instead of regular API
  --existing-job-id EXISTING_JOB_ID
                        Optional existing Bulk API job ID to use
  --no-delete-job       Do not delete the Bulk API job after completion
  --where WHERE         Optional SOQL WHERE clause to append to the Salesforce
                        query (e.g., "IsPersonAccount = False")

lht retl

usage: lht retl [-h] --sobject SOBJECT (--sql SQL | --sql-file SQL_FILE)
                [--match-field MATCH_FIELD] [--batch-size BATCH_SIZE]
                [--snowflake NAME] [--salesforce NAME] [--clear-nulls]
                [--log-results] [-v]
                {upsert,insert,update,delete}

Push rows from a Snowflake SQL query into a Salesforce SObject using Bulk API
2.0 ingest

positional arguments:
  {upsert,insert,update,delete}
                        Operation to perform in Salesforce

options:
  -h, --help            show this help message and exit
  --sobject SOBJECT     Salesforce object name (e.g., Account)
  --sql SQL             Snowflake SQL SELECT that outputs Salesforce field
                        columns
  --sql-file SQL_FILE   Path to a file containing the Snowflake SQL SELECT
  --match-field MATCH_FIELD
                        External ID field for matching records (required for
                        upsert)
  --batch-size BATCH_SIZE
                        Upsert batch size (default: 25000)
  --snowflake NAME      Snowflake connection name (defaults to primary
                        connection)
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --clear-nulls         Send NULL as #N/A so Salesforce clears the field
                        (upsert/update). Without it a NULL is an empty cell,
                        which Salesforce treats as 'leave unchanged'
  --log-results         (Best-effort) Log ingest results into Snowflake LOGS
                        schema tables
  -v, --verbose         Show detailed progress and debug output

lht merge

usage: lht merge [-h] --sobject SOBJECT (--sql SQL | --sql-file SQL_FILE)
                 [--snowflake NAME] [--salesforce NAME] [--dry-run] [-v]

Merge Salesforce records inside Salesforce using the SOAP API merge() call.
The query returns one row per record to merge away: MasterId survives, LoserId
is merged into it. The master keeps its field values; the loser's related
records move to it. Exits non-zero if any merge fails. Salesforce refuses to
merge accounts that both relate to the same contact: remove the loser's
redundant AccountContactRelation first.

options:
  -h, --help           show this help message and exit
  --sobject SOBJECT    Salesforce object whose records are merged (Account,
                       Contact or Lead)
  --sql SQL            Snowflake SQL SELECT returning MasterId and LoserId
                       columns
  --sql-file SQL_FILE  Path to a file containing the Snowflake SQL SELECT
  --snowflake NAME     Snowflake connection name (defaults to primary
                       connection)
  --salesforce NAME    Salesforce connection name (defaults to primary
                       connection)
  --dry-run            Validate the pairs and report the merge requests
                       without sending anything to Salesforce
  -v, --verbose        Show detailed progress and debug output

lht list-jobs

usage: lht list-jobs [-h] [--salesforce NAME] [--api-version API_VERSION]

List all Bulk API 2.0 query jobs from Salesforce

options:
  -h, --help            show this help message and exit
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --api-version API_VERSION
                        Salesforce API version (default: v58.0)

lht show-job

usage: lht show-job [-h] [--salesforce NAME] [--api-version API_VERSION]
                    job_id

Show detailed information about a specific Bulk API 2.0 query job from
Salesforce

positional arguments:
  job_id                The ID of the Bulk API 2.0 job to retrieve

options:
  -h, --help            show this help message and exit
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --api-version API_VERSION
                        Salesforce API version (default: v58.0)

lht get-job-results

usage: lht get-job-results [-h] [--salesforce NAME]
                           [--api-version API_VERSION]
                           job_id

Download successfulResults, failedResults, and unprocessedrecords for a Bulk
API 2.0 ingest job

positional arguments:
  job_id                The ID of the Bulk API 2.0 ingest job

options:
  -h, --help            show this help message and exit
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --api-version API_VERSION
                        Salesforce API version (default: v58.0)

lht delete-job

usage: lht delete-job [-h] [--salesforce NAME] [--api-version API_VERSION]
                      job_id

Delete a specific Bulk API 2.0 query job from Salesforce

positional arguments:
  job_id                The ID of the Bulk API 2.0 job to delete

options:
  -h, --help            show this help message and exit
  --salesforce NAME     Salesforce connection name (defaults to primary
                        connection)
  --api-version API_VERSION
                        Salesforce API version (default: v58.0)