From copy-connections
Use this skill as part of the Copy Connections workflow to gather the user's intent, fetch their current Fivetran setup (connections, destinations, transformations), and produce a structured copy plan. Invoke this from the copy-connections coordinator, not directly.
How this skill is triggered — by the user, by Claude, or both
Slash command
/copy-connections:copy-connections-scopeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill produces the copy plan. It's the interactive phase where you learn what the user wants to copy, fetch their current state via the Fivetran MCP, and write a structured plan to `.copy-connections/copy_plan.yaml` that the validate and execute skills will consume.
This skill produces the copy plan. It's the interactive phase where you learn what the user wants to copy, fetch their current state via the Fivetran MCP, and write a structured plan to .copy-connections/copy_plan.yaml that the validate and execute skills will consume.
Credentials are not part of scoping or execution. Copying a connection and adding credentials to it are separate concerns. After execute finishes, a post-execute flow (the copy-connections-credentials skill) offers to help attach credentials, but it's optional. Scope just captures which fields will need credentials eventually, so the results file can tell the user what they'll need.
These must happen in order. Skipping any of them will produce an incomplete or wrong plan.
config blocks (for execute) and schema configs (for the schema skill to apply after credentials are in place)."********") in what Fivetran returns. This is informational (for the results file later); scope doesn't collect credentials.copy_plan.yaml.Between these checkpoints, talk naturally. Don't force the conversation through a rigid script.
Before starting the fresh flow, check if .copy-connections/copy_plan.yaml already exists.
If no existing plan: proceed to step 1 (fresh flow).
If an existing plan exists: tell the user what you see and offer two paths:
"I see a copy plan from [timestamp]. Want to modify it, or start over?"
Modify path:
get_connection_details and get_connection_schema_config — that's new data that doesn't exist in the plan yet.Start-over path:
copy_plan.yaml with the fresh flow output (don't archive the old one unless the user asks — keeping junk files around clutters .copy-connections/).A note on drift. The modify path doesn't re-fetch current state for unchanged connections. This is deliberate: if the user made their decisions based on a snapshot from yesterday and wants to tweak one thing today, forcing them to re-confirm everything they already decided wastes their time. Drift detection happens in copy-connections-validate, which already re-fetches list_connections, list_destinations, and per-connection get_connection_details to catch anything that changed in Fivetran between scope and validate. That's the right place for it.
Before any API calls, get a rough sense of what the user is trying to accomplish. Common patterns:
A short conversational question works — you don't need a form. Something like "What are you trying to accomplish — testing a few connections in a new destination, migrating everything, or something else?" The answer tells you defaults and tone for the rest. Don't force them into a category if their answer is bespoke; just adapt.
Once intent is understood, fetch current state. Run these MCP calls in parallel if possible:
list_destinationslist_groupslist_transformationslist_transformation_projects — to detect custom dbt projects (out of scope for this plugin, but worth flagging)Don't call list_connections at the account level yet — you'll do it filtered to the source group once that's chosen. In large accounts, un-filtered list_connections is wasteful.
If the user's intent made this obvious ("my Redshift setup"), confirm it rather than asking. Otherwise list the destinations they have and ask.
Once you have the source destination, call list_connections filtered to that group (or use the full list and filter locally). Summarize the connections in that group: service type, sync frequency, health/state. If any are in an error state, flag them — the user may want to fix at source before copying.
Also surface what transformations are attached to connections in this group. Quickstart packages and column config both live at the connection level, so they come along with each connection — no separate "source transformation" decision. But telling the user what's configured helps them know what will come along.
If you detect a custom dbt project (transformation project) tied to the source, tell the user: "You have a custom dbt project — that's out of scope for this copy. You'll need to set it up separately on the new destination after we're done here." Don't try to copy it; don't block on it.
Ask whether the target destination already exists.
If it already exists: confirm it by name/id and move on. Warn if the target is the same as the source — that's almost certainly a mistake, but not strictly invalid (e.g., the user might want to copy-and-rename within the same destination).
If it doesn't exist yet: help them create it. Three config options:
Once the config path is resolved, actually create the destination:
create_group for the target group name.create_destination with the composed config (portable fields from source + user-provided fields + type-specific defaults).run_destination_setup_tests. If tests fail, surface the errors and stop — fix the destination before proceeding.create_destination is a write operation — only do it after explicit confirmation. Don't create destinations speculatively.
Now that source and target are locked, ask which connections from the source to include.
Frame the question by intent (from step 1):
For any connections in an error state at the source, ask explicitly whether to include them. Some users want to fix upstream first; others want to debug in the new environment.
Default: copy schema configs as-is. Offer "review each one" as an option for users who want to prune tables or columns before copying.
Most users pick "as-is." Reviewing each connection's schema is tedious; offer it, don't push it.
For each connection in scope, call:
get_connection_details — returns the full config block with credential fields masked as "********"get_connection_schema_config — returns table/column selections and sync_mode per tableFor each Quickstart package attached to a connection in scope, call get_transformation_details to capture the package name and dependencies.
For each connection's config block, scan for masked fields (values equal to "********"). Those are credential fields that will need to be filled in later (during the optional post-execute credentials flow, or manually by the user in the Fivetran UI).
Record these in the plan per connection. Also classify each connection's auth style based on its config shape:
refresh_token, access_token, oauth_*). OAuth connectors can't have their credentials patched via the API — the user must complete auth in the Fivetran UI.The plan records this classification. Scope does not collect credentials and does not ask the user about credential collection mode — credentials happen post-execute, optionally.
Before writing the plan, show the user a table like this:
Copy plan summary:
Intent: Test a few connections before full migration
Source: prod_redshift (Redshift)
Target: snowflake_test (Snowflake) — created just now, portable config copied from prod_redshift
Connections (3 of 4 in prod_redshift, hubspot_marketing excluded):
salesforce_prod → salesforce_prod (Salesforce, 47 tables, OAuth — UI needed for auth later)
postgres_app → postgres_app (Postgres, 12 tables, password needed later)
stripe_prod → stripe_prod (Stripe, 23 tables, API key needed later; hash on customers.email)
Transformations:
stripe_analytics Quickstart package (tied to stripe_prod)
All connection settings (sync frequency, data delay, schedule type, networking method, connector-specific config) are copied exactly as configured in the source.
Note: Connections will be created without credentials and left paused. After the copy:
1. Attach credentials (I can help, or do it yourself in the Fivetran UI)
2. Run setup tests and apply schema config (table/column selections, sync modes, hashing)
3. Unpause when you're ready
Write this plan?
If they confirm, write .copy-connections/copy_plan.yaml. If they want to change something, adjust and re-summarize.
Write .copy-connections/copy_plan.yaml conforming to the schema in schemas/copy_plan.schema.yaml (at the plugin root).
Key fields to capture verbatim from what Fivetran returned:
config block with masked fields replaced by empty strings (don't carry "********" through)enabled, sync_mode, and every column's enabled and hashedauth_style classificationTell the user the plan is written and mention the next step: run validate.
Masked credential fields. Fivetran's get_connection_details returns "********" for credential fields and real values for everything else. Never assume which fields are credentials for a given connector — always scan. Different connectors have different credential shapes (Postgres has password; Stripe has api_key; Salesforce has OAuth tokens that may or may not appear depending on auth method).
Credentials are not part of copying. A connection exists once it's created, even without credentials. Credentials make it sync, not make it exist. This plugin creates connections; adding credentials is a separate, optional post-step. This framing matters for user communication — don't tell them "we need credentials to copy" because we don't.
Connection configs copy verbatim. Every field from the source's config block — sync frequency, data delay threshold, schedule type, networking method, connector-specific settings, everything — is replicated as-is. The only exception is credentials (masked in source, filled in later via the optional credentials flow or the Fivetran UI). Don't selectively choose what to copy; copy everything that isn't credentials. The user's source configuration is their deliberate choice; respect it.
Destination config portability is type-sensitive. Same-type: nearly everything ports except credentials and account-specific identifiers. Cross-type: only type-agnostic fields. Be honest with the user about what's carrying over.
Quickstart packages vs. custom dbt vs. column config. These are three different things that users conflate:
Source connection state doesn't block the copy. If a connection is in auth_token_expired or another error state, copying is still valid — it replicates the current broken config. The user may want to fix at source first, or they may want to debug in the new environment. Ask, don't assume.
enabled_patch_settings.allowed: false is a validation concern, not a scoping concern. Some tables/columns have SYSTEM_TABLE, DELETED, or OTHER reason codes that prevent their enabled flag from being patched. We capture everything in the plan; validation flags which settings won't actually replicate.
Intent shapes defaults, not hard rules. The test-a-few-connections user and the full-migration user can both end up with any scope of connections. Intent is a prior, not a constraint.
In all cases: the plan in .copy-connections/copy_plan.yaml is overwritten, and any existing validation_report.yaml is considered stale (validate must re-run before execute).
If the destination was already created in a prior scoping run and the user now wants to change it, don't auto-delete it — surface that the existing destination is orphaned and ask what to do. Destination cleanup is the user's responsibility.
get_connection_details per-connection is expensive; only do it after the user has confirmed the connection list.Use this as a reference for the feel of the conversation, not a script. The complete end-to-end example with fictional Maya is in the top-level plan document (COPY_CONNECTIONS_PLAN.md Section 7).
User: I want to copy my Fivetran connections from Redshift to a new Snowflake destination.
Claude: What are you trying to accomplish here — testing a few connections in a new warehouse before committing to a full migration, migrating everything over, or something else?
User: Testing a few first. I want to make sure Snowflake works with our data before I move prod.
[fetch current state — list_destinations, list_groups, list_transformations, list_transformation_projects in parallel]
Claude: Got it. You have one Redshift destination (group `prod_redshift`) and no custom dbt projects, so this should be clean. Is `prod_redshift` the source you want to test from?
User: Yes.
[list_connections filtered to prod_redshift]
Claude: Four connections in prod_redshift: salesforce_prod (healthy), postgres_app (healthy), stripe_prod (healthy), and hubspot_marketing (in auth_token_expired state). The stripe one has a Quickstart package (stripe_analytics) and some column config — customers.email is hashed. Salesforce has contacts.ssn blocked.
For the target — does the Snowflake destination already exist, or do I need to create one?
User: Need to create it.
Claude: Three options for the config — copy portable fields from prod_redshift (that's type-agnostic stuff like time zone, processing location, naming conventions), start from Snowflake defaults, or configure from scratch. For a cross-type copy like Redshift → Snowflake, only a few fields port over, but it saves you some setup.
User: Copy portable from prod_redshift is fine.
[... ask for Snowflake credentials, create_group, create_destination, run_destination_setup_tests ...]
Claude: Destination snowflake_test created and tests passed. Now — which of the four connections do you want to include? For a test, I'd suggest 2–3 representative ones. The HubSpot one is broken — worth skipping for a test, unless you specifically want to see how it behaves in the new env.
[... conversation continues through connection selection and schema choices ...]
Claude: Ready to write the plan. Connections will be created without credentials and left paused — after the copy, we'll attach credentials, then run setup tests and apply your schema config (table/column selections, hashing, etc.). Sound good?
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub fivetran/copy-connections