A Python CLI for migrating users and roles, datasets, experiments, annotation queues, project rules, prompts, charts, Engine issues, and Fleet resources between LangSmith instances, plus CSV-driven access sync for a single LangSmith deployment.
# Install (requires uv: https://docs.astral.sh/uv/)
uv tool install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.83-py3-none-any.whl"
# Set up environment variables
export LANGSMITH_OLD_API_KEY="your_source_api_key"
export LANGSMITH_NEW_API_KEY="your_destination_api_key"
# Test connections
langsmith-migrator test
# Start migrating
langsmith-migrator datasets- All-in-One Wizard: Interactive migration of all resources (
migrate-all) - Users & Roles: Migrate custom roles, org members, and workspace memberships between instances
- Export Users to CSV: Export active org and workspace members to a members CSV (
export-users) that round-trips into theusers --members-csvimporter - Single-Instance Access Sync: Apply CSV-driven add/update or authoritative access sync to one LangSmith instance (
users --csv ... [--sync]), including multi-row workspace role unionization for custom ABAC roles - Datasets: Migrate datasets with examples and file attachments
- Experiments: Include experiments, runs, and feedback during dataset migration (
datasets --include-experiments) or throughmigrate-all - Annotation Queues: Transfer queue configurations
- Project Rules: Copy automation rules with project mapping and optional project creation in interactive flows
- Prompts: Migrate prompts (latest by default, full history with
--include-all-commits) - Charts: Migrate monitoring charts with filter preservation
- Custom Model Pricing: Migrate workspace-custom model price entries (
model-pricing). Global built-in prices are skipped since they already exist in every workspace. Idempotent: an equivalent entry on the destination is updated in place, or skipped with--skip-existing - Engine Issues: Migrate per-project LangSmith Engine issues-agent configs and detected issues as metadata (
issues). Run links and trace deep-links are not migrated (see Limitations) - Fleet: Migrate agents, shared skills, MCP servers, integrations, auth providers, schedules, triggers, webhooks, usage limits, sandbox policies, and workspace secrets (
fleet) - Context Hub: Migrate Context Hub agents and skills (the versioned agent/skill repos in the LangSmith Context Hub), including files and repo metadata (description, readme, tags, is_public) (
contexts). Replays the full commit history by default so the destination reproduces the source's commit chain; use--latest-onlyto copy just the latest commit. Also copies commit tags, including theproduction/stagingenvironment tags behind the Context Hub promote feature, pointing each at the same commit on the destination (--no-tagsto skip). Lists the same contexts the Context Hub UI shows (external-source repos are hidden by default; use--include-externalto migrate them too). Scope with--agents-only/--skills-only; linked-repo commit pins are stripped and reported cross-instance, or preserved with--same-instance - Workspace Scoping: Run resource migrations per workspace pair with explicit IDs or interactive workspace mapping
- Remediation & Resume: Persist migration state, write remediation bundles, print grouped actionable next steps, and retry pending/failed work with
resume - Interactive CLI: TUI-based selection with search/filter, plus
--non-interactivemode for automation
This tool does not support migrating trace data. It migrates:
- Datasets and examples (including file attachments)
- Experiments, runs, and feedback
- Annotation queues
- Project rules
- Prompts
- Charts
- Custom model pricing (workspace-custom model-price-map entries)
- LangSmith Engine issues-agent configs and detected issue metadata
- Fleet resources (agents, skills, MCP servers, integrations, auth providers, schedules, triggers, webhooks, usage limits, sandbox policies, secrets)
- Context Hub agents and skills (full commit history)
For trace data, use LangSmith's Bulk Export functionality: LangSmith Bulk Export Documentation
The issues command migrates two LangSmith Engine resource types: per-project issues-agent configs and the detected issues themselves. Detected issues are migrated as metadata only (name, description, severity, status, tags, plus the Engine-authored proposed_fix and fix_prompt).
An issue's linked runs are not migrated. Issues reference runs by run_id/trace_id, and trace data is not portable across instances (see "Trace Data Not Supported" above). The destination validates every run_id against its own run store, so links pointing at source runs would be rejected. The tool never sends the linked-run list when recreating an issue. To repopulate run links, run Engine on the destination so it re-detects issues against the destination's own traces. For the same reason, fix_branch/fix_pr_number (source-instance GitHub references) and Engine-generated advisory actions are also not sent on create.
Issues-agent configs are recreated with source-instance-only fields stripped (latest_thread_id, latest_run_id, issue counts, tenant, timestamps). GitHub/Context-Hub linkage (github_repo_url, context_hub_repo_handle, etc.) is carried over but only works if the destination has the corresponding integrations configured. Engine-generated advisory actions on an issue (e.g. suggested evaluators) are not migrated: the destination re-validates them strictly on create and regenerates them when Engine runs there. Tip: migrate datasets/projects first (or use migrate-all) so issues map onto existing projects instead of freshly-created empty ones.
By default issues migrates every Engine issue and issues-agent config in the workspace. Use --session <name-or-ID> to scope the migration to a single tracing project (like the charts command's --session flag).
Only tracing projects that actually have Engine data (an issues-agent config or detected issues) are mapped/created on the destination -- the tool fetches the Engine data first and then maps only the projects it references, so other tracing projects in the workspace are never recreated. Project mapping also only considers real tracing projects (it applies the same reference_free filter the UI uses for "Exclude Experiments"), so experiment/test-run sessions are never recreated either. Note that a raw GET /api/v1/sessions call returns both tracing projects and experiment sessions, so the API project count can be higher than what the UI shows by default.
The command is idempotent. Issues-agent configs are skipped if the destination project already has one, and detected issues are skipped if an issue with the same name already exists in the destination project (issue names are unique within a project). Re-running issues only migrates what is missing, so it is safe to run repeatedly. If the destination issue list can't be fetched, the tool falls back to creating issues rather than blocking.
The Fleet API does not return secret values. When migrating workspace secrets, the tool creates placeholder entries on the destination with empty values. You must re-enter each secret's value manually on the destination after migration. Similarly, auth provider client_secret values cannot be read from the source and must be re-entered on the destination.
Agent OAuth connections (Gmail, Slack, GitHub, etc.) are tied to individual user tokens and cannot be transferred between instances. After migration, each user must re-authenticate their OAuth connections on the destination. The tool prints remediation steps listing which agents need re-authentication.
Fleet agent ownership is determined by the authenticated user, not by a field in the request body. Workspace API keys (lsv2_sk_*) do not carry a user identity, so agents created with them have no owner and become invisible to everyone. To assign ownership of migrated agents, use a Personal Access Token (lsv2_pt_*) for LANGSMITH_NEW_API_KEY. The PAT creator becomes the owner of all migrated agents. After migration, individual users can clone their agents from the workspace to transfer ownership to themselves.
The shared_users permission (per-user read/run/write access lists) references user IDs that are org-scoped. The tool fetches the destination workspace's active member list and filters shared_users to keep only user IDs that exist on the destination. User IDs not found on the destination are removed, and the tool prints a warning. If the destination member list can't be fetched, all shared_users are stripped as a safety measure. Re-share agents with any missing users after migration via the Fleet UI.
The destination instance may not support the same model IDs as the source (e.g. SaaS vs BYOC may offer different model providers). The tool fetches the destination's model catalog and substitutes unavailable models with a model from the same provider if available, or falls back to the first available model. A warning is logged for each substitution. Set the correct model manually after migration if needed.
All Fleet migrators skip resources that already exist on the destination, regardless of the --skip-existing flag. This prevents overwriting org-scoped infrastructure (auth providers, MCP servers, integrations) that may already be correctly configured on the destination. Re-running fleet is safe and idempotent.
OAuth providers, GitHub App, and Slack app configuration are set at the infrastructure level (Helm chart for self-hosted, or cloud provider console). The tool cannot migrate these. For BYOC deployments, configure OAuth providers in your langsmith_config.yaml as described in the self-hosted Fleet setup docs.
The destination's POST /runs/batch endpoint rejects runs with timestamps outside a 24-hour window of "now", so historical experiments cannot be replayed with their original timestamps. To migrate experiment runs at all, this tool shifts every run's start_time, end_time, dotted_order, and events[].time (and the parent experiment's start_time/end_time) by a per-experiment delta so the newest timestamp lands at migration time. Relative offsets between runs within the same experiment are preserved exactly. The delta is persisted in migration state so resumed migrations apply the same shift to remaining runs.
- Full commit history by default: the tool enumerates each context's commit chain (via
list_prompt_commits, which works for directory-type repos) and replays every commit oldest-to-newest on the destination, chainingparent_commit. Because Context Hub directory commits are content-addressed, this reproduces the source's exact commit hashes and history. Pass--latest-onlyto instead copy just the latest commit as a single fresh commit. - Commit tags and environments: all commit tags are copied by default, including the
production/stagingenvironment tags that back the Context Hub promote feature. Each tag is re-created on the destination pointing at the commit with the same content-addressed hash. Under--latest-only, a tag whose target commit was not migrated is skipped and reported. Use--no-tagsto skip tag migration entirely. - Linked repos: a context's
filesmap can link to another agent/skill repo (skills/<name>,agents/<name>) instead of inlining content. Cross-instance, the source-instance commit pin on each link is stripped so the link resolves to the destination's latest commit of the linked repo, and the downgrade is reported. Migrate linked repos separately (and re-pin if you need reproducibility). Pass--same-instanceto preserve link pins verbatim. - External-source contexts hidden by default: the tool lists contexts exactly as the Context Hub UI does, which excludes repos whose
sourceisexternal(agents/skills created by an external harness such as the Agent Builder, typically with raw-UUID handles). These are hidden by default; pass--include-externalto migrate them too. Note that externally-created repos often have UUID handles, and the destination rejects a repo handle that does not match^[a-z][a-z0-9-_]*$(must start with a lowercase letter), so such repos fail on create and are reported. - Owner: migrated contexts are owned by the identity behind the destination API key.
Prerequisites: Python 3.12+, uv
uv tool install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.83-py3-none-any.whl"
# To update an existing installation, use --force:
uv tool install --force "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.83-py3-none-any.whl"uvx --from "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.83-py3-none-any.whl" langsmith-migrator testpip install "langsmith-data-migration-tool @ https://github.com/langchain-ai/langsmith-data-migration-tool/releases/latest/download/langsmith_data_migration_tool-0.0.83-py3-none-any.whl"git clone https://github.com/langchain-ai/langsmith-data-migration-tool.git
cd langsmith-data-migration-tool
uv sync
# Run with: uv run langsmith-migrator <command>export LANGSMITH_OLD_API_KEY="your_source_api_key"
export LANGSMITH_NEW_API_KEY="your_destination_api_key"
# Optional: Custom base URLs (default: https://api.smith.langchain.com)
export LANGSMITH_OLD_BASE_URL="https://your-source-instance.com"
export LANGSMITH_NEW_BASE_URL="https://your-destination-instance.com"Or use a .env file (auto-loaded on startup):
LANGSMITH_OLD_API_KEY=your_source_api_key
LANGSMITH_NEW_API_KEY=your_destination_api_key
LANGSMITH_OLD_BASE_URL=https://your-source-instance.com
LANGSMITH_NEW_BASE_URL=https://your-destination-instance.com
LANGSMITH_VERIFY_SSL=true# Test connections
langsmith-migrator test
# Interactive wizard for all resources
langsmith-migrator migrate-all
langsmith-migrator migrate-all --rules-create-enabled # Create migrated rules as enabled
# Datasets
langsmith-migrator datasets # Interactive selection
langsmith-migrator datasets --all # All datasets
langsmith-migrator datasets --include-experiments # With experiments, runs, and feedback
# Note: When running `datasets` without `--include-experiments`, you'll be prompted
# interactively whether to include experiments. Experiments include all runs and feedback.
# Annotation queues
langsmith-migrator queues
# Prompts
langsmith-migrator prompts
langsmith-migrator prompts --all --include-all-commits
# Project rules
langsmith-migrator rules
langsmith-migrator rules --strip-projects # As global rules
langsmith-migrator rules --project-mapping '{"old-project-id": "new-project-id"}'
langsmith-migrator rules --project-mapping mapping.json # From file
langsmith-migrator rules --map-projects # Interactive TUI project mapping
langsmith-migrator rules --create-enabled # Create rules enabled (default: disabled)
# Charts
langsmith-migrator charts
langsmith-migrator charts --session "project-name"
langsmith-migrator charts --map-projects # Interactive TUI project mapping
langsmith-migrator charts --project-mapping '{"old-project-id": "new-project-id"}' # Headless, no TUI
langsmith-migrator charts --project-mapping mapping.json # Headless, from file
langsmith-migrator charts --same-instance # Reuse source IDs only when both sides share IDs
# Custom model pricing (model-price-map)
langsmith-migrator model-pricing # Copy workspace-custom model prices (built-in prices are skipped)
# Fleet resources (agents, skills, MCP servers, etc.)
langsmith-migrator fleet # Migrate all Fleet resources
langsmith-migrator fleet --skip-agents # Skip agent migration
langsmith-migrator fleet --skip-skills --skip-mcp-servers # Skip specific resources
langsmith-migrator fleet --agent "My Agent" --agent agent-abc123 # Only these agents (by name or ID)
langsmith-migrator fleet --agents-owned-only # Only agents you own or are directly shared
# Utilities
langsmith-migrator export-users --source -o users.csv # Export active members to a members CSV
langsmith-migrator list-projects --source
langsmith-migrator list_workspaces --source --dest
langsmith-migrator resume # Resume pending/failed items from a prior migration session
langsmith-migrator cleantest: verify source and destination connectivity before running a migrationmigrate-all: guided end-to-end wizard for users, datasets, prompts, queues, rules, charts, custom model pricing, and Fleet resourcesdatasets: migrate datasets; optionally include experiments, runs, and feedbackqueues: migrate annotation queuesprompts: migrate prompts, optionally with full commit historyrules: migrate automation rules with project mapping controlscharts: migrate monitoring charts, either all sessions or one named session/projectmodel-pricing: migrate workspace-custom model price entries (global built-in prices are skipped; idempotent, with--skip-existing)fleet: migrate Fleet resources (agents, skills, MCP servers, integrations, auth providers, schedules, triggers, webhooks, usage limits, sandbox policies, secrets) with--skip-*flags for each resource type, and--agent <name-or-id>/--agents-owned-onlyto scope which agents (and their schedules/triggers/usage limits) are migratedissues: migrate Engine issues-agent configs and detected issues as metadata (--sessionto scope to one tracing project)contexts: migrate Context Hub agents and skills, replaying full commit history and tags by default (--latest-only,--no-tags,--agents-only,--skills-only,--include-external,--same-instance)users: migrate users/roles between instances, or run single-instance CSV access syncexport-users: export active org and workspace members to a members CSV for import viausers --members-csvresume: retry resumable items from a prior session and show grouped manual blockerslist-projects/list_workspaces: inspect project and workspace IDs for mappingclean: remove saved migration sessions
Use export-users to write the active org and workspace members of an instance to a members CSV. The output uses the exact columns the importer expects (email, langsmith_role, workspace_id, workspace_name), so an export from one instance feeds straight into users --members-csv on another.
# Export everything from the source instance (default output: users.csv)
langsmith-migrator export-users --source -o users.csv
# Export from the destination instead
langsmith-migrator export-users --dest -o dest_users.csv
# Org-level memberships only (skip workspace members)
langsmith-migrator export-users --source --org-only -o org_users.csv
# Restrict workspace membership export to specific workspace IDs (repeatable)
langsmith-migrator export-users --source --workspace ws_a --workspace ws_b -o subset.csvNotes:
- Pending invites are not exported — only accepted (
active) memberships are included. - Built-in roles are written with their display label (e.g.
Organization Admin); custom roles use their display name. - Members whose role can't be mapped to a CSV label are still exported but with an empty
langsmith_role; the command lists them so you can fill the value in before importing. --sourceis the default if neither--sourcenor--destis given;--org-onlycannot be combined with--workspace.
When importing into a different instance, the CSV's workspace_id values are the source workspace IDs — map them to the destination with users --members-csv ... --source-workspace <SRC> --dest-workspace <DST> (or --map-workspaces).
When running users, you can provide member details from CSV instead of source member list APIs:
langsmith-migrator users --members-csv examples/users_members_example.csv --map-workspacesFor a single deployed LangSmith instance, users can also run as an access-sync command instead of a source→destination migration.
Safe default: add or update access from the CSV without removing anyone:
langsmith-migrator users \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csvPreview the same run without making changes:
langsmith-migrator users \
--dry-run \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csvAuthoritative mode: make the CSV the source of truth for access and remove anything not present:
langsmith-migrator users \
--api-key "$LANGSMITH_API_KEY" \
--url "https://your-langsmith-instance.example.com" \
--csv examples/users_members_example.csv \
--syncEquivalent explicit form:
langsmith-migrator \
--dest-key "$LANGSMITH_API_KEY" \
--dest-url "https://your-langsmith-instance.example.com" \
users \
--single-instance \
--members-csv examples/users_members_example.csv \
--csv-source-of-truthIn --single-instance mode, the command mirrors the provided instance configuration onto both internal clients, so you only need one working LangSmith connection. Workspace rows use the target workspace IDs directly; there is no workspace mapping step. All CSV rows are applied automatically after a single confirmation summary; there is no row-selection step in this mode. --api-key/--url imply --single-instance, --csv is a short alias for --members-csv, and --sync is a short alias for --csv-source-of-truth.
users --dry-run is also supported as a command-local preview flag if you prefer to put dry-run after the subcommand instead of before it.
For cron jobs and other headless runs, users --non-interactive is also supported as a command-local alias for the global langsmith-migrator --non-interactive users ... form. In headless mode, missing credentials fail fast instead of prompting.
CSV schema:
email,langsmith_role,workspace_id,workspace_name
alice@example.com,Organization Admin,,
alice@example.com,Workspace Admin,ws_src_prod_us,Production USExample CSVs:
examples/users_members_example.csv: minimal org and workspace member rows.examples/users_members_multi_workspace_roles_example.csv: users with multiple workspace assignments, including different workspace roles.examples/users_members_sync_remove_workspace_b_example.csv: desired-state CSV for--csv-source-of-truthwhen a user should keep Workspace A and lose Workspace B.examples/users_members_sync_remove_user_example.csv: desired-state CSV for--csv-source-of-truthafter a removed user has been omitted entirely.examples/users_members_pending_mixed_workspace_roles_example.csv: pending-invite examples for same-role multi-workspace invites and mixed workspace-role rows.
These examples are templates. Do not run them with --csv-source-of-truth against a populated target unless the file has been expanded into the full desired org and workspace access state for that target; authoritative sync removes org users, pending invites, and workspace memberships that are not listed.
Notes:
emailandlangsmith_roleare required.workspace_idis optional. Leave it empty for org-level role assignments.workspace_nameis optional. When provided in single-instance CSV sync, it is validated against the target workspace display name, name, or tenant handle;workspace_idremains authoritative for applying access.langsmith_roleshould be a built-in LangSmith role name (for exampleOrganization Admin,Organization Operator,Organization User,Organization Viewer,Workspace Admin,Workspace User, orWorkspace Viewer) or a custom roledisplay_name.- Multiple rows for the same user and workspace are combined. Built-in workspace roles collapse to the highest-privilege built-in role; custom ABAC roles are unioned with each other and with any built-in workspace role so their policy attachments are preserved.
- Users who only appear in workspace rows are invited to the org with the source
ORGANIZATION_USERrole before workspace membership is applied. - Workspace-only users with multiple workspace roles cannot have all workspace access attached to the initial org invite. The command calls this out before apply, attempts phase 3 workspace membership application, and may require a rerun after the invite is accepted on target versions that block workspace membership for pending org invites.
Organization Adminon a workspace row is treated as org-level admin access only. No explicit workspace membership is created because org admins already have workspace access.- Other org-scoped roles cannot be used on workspace rows. If you want org-level access, leave
workspace_idempty. - Workspace-scoped roles such as
Workspace Admincannot be used on org-level rows. --sync/--csv-source-of-truthis the only mode that removes access. Without it, single-instance CSV mode only adds or updates access.--csv-source-of-truthis available with--single-instanceand makes the CSV authoritative for access:- users missing from the CSV are removed from the org
- pending org invites missing from the CSV are cancelled
- workspace memberships missing from the CSV are removed
- workspaces omitted from the CSV are treated as having no desired memberships
Guardrails:
--api-keyand--urlmust be provided together when either is used.--single-instancerequires--csv/--members-csv.--syncrequires--csvand cannot be combined with--skip-existingor--skip-workspace-members.--single-instancecannot be combined with workspace mapping flags.--roles-onlycannot be combined with--single-instanceor--members-csv.- If the CSV contains workspace rows and
--skip-workspace-membersis set, the command fails instead of silently ignoring those rows. - If the CSV contains workspace-only users, the target instance must have an
ORGANIZATION_USERrole available or the command fails before applying member changes. - If the CSV references unknown
workspace_idvalues, the command fails before any membership changes are applied.
Operational notes:
- Authoritative sync can remove active org members, cancel pending invites, and remove workspace memberships. Use an Organization Admin PAT for unattended runs that need removal semantics.
- If the destination API key cannot manage org members or pending invites, 401/403 responses are reported as Organization Admin PAT blockers with grouped remediation and resume metadata.
- Pending invites whose org role or workspace access does not match the CSV are refreshed when the target supports invite cancellation; if the target lacks a cancellation endpoint, the command reports an explicit manual follow-up instead of silently accepting stale access.
--source-key TEXT Source API key
--dest-key TEXT Destination API key
--source-url TEXT Source base URL
--dest-url TEXT Destination base URL
--no-ssl Disable SSL verification
--batch-size INTEGER Batch size for operations (1-1000, default: 100)
--workers INTEGER Number of concurrent workers (1-10, default: 4)
--dry-run Run without making changes
--skip-existing Skip existing resources instead of updating them
--non-interactive Disable prompts and exit with code 2 when remediation is required
--verbose, -v Verbose output--include-experiments Include experiments with datasets
--all Migrate all datasets--all Migrate all prompts
--include-all-commits Include all commit history--strip-projects Strip project associations and create as global rules
--project-mapping TEXT JSON string or file path with project ID mapping (e.g., '{"old-id": "new-id"}')
--map-projects Launch interactive TUI to map source projects to destination projects
--create-enabled Create rules as enabled (default: disabled to bypass secrets validation)
--all Migrate all rules without interactive selection--rules-create-enabled Create migrated rules as enabled (default: disabled)If --rules-create-enabled is omitted, migrate-all asks interactively whether to create rules enabled.
The prompt default is No (rules are created disabled).
--skip-users Skip user and role migration
--skip-datasets Skip dataset migration
--skip-experiments Skip experiment migration
--skip-prompts Skip prompt migration
--skip-queues Skip annotation queue migration
--skip-rules Skip rules migration
--skip-charts Skip chart migration
--include-all-commits Include all prompt commit history
--strip-projects Strip project associations from rules
--map-projects Launch interactive TUI to map source projects to destination projects
--project-mapping TEXT JSON string or file path with project ID mapping (headless, no TUI; mutually exclusive with --map-projects)
--rules-create-enabled Create migrated rules as enabled instead of asking interactively--session TEXT Migrate charts for a specific session/project (by name or ID)
--map-projects Launch interactive TUI to map source projects to destination projects
--project-mapping TEXT JSON string or file path with project ID mapping (headless, no TUI; mutually exclusive with --map-projects)
--same-instance Reuse source project/session IDs on destination only when both sides truly share IDs--dry-run Preview this users sync without making POST/PATCH/DELETE changes
--non-interactive Disable prompts for this users run. Same as the global --non-interactive.
--roles-only Only migrate custom roles (skip member migration)
--skip-workspace-members Skip workspace member migration
--single-instance, --instance
Use one target LangSmith instance for CSV-driven access sync instead of source→destination migration
--csv-source-of-truth, --sync
Make the CSV authoritative for single-instance sync: any active org user or pending invite not
present in the CSV will be removed, and workspace memberships not present in the CSV will also
be removed. Without this flag, CSV mode only adds or updates access.
--members-csv, --csv PATH CSV file with member details (email, langsmith_role, workspace_id, workspace_name)
Replaces source member API lookups. In --single-instance mode, all CSV rows are applied
automatically.
--api-key TEXT API key for the single-instance CSV sync target. Must be provided together with --url.
--url TEXT Base URL for the single-instance CSV sync target. Must be provided together with --api-key.
--source-workspace TEXT Source workspace ID (skip auto-detection)
--dest-workspace TEXT Destination workspace ID (skip auto-detection)
--map-workspaces Force workspace mapping TUI even for single-workspace instancesThese flags are available on datasets, queues, prompts, rules, charts, migrate-all, and users:
--source-workspace TEXT Source workspace ID (skip auto-detection)
--dest-workspace TEXT Destination workspace ID (skip auto-detection)
--map-workspaces Force workspace mapping TUI even for single-workspace instancesMigration proceeds in three phases:
- Role sync (org-scoped): match built-in roles by name, create/update custom roles
- Org members (org-scoped): invite missing members, update roles for existing ones
- Workspace members (per workspace pair): add members to workspaces with correct roles
Rules are created disabled by default. Use --create-enabled on the rules command to override.
--skip-users Skip user and role migration in migrate-all wizardWhen --skip-users is omitted, migrate-all runs user/role migration as Step 0 before all other resources. Phases 1-2 (roles + org members) run once; phase 3 (workspace members) runs per workspace pair.
Rules and charts reference projects by ID. When migrating between instances, project IDs differ.
- Interactive TUI (
--map-projects): Launch a visual TUI to map source projects to destination projects. Available onrules,charts,issues, andmigrate-allcommands. Select a source project and type a destination name directly — existing projects appear as filterable suggestions below the input, and pressingEnteron a unique suggestion records the destination project ID used by downstream chart/rule validation. Supports auto-match by name, skip, and custom name entry. For ID-based chart/rule remapping, unresolved text entries remain unmapped instead of being counted as resolved. - Headless mapping (
--project-mapping): Available onrules,charts, andmigrate-all. Supply an explicit source->destination project ID mapping as a JSON string or a file path (e.g.'{"<source-project-id>": "<dest-project-id>"}'). Uselist-projects --sourceandlist-projects --destto get IDs. This runs the mapping with no interactive TUI, so the migration can be driven from a backend/CI onboarding job. Forrules, the mapping is applied to both top-level project associations and project IDs embedded inside rule filters. Mutually exclusive with--map-projects. - Rules queue targets: When a rule references an annotation queue, the migrator first reuses any saved queue migration mapping, then falls back to an exact-name queue match in the destination workspace. If neither is safe, the rule is exported for remediation instead of being posted with the source queue ID.
- Charts: Without
--map-projects, project mapping is built automatically by matching project names between source and destination. When both sides point at the same deployment URL but use different API keys/workspaces, charts still remap project/session IDs; the tool does not treat that as--same-instance. Workspace-scoped--map-projectsmappings are resolved against the active workspace pair so duplicate project names in other workspaces are ignored. Chart dependency validation also verifies that saved destination project IDs still exist before migration. Chart filters are normalized to the destination API'ssession/session_idproject-scoping shape before create or update. migrate-all: Supports--strip-projects,--map-projects,--project-mapping(headless JSON/file mapping applied to both rules and charts), and--rules-create-enabledfor rules.
Keyboard shortcuts in resource selection TUI:
↑↓Navigate |SpaceToggle |aSelect all |nClear/Search |EnterConfirm |EscCancel
Keyboard shortcuts in project mapper TUI (--map-projects):
Enter/SpaceEdit destination |sSkip |mSame name |uUnmapaAuto-match all |/Search |Ctrl+SSave |EscCancel
Keyboard shortcuts in workspace mapper TUI (--map-workspaces):
EnterPick destination |nCreate new |cCreate all unmappedpMap projects |sSkip |aAuto-match all |uUnmapCtrl+SSave |EscCancel
For multi-workspace organizations, all resource commands support workspace-scoped migration:
# Interactive workspace mapping TUI (available on all commands)
langsmith-migrator datasets --map-workspaces
langsmith-migrator queues --map-workspaces
langsmith-migrator prompts --map-workspaces
langsmith-migrator rules --map-workspaces --map-projects
langsmith-migrator charts --map-workspaces --map-projects
langsmith-migrator migrate-all --map-workspaces
# Explicit workspace pair
langsmith-migrator datasets --source-workspace WS_ID --dest-workspace WS_IDWhen using --map-workspaces, each command iterates all mapped workspace pairs, running the full fetch/select/migrate flow per pair. For rules and charts with --map-projects, the project mapping TUI is shown per workspace pair so projects are correctly scoped.
Every migration session persists state and writes a remediation bundle when there are blocked or manual-follow-up items.
- Session state is stored under
~/.langsmith-migrator/state. - Remediation bundles are written under
./.langsmith-migrator/remediation/<session_id>by default. - The CLI prints a Resolution Summary with grouped Actionable Next Steps instead of one repeated line per failed item.
--non-interactivedisables prompts and exits with status code2if manual remediation is still required.
langsmith-migrator resume retries pending or failed items from a previous session. Today that includes:
- datasets
- experiments
- prompts
- annotation queues
- rules
- charts
- org members
- workspace members
Each item gets a budget of three failed attempts before resume stops picking it up automatically. Failures are what consume the budget, so an item that failed once still has two retries left. If an item does use up its budget and you want to try again anyway (for example once a network or permissions problem has been resolved), pass --retry-exhausted:
langsmith-migrator resume --retry-exhaustedItems that are blocked rather than failed (a missing dataset dependency, say) are not retried by resume at all, since retrying cannot resolve them. Those are listed separately under "Items requiring manual attention" along with the action needed.
For chart items, resume revalidates saved --same-instance metadata against the current source/destination and workspace context. If the mode changed, it re-resolves the destination project/session before retrying; if that cannot be resolved safely, the item is checkpointed with guidance to rerun charts with project mapping. A later successful charts --map-projects run marks the prior chart dependency blocker resolved so resume does not keep looping on stale blocked state. Global or dataset-only charts that have no project/session dependency can resume with dest_session_id=None.
Use langsmith-migrator clean to remove saved sessions once you no longer need their state or remediation bundles.
For self-hosted instances with SSL errors:
# Use --no-ssl flag
langsmith-migrator --no-ssl datasets
# Or set environment variable
export LANGSMITH_VERIFY_SSL=falseMIT License - see LICENSE for details.
Contributions welcome! Fork, create a feature branch, and submit a Pull Request.
For release changes, update all of:
pyproject.tomlversionCHANGELOG.mdrelease notesREADME.mdrelease-facing docs/examples
CI enforces this on pull requests: if pyproject.toml or CHANGELOG.md changes, README.md must also be updated (including dependency-only bumps).
For issues or questions: GitHub repository