From product
Orchestrates Oracle to ScalarDB migration: collects DB connection params, updates config, runs schema extraction, migration analysis, AQ integration, and SP/trigger-to-Java conversion.
How this skill is triggered — by the user, by Claude, or both
Slash command
/product:migrate-oraclesonnetThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Orchestrates the complete Oracle to ScalarDB migration workflow through an interactive chat interface. Collects database connection parameters from the user via questions, updates the configuration file, then runs the analysis and migration skills.
analyze-oracle-schema/analyze-oracle-dbms_report.mdanalyze-oracle-schema/requirements.txtanalyze-oracle-schema/scripts/oracle_db_extractor.pymigrate-oracle-aq-to-scalardb/reference/AQ-official-docs/23 - Oracle Database Advanced Queuing (AQ)_Html.txtmigrate-oracle-aq-to-scalardb/reference/AQ-official-docs/24 - Oracle Database Advanced Queuing (AQADM)_Html.txtmigrate-oracle-aq-to-scalardb/reference/AQ-official-docs/25 - Oracle Advanced Queuing (AQ) DBMS_AQELM.txtmigrate-oracle-aq-to-scalardb/reference/aq-exception-handling-strategy.mdmigrate-oracle-aq-to-scalardb/reference/aq-migration-strategy-guide.mdmigrate-oracle-aq-to-scalardb/templates/scalardb_aq_migration_report.mdmigrate-oracle-sp-trigger-to-scalardb/reference/migration-strategy-guide-sp-triggers-to-scalardb.mdmigrate-oracle-sp-trigger-to-scalardb/templates/scalardb_sp_migration_report.mdmigrate-oracle-to-scalardb/reference/scalardb_reference.mdmigrate-oracle-to-scalardb/templates/scalardb_migration_analysis.mdmigrate-oracle-to-scalardb/templates/scalardb_migration_steps.mdOrchestrates the complete Oracle to ScalarDB migration workflow through an interactive chat interface. Collects database connection parameters from the user via questions, updates the configuration file, then runs the analysis and migration skills.
You MUST follow these steps exactly in order. Do NOT skip any step.
Run the following Bash command to get the plugin installation directory:
echo "$CLAUDE_PLUGIN_ROOT"
PLUGIN_ROOT to that value.find ~/.claude/plugins -name "plugin.json" -path "*/architect/*" 2>/dev/null | head -1 | xargs -I{} dirname {} | xargs -I{} dirname {}
Store the result as PLUGIN_ROOT. All subagent template paths in Steps 7–12 use this variable (e.g., PLUGIN_ROOT/skills/common/subagents/oracle/0-test-connection.md).
First, attempt to read the current configuration file:
Read file: .claude/configuration/databases.env
Two possible outcomes:
A) File EXISTS → Set CONFIG_EXISTS = true
B) File DOES NOT EXIST → Set CONFIG_EXISTS = false
mkdir -p .claude/configurationBuild the questions based on CONFIG_EXISTS:
If CONFIG_EXISTS = true: Include "Keep current" options with actual values in descriptions (e.g., "Keep current" with description "Keep: 98.130.78.220").
If CONFIG_EXISTS = false: Replace "Keep current" options with additional useful defaults instead. Do NOT offer "Keep current" since there is nothing to keep.
Use the AskUserQuestion tool:
{
"questions": [
{
"question": "What is the Oracle database host?",
"header": "Host",
"options": [
{"label": "localhost", "description": "Database running on local machine"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_ORACLE_HOST>"}
: {"label": "127.0.0.1", "description": "Loopback IP address"}
],
"multiSelect": false
},
{
"question": "What is the Oracle listener port?",
"header": "Port",
"options": [
{"label": "1521 (Default)", "description": "Standard Oracle listener port"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_ORACLE_PORT>"}
: {"label": "1522", "description": "Alternative Oracle port"}
],
"multiSelect": false
},
{
"question": "What is the Oracle service name or SID?",
"header": "Service",
"options": [
{"label": "ORCL", "description": "Default Oracle service name"},
{"label": "FREEPDB1", "description": "Oracle Free/XE pluggable database"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_ORACLE_SERVICE>"}
: {"label": "XE", "description": "Oracle Express Edition"}
],
"multiSelect": false
},
{
"question": "What is the Oracle database username?",
"header": "Username",
"options": [
{"label": "HR", "description": "Human Resources sample schema"},
{"label": "SYSTEM", "description": "Oracle system administrator"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_ORACLE_USER>"}
: {"label": "ADMIN", "description": "Common admin username"}
],
"multiSelect": false
}
]
}
Note: The pseudo-code CONFIG_EXISTS ? ... : ... means you must construct the actual JSON dynamically based on whether the config file existed. Replace <CURRENT_*> placeholders with actual values read from the file.
Save all responses. For "Keep current" responses, use the existing values from the config file. For "Other" responses, use the custom text the user typed.
Use the AskUserQuestion tool, again adapting based on CONFIG_EXISTS:
{
"questions": [
{
"question": "What is the database password? (Select 'Other' to type your password)",
"header": "Password",
"options": [
CONFIG_EXISTS ? {"label": "Keep current", "description": "Use the password already in config"}
: {"label": "No password", "description": "Connect without a password (empty)"},
CONFIG_EXISTS ? {"label": "No password", "description": "Connect without a password (empty)"}
: {"label": "Type below", "description": "Select 'Other' to enter your password"}
],
"multiSelect": false
},
{
"question": "Which Oracle schema to analyze? (Leave empty for connected user's default schema)",
"header": "Schema",
"options": [
{"label": "Use default", "description": "Use connected user's own schema (leave ORACLE_SCHEMA empty)"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_ORACLE_SCHEMA or '(empty)'>"}
: {"label": "HR", "description": "Human Resources sample schema"}
],
"multiSelect": false
},
{
"question": "Include PL/SQL source code in the analysis report?",
"header": "PL/SQL",
"options": [
{"label": "No (Recommended)", "description": "Skip PL/SQL source code - faster, smaller report"},
{"label": "Yes", "description": "Include full PL/SQL source code in the report"}
],
"multiSelect": false
},
{
"question": "Where should output files be saved? (Must be an absolute path)",
"header": "Output Dir",
"options": [
{"label": "Default (.claude/output)", "description": "Use the project's .claude/output directory"},
CONFIG_EXISTS ? {"label": "Keep current", "description": "Keep: <CURRENT_OUTPUT_DIR>"}
: {"label": "Custom path", "description": "Select 'Other' to type a custom absolute path"}
],
"multiSelect": false
}
]
}
Save all responses.
Process the collected answers into configuration values using these rules:
| Parameter | Response Mapping |
|---|---|
| ORACLE_HOST | "localhost" -> localhost, "127.0.0.1" -> 127.0.0.1, "Keep current" -> keep existing, "Other" -> user's typed value |
| ORACLE_PORT | "1521 (Default)" -> 1521, "1522" -> 1522, "Keep current" -> keep existing, "Other" -> user's typed value |
| ORACLE_SERVICE | "ORCL" -> ORCL, "FREEPDB1" -> FREEPDB1, "XE" -> XE, "Keep current" -> keep existing, "Other" -> user's typed value |
| ORACLE_USER | "HR" -> HR, "SYSTEM" -> SYSTEM, "ADMIN" -> ADMIN, "Keep current" -> keep existing, "Other" -> user's typed value |
| ORACLE_PASSWORD | "Keep current" -> keep existing, "No password" -> empty string, "Type below" -> user must use "Other", "Other" -> user's typed value |
| ORACLE_SCHEMA | "Use default" -> empty string, "HR" -> HR, "Keep current" -> keep existing, "Other" -> user's typed value |
| ORACLE_INCLUDE_PLSQL_SOURCE | "No (Recommended)" -> false, "Yes" -> true |
| OUTPUT_DIR | "Default (.claude/output)" -> absolute path to project's .claude/output directory, "Keep current" -> keep existing, "Custom path" -> user must use "Other", "Other" -> user's typed value |
Also set: ACTIVE_DATABASE=oracle
If CONFIG_EXISTS = false (first run):
Use the Write tool to create .claude/configuration/databases.env with the complete template populated with collected values:
# =============================================================================
# CONSOLIDATED DATABASE CONFIGURATION
# =============================================================================
# Single configuration file for all database migration skills
# =============================================================================
# ACTIVE DATABASE SELECTION
ACTIVE_DATABASE=oracle
# SHARED OUTPUT CONFIGURATION (ABSOLUTE PATH REQUIRED)
OUTPUT_DIR=<collected_output_dir>
# ScalarDB target version
SCALARDB_TARGET_VERSION=3.17
# =============================================================================
# POSTGRESQL CONFIGURATION (defaults - not yet configured)
# =============================================================================
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DATABASE=your_database
POSTGRES_USER=your_username
POSTGRES_PASSWORD=your_password
POSTGRES_SCHEMA=public
POSTGRES_REPORT_FILENAME=postgresql_schema_report.md
POSTGRES_SCALARDB_NAMESPACE=
POSTGRES_INCLUDE_PLPGSQL_SOURCE=true
POSTGRES_PSQL_PATH=
POSTGRES_CONNECTION_TIMEOUT=30
POSTGRES_QUERY_TIMEOUT=300
# =============================================================================
# MYSQL CONFIGURATION (defaults - not yet configured)
# =============================================================================
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=your_database
MYSQL_USER=your_username
MYSQL_PASSWORD=your_password
MYSQL_REPORT_FILENAME=mysql_schema_report.md
MYSQL_SCALARDB_NAMESPACE=
MYSQL_INCLUDE_SOURCE=false
MYSQL_CHARSET=utf8mb4
MYSQL_CONNECTION_TIMEOUT=30
# =============================================================================
# ORACLE CONFIGURATION
# =============================================================================
ORACLE_HOST=<collected_host>
ORACLE_PORT=<collected_port>
ORACLE_SERVICE=<collected_service>
ORACLE_USER=<collected_user>
ORACLE_PASSWORD=<collected_password>
ORACLE_SCHEMA=<collected_schema>
ORACLE_REPORT_FILENAME=oracle_schema_report.md
ORACLE_SCALARDB_NAMESPACE=<lowercase of collected_user or collected_schema>
ORACLE_INCLUDE_PLSQL_SOURCE=<collected_plsql_source>
ORACLE_SQLPLUS_PATH=
ORACLE_HOME=
ORACLE_TNS_ADMIN=
# =============================================================================
# END OF CONFIGURATION
# =============================================================================
If CONFIG_EXISTS = true (updating existing):
Use the Edit tool to update .claude/configuration/databases.env with the collected values:
ACTIVE_DATABASE=oracleOUTPUT_DIR if changedORACLE_* parameters with the mapped values from Step 4After writing/updating, display a confirmation summary to the user:
Configuration <Created / Updated>:
Host: <value>
Port: <value>
Service: <value>
User: <value>
Password: ******** (hidden)
Schema: <value or "default (connected user)">
PL/SQL: <true/false>
Output: <path>
Use Bash to create the output directory if it doesn't exist:
mkdir -p <OUTPUT_DIR>
Spawn a Bash subagent using the Task tool to test the database connection directly using SQL*Plus before running the heavy extraction process.
${PLUGIN_ROOT}/skills/common/subagents/oracle/0-test-connection.md<ORACLE_HOST> → the collected ORACLE_HOST value<ORACLE_PORT> → the collected ORACLE_PORT value<ORACLE_SERVICE> → the collected ORACLE_SERVICE value<ORACLE_USER> → the collected ORACLE_USER value<ORACLE_PASSWORD> → the collected ORACLE_PASSWORD value<ORACLE_SQLPLUS_PATH> → the collected ORACLE_SQLPLUS_PATH value (empty string if not set)<OUTPUT_DIR> → the collected OUTPUT_DIR valuesubagent_type: "Bash", description: "Test Oracle DB connection", and the substituted promptCheck the subagent result:
DURATION_SECONDS from the subagent's response → store as S0_DURATIONtotal_tokens from the <usage> block in the Task result (if present) → store as S0_TOKENSORA-12541 → Oracle listener not running or wrong host/portORA-12514 → Wrong service name or SIDORA-01017 → Wrong username or passwordSQL*Plus not found → SQL*Plus is not installed or ORACLE_SQLPLUS_PATH is not set in .claude/configuration/databases.envSpawn a Bash subagent using the Task tool to run the Python extractor script.
${PLUGIN_ROOT}/skills/common/subagents/oracle/1-extract-schema.md<INCLUDE_SOURCE_FLAG> based on ORACLE_INCLUDE_PLSQL_SOURCE from Step 4)subagent_type: "Bash", description: "Extract Oracle schema", and the substituted promptCheck the subagent result:
DURATION_SECONDS from the subagent's response → store as S1_DURATIONtotal_tokens from the <usage> block in the Task result (if present) → store as S1_TOKENSSpawn a general-purpose subagent using the Task tool to generate the schema report from the extracted JSON.
${PLUGIN_ROOT}/skills/common/subagents/oracle/2-generate-report.md<OUTPUT_DIR> with the actual absolute output directory path from Step 4)subagent_type: "general-purpose", description: "Generate Oracle schema report", and the substituted promptCheck the subagent result:
DURATION_SECONDS from the subagent's response → store as S2_DURATIONtotal_tokens from the <usage> block in the Task result (if present) → store as S2_TOKENSraw_schema_data.json is still available for manual inspection. STOP HERE — do NOT proceed to Step 10.Subagents 3, 4, and 5 all depend only on the outputs of Subagent 2 (oracle_schema_report.md + raw_schema_data.json). They have no dependencies on each other, so spawn all three in a single message to run in parallel.
Record S345_START = current time.
In one message, issue all three Task() calls simultaneously:
Task A — Subagent 3: Migration Analysis
${PLUGIN_ROOT}/skills/common/subagents/oracle/3-migration-analysis.md<OUTPUT_DIR> with the actual absolute output directory path from Step 4Task(subagent_type: "general-purpose", description: "Generate Oracle migration docs", prompt: <substituted>)Task B — Subagent 4: AQ Migration
${PLUGIN_ROOT}/skills/common/subagents/oracle/4-aq-migration.md<OUTPUT_DIR> with the actual absolute output directory path from Step 4Task(subagent_type: "general-purpose", description: "Generate AQ setup SQL & consumer Java", prompt: <substituted>)Task C — Subagent 5: Stored Procedure & Trigger Migration
${PLUGIN_ROOT}/skills/common/subagents/oracle/5-sp-trigger-migration.md<OUTPUT_DIR> with the actual absolute output directory path from Step 4Task(subagent_type: "general-purpose", description: "Generate SP & trigger migration code", prompt: <substituted>)Wait for all three Tasks to complete, then:
DURATION_SECONDS → store as S3_DURATION; extract total_tokens from <usage> block → store as S3_TOKENSDURATION_SECONDS → store as S4_DURATION; extract total_tokens from <usage> block → store as S4_TOKENSDURATION_SECONDS → store as S5_DURATION; extract total_tokens from <usage> block → store as S5_TOKENSS345_WALL = max(S3_DURATION, S4_DURATION, S5_DURATION)Check results independently (failures are isolated — one does not block the others):
Compute totals before rendering:
TOTAL_DURATION = S0_DURATION + S1_DURATION + S2_DURATION + S345_WALL
(Phases 3, 4 & 5 ran in parallel, so only the longest one adds to wall-clock time)TOTAL_TOKENS = S0_TOKENS + S1_TOKENS + S2_TOKENS + S3_TOKENS + S4_TOKENS + S5_TOKENS
(If any token value is unavailable, mark it as "N/A" and omit it from the total)Display the combined results from all six subagents to the user:
Oracle to ScalarDB Migration - Complete
Phase 0: Connection Test
- Connection method: SQL*Plus (direct database connection)
- <Subagent 0 SUMMARY line (database product and version)>
Phase 1: Schema Extraction
- Connected to Oracle at <host>:<port>/<service>
- <Subagent 1 SUMMARY line>
Phase 2: Schema Report
- Generated: oracle_schema_report.md
- <Subagent 2 SUMMARY lines>
Phase 3+4+5: Parallel Migration (ran simultaneously after Phase 2)
Wall-clock time: <S345_WALL>s (SA3: <S3_DURATION>s | SA4: <S4_DURATION>s | SA5: <S5_DURATION>s)
[Phase 3] Migration Analysis
- Generated: scalardb_migration_analysis.md
- Generated: scalardb_migration_steps.md
- Migration Complexity: <Subagent 3 COMPLEXITY_SCORE>
- <Subagent 3 SUMMARY lines>
[Phase 4] AQ Migration
- Generated: aq_setup.sql (Oracle AQ setup — payload types, queues, triggers, enqueue SPs)
- Generated: scalardb_aq_migration_report.md
- Java consumer files: <OUTPUT_DIR>/generated-java/
- Queues created: <Subagent 4 QUEUES_CREATED>
- Files generated: <Subagent 4 FILES_GENERATED>
- <Subagent 4 SUMMARY lines>
[Phase 5] Stored Procedure & Trigger Migration (Direct)
- Generated: scalardb_sp_migration_report.md
- Java files: <OUTPUT_DIR>/generated-java/
- Files generated: <Subagent 5 FILES_GENERATED>
- <Subagent 5 SUMMARY lines>
Output Directory: <OUTPUT_DIR>
Next Steps:
1. Review scalardb_migration_analysis.md for compatibility details
2. Follow scalardb_migration_steps.md for implementation guide
3. Import database into ScalarDB (required before AQ consumer can work)
4. Run aq_setup.sql against Oracle to create queues and AQ triggers
5. Review scalardb_aq_migration_report.md for AQ integration guide
6. Review generated-java/ for consumer and direct migration code
7. Review scalardb_sp_migration_report.md for SP & trigger migration details
Then display the metrics table:
Execution Summary
─────────────────────────────────────────────────────────────────────
Phase │ Subagent Type │ Tokens │ Time
─────────────────────────────────────────────────────────────────────
Phase 0: Connection Test │ Bash │ S0_TOK │ S0s
Phase 1: Schema Extraction │ Bash │ S1_TOK │ S1s
Phase 2: Schema Report │ General-purpose │ S2_TOK │ S2s
Phase 3: Migration Analysis ┐ │ General-purpose │ S3_TOK │ S3s
Phase 4: AQ Migration │ │ General-purpose │ S4_TOK │ S4s
Phase 5: SP/Trigger Migration ┘ │ General-purpose │ S5_TOK │ S5s
(parallel wall-clock) │ S345s
─────────────────────────────────────────────────────────────────────
TOTAL │ 6 subagents │ TOT_TOK │ TOTs
─────────────────────────────────────────────────────────────────────
(If any token value is unavailable, mark it as "N/A" and omit it from the total)
raw_schema_data.json is available on disk, STOP (do not spawn Subagent 3, 4, or 5 — Subagents 4 and 5 need the schema report for table/column context)Partial outputs are always preserved — if extraction succeeds but later steps fail, earlier output files remain on disk for manual inspection.
This command uses 6 subagents — 3 sequential then 3 parallel — to isolate heavy processing from the main conversation:
SA0 (Bash) → SA1 (Bash) → SA2 (general-purpose) → ┌─ SA3 (general-purpose) ─┐
├─ SA4 (general-purpose) ─┤ → Summary
└─ SA5 (general-purpose) ─┘
| Subagent | Type | Phase | Purpose | Returns |
|---|---|---|---|---|
| 0 | Bash | Sequential | Test DB connection via SQL*Plus | SUCCESS/FAILURE + DB version |
| 1 | Bash | Sequential | Run oracle_db_extractor.py | SUCCESS/FAILURE + file path |
| 2 | general-purpose | Sequential | Generate oracle_schema_report.md from JSON + template | Executive summary |
| 3 | general-purpose | Parallel | Generate migration analysis + steps from report + reference docs | Complexity score + findings |
| 4 | general-purpose | Parallel | Generate AQ setup SQL + Java consumer code from triggers/SPs | Queues + files generated |
| 5 | general-purpose | Parallel | Generate Java code from PL/SQL + SP & trigger migration report | Files generated + complexity |
SA3, SA4, and SA5 are spawned simultaneously in a single message after SA2 completes. Expected speedup vs. sequential: ~33–55% reduction in wall-clock time for phases 3–5.
The SKILL.md files are read directly by subagents as instruction documents (the Skill tool is not invoked).
${PLUGIN_ROOT}/skills/common/subagents/oracle/ (6 prompt templates: 0-test-connection.md through 5-sp-trigger-migration.md)${PLUGIN_ROOT}/skills/migrate-oracle/analyze-oracle-schema/SKILL.md${PLUGIN_ROOT}/skills/migrate-oracle/analyze-oracle-schema/analyze-oracle-dbms_report.md${PLUGIN_ROOT}/skills/migrate-oracle/analyze-oracle-schema/scripts/oracle_db_extractor.py${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-to-scalardb/SKILL.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-to-scalardb/templates/${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-to-scalardb/reference/scalardb_reference.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-aq-to-scalardb/SKILL.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-aq-to-scalardb/reference/aq-migration-strategy-guide.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-aq-to-scalardb/templates/scalardb_aq_migration_report.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-aq-to-scalardb/reference/AQ-official-docs/${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-sp-trigger-to-scalardb/SKILL.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-sp-trigger-to-scalardb/reference/migration-strategy-guide-sp-triggers-to-scalardb.md${PLUGIN_ROOT}/skills/migrate-oracle/migrate-oracle-sp-trigger-to-scalardb/templates/scalardb_sp_migration_report.md.claude/configuration/databases.envnpx claudepluginhub wfukatsu/nexus-architect --plugin scalardbOrchestrates MySQL to ScalarDB migration: schema extraction, migration analysis, and stored procedure/trigger to Java conversion. Interactive chat collects DB connection params, updates config, then runs analysis and migration skills.
Plans zero-downtime data and system migrations with rollback procedures, validation checks, and execution timeline. Useful for database restructures, provider switches, and infrastructure moves.
Creates zero-downtime SQL migration scripts with rollback procedures, validation checks, and performance optimization for PostgreSQL, MySQL, and SQL Server.