@ductape/mcp 0.1.61 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -725,6 +725,10 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
725
725
  ━━━ MODULE: features ━━━
726
726
  Feature definitions are code-first. Use features.define in application source; do not call
727
727
  administrative create/update/delete methods through ductape_execute.
728
+ A Feature is a named, reusable product capability with a stable input/output contract that
729
+ benefits from managed execution, composition, observability, retries, versioning, policy
730
+ enforcement, or explicit execution steps. It may execute synchronously and entirely locally.
731
+ Signals, Events, schedules, waits, checkpoints, compensation, and rollback are optional patterns.
728
732
  features.fetch [product_tag, feature_tag]
729
733
  features.fetchAll [product_tag]
730
734
 
@@ -1129,16 +1133,25 @@ const ADMIN_SUBCOMMANDS = [
1129
1133
  'profiles',
1130
1134
  'workspaces',
1131
1135
  'link', 'unlink', 'init',
1132
- 'products', 'apps',
1136
+ 'products', 'apps', 'marketplace',
1133
1137
  'resources',
1134
1138
  'notifications',
1135
1139
  'events',
1136
1140
  'cloud',
1137
1141
  'secrets',
1142
+ 'secrets-import-env',
1138
1143
  'generate',
1139
1144
  'apply',
1140
1145
  'db',
1141
1146
  'graph',
1147
+ 'migrate-codebase',
1148
+ 'migration-review',
1149
+ 'migration-slice',
1150
+ 'migration-portfolio',
1151
+ 'migration-database',
1152
+ 'migration-environments',
1153
+ 'migration-products',
1154
+ 'migration-secrets',
1142
1155
  ];
1143
1156
  function checkCli() {
1144
1157
  try {
@@ -1265,13 +1278,441 @@ function cliEnvironment() {
1265
1278
  delete environment.DUCTAPE_ACCESS_KEY;
1266
1279
  return environment;
1267
1280
  }
1281
+ function shellArgument(value) {
1282
+ return `'${value.replace(/'/g, `'\\''`)}'`;
1283
+ }
1268
1284
  const docsInputSchema = z.object({
1269
1285
  topic: z.string().describe('Feature topic to look up. Supported: ' +
1270
1286
  'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
1271
1287
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
1272
- 'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue'),
1288
+ 'notifications, resilience, features, events, logs, migration, frontend, frontend-analytics, client, react, vue'),
1289
+ });
1290
+ const migrationInputSchema = z.object({
1291
+ source: z.string().describe('Absolute path to the existing codebase.'),
1292
+ e2e_baseline: z.string().describe('Absolute path to a passing migration-e2e baseline manifest created before migration inspection.'),
1293
+ mode: z.enum(['in-place', 'new-codebase']).default('new-codebase').describe('Selects where advisory guidance is written. It never generates or rewrites application code.'),
1294
+ destination: z.string().optional().describe('Required destination path for new-codebase mode.'),
1295
+ product: z.string().optional().describe('Ductape product tag; defaults to a slug of the source directory name.'),
1296
+ name: z.string().optional().describe('Product display name.'),
1297
+ database: z.string().optional().describe('Target database tag recorded for the AI review; no schema is generated.'),
1298
+ max_file_bytes: z.number().int().positive().optional().default(2_000_000),
1299
+ include: z.array(z.string()).optional().default([]).describe('Repository-relative glob patterns to include.'),
1300
+ exclude: z.array(z.string()).optional().default([]).describe('Repository-relative glob patterns to exclude with audit evidence.'),
1301
+ ensure_product: z.boolean().optional().default(false).describe('Create the product through the standalone authenticated CLI when it does not exist.'),
1302
+ write: z.boolean().optional().default(false).describe('Write redacted advisory artifacts only. This never writes application code or executable Ductape assets.'),
1273
1303
  });
1274
1304
  const DOCS = {
1305
+ migration: `
1306
+ DUCTAPE CODEBASE MIGRATION GUIDE
1307
+
1308
+ NON-NEGOTIABLE AUTOMATION BOUNDARY
1309
+ The scanner is an evidence collector and standards engine, not a code generator or codemod.
1310
+ Scanner findings are evidence, not implementation instructions.
1311
+ It MUST NOT create, rewrite, patch, or mechanically replace application source.
1312
+ It MUST NOT emit executable migrations or authoritative Ductape assets.
1313
+ The scanner does not generate or propose a schema. Schema decisions belong to the contextual AI review.
1314
+ migration-evidence.json is checksummed source evidence, never an executable migration.
1315
+ The AI must inspect relevant source files and installed SDK APIs, explain its design, and then write
1316
+ code through normal editing tools. Builds, tests, rescans, inventory checks, and smoke tests verify it.
1317
+
1318
+ SUPPORTED SERVER LANGUAGES
1319
+ TypeScript/Node.js (including NestJS), Go, Java, and .NET.
1320
+ Inspect installed package exports before generating code; language APIs pursue parity but signatures differ.
1321
+
1322
+ START
1323
+ 1. Inspect the original project and create or complete project-level E2E tests before changing application code.
1324
+ Run them against the original codebase. The AI executes the project test command with normal coding tools;
1325
+ Ductape CLI only records evidence and never executes an arbitrary command.
1326
+ Create a value-free definition containing command, suite_files, and passing baseline status/evidence/environment:
1327
+ ductape_cli("migration-e2e init --source <source> --definition <baseline-definition.json> --output <e2e-baseline.json> --json")
1328
+ The manifest SHA-256 binds every original test/fixture. Preserve it unchanged as the acceptance oracle.
1329
+ 2. Call ductape_migration_plan in read-only mode with e2e_baseline set to that passing manifest.
1330
+ 3. Present the review queue, inventory, secret NAMES, migration evidence, and low-confidence
1331
+ deterministic hints. Never present a hint as a component decision.
1332
+ 4. Use the default new-codebase mode unless the user explicitly selects in-place:
1333
+ in-place — progressively migrate the existing repository.
1334
+ new-codebase — place guidance in a separate destination while preserving the source untouched.
1335
+ It does not generate a new application; the AI creates it deliberately.
1336
+ 5. Call again with write=true only after confirming the destination. This writes guidance artifacts only.
1337
+ 6. Call with ensure_product=true when product inventory confirms the product is absent.
1338
+
1339
+ FINAL E2E ACCEPTANCE GATE
1340
+ End the migration by running the exact original E2E command against the migrated codebase while retaining
1341
+ the original checksum-bound suite. Do not silently edit, delete, skip, quarantine, or weaken baseline tests.
1342
+ Record the passing result in a value-free evidence JSON containing the command, status, evidence,
1343
+ environment, and absolute suite_root of the migrated codebase, then:
1344
+ ductape_cli("migration-e2e final --manifest <e2e-baseline.json> --evidence <final-evidence.json> --json")
1345
+ ductape_cli("migration-e2e validate --manifest <e2e-baseline.json> --strict --json")
1346
+ The final command must exactly equal the baseline command. Every suite file under suite_root must match
1347
+ its original checksum, proving the migrated codebase is tested with the same original tests and fixtures.
1348
+ New migration-specific tests supplement the baseline; they never replace it. A failing original E2E case blocks
1349
+ readiness unless the user explicitly authorizes a product behavior change and the exception is separately audited.
1350
+
1351
+ SECURITY
1352
+ Never read secret values into MCP arguments or output. Discovery reports names and locations only.
1353
+ The MCP server accepts publishable keys only and never accepts an access key.
1354
+ Secret values must be imported by the standalone CLI reading local files directly. Assets reference
1355
+ $Secret{tag}; manifests never embed credentials. Keep snd/stg/prd values separate.
1356
+ Use ductape_cli("secrets-import-env --env-file <local-file> --source-key <ENV_KEY> --key <secret-tag> --env <slug> --json").
1357
+ The command reads the value locally and redacts it from output; never place the value in an MCP argument.
1358
+ secret_references are names-only navigation evidence from Docker Compose, Kubernetes secretKeyRef,
1359
+ GitHub/GitLab/Jenkins, Spring, .NET configuration, Terraform, and AWS/GCP/Azure secret managers.
1360
+ Their value is always [NOT_READ]. Inspect context before deciding whether a reference is sensitive,
1361
+ environment-specific, shared, or suitable for a Ductape secret; never resolve it through MCP.
1362
+ Classify and reconcile every discovered reference through a value-free artifact:
1363
+ ductape_cli("migration-secrets init --analysis <analysis.json> --definition <secret-map-definition.json> --output <secret-map.json> --json")
1364
+ ductape_cli("migration-secrets validate --file <secret-map.json> --strict --json")
1365
+ Each classification requires environment, service, provider, sensitivity, rotation owner,
1366
+ Ductape secret tag, authenticated inventory action/evidence, and rotation validation/rollback.
1367
+ The validator rejects value, password, credential, private-key, and access-token fields.
1368
+ potential_secret_exposures are low-confidence security-review findings only. They contain source,
1369
+ line, category, and a truncated SHA-256 fingerprint; matched material is always [NOT_RETURNED].
1370
+ Never ask the scanner, CLI, user, or MCP to reveal a finding. Ask the user/security owner to rotate
1371
+ and remediate confirmed exposure through trusted local processes.
1372
+
1373
+ ENVIRONMENTS
1374
+ Detect environments from .env variants, deployment files, CI, Docker, Kubernetes, Terraform,
1375
+ framework configuration, and existing database/provider configuration. Normalize common aliases
1376
+ (production→prd, sandbox→snd, staging→stg) but present uncertain mappings for confirmation.
1377
+ Before creating any asset, list product environments and require complete per-environment coverage.
1378
+ Missing environments can be created idempotently through the authenticated standalone CLI:
1379
+ ductape_cli("products environments create <product-tag> -f <environment.json> --json")
1380
+ The JSON requires env_name, description, and a three-character slug. The CLI fetches first, creates only
1381
+ when absent, then fetches again to verify persistence. Update and verify with:
1382
+ ductape_cli("products environments update <product-tag> <slug> -f <patch.json> --json")
1383
+ Export authenticated inventory with ductape_cli("products environments list <product-tag> --json"),
1384
+ save it as evidence, then reconcile locally:
1385
+ ductape_cli("migration-environments --analysis <analysis.json> --inventory <inventory.json> --strict --json")
1386
+ Report matched, missing, extra, and ambiguous normalized aliases. Never guess an ambiguous mapping.
1387
+ Environment mutation is administrative CLI work and must never be routed through ductape_execute.
1388
+
1389
+ PRODUCT AND ASSET BOOTSTRAP
1390
+ Product creation is idempotent: fetch by tag, create only when absent, then link the destination.
1391
+ Use ductape_cli for products, apps, resources, cloud connections, secrets, apply, and migrations.
1392
+ Use ductape_execute only for runtime calls with a publishable key.
1393
+ For monorepos, define explicit service ownership, product boundaries, asset environment coverage,
1394
+ and environment promotion evidence:
1395
+ ductape_cli("migration-products init --analysis <analysis.json> --definition <product-map-definition.json> --output <product-map.json> --json")
1396
+ ductape_cli("migration-products validate --file <product-map.json> --strict --json")
1397
+ Every discovered workspace-unit manifest must have exactly one service owner. Each service records
1398
+ its product and target environments. Every required asset records authenticated inventory evidence
1399
+ and configured environments. Every mapped product requires promotion entry conditions, validation,
1400
+ and rollback; never assume repository, service, and product boundaries are identical.
1401
+
1402
+ DATABASE SCHEMAS AND MIGRATIONS
1403
+ For every database migration, create a definition containing baseline, data, and cutover sections:
1404
+ ductape_cli("migration-database init --definition <database-definition.json> --output <guidance-dir> --json")
1405
+ ductape_cli("migration-database validate --directory <guidance-dir> --strict --json")
1406
+ Baseline evidence covers code/live/applied schemas, drift, views/triggers/procedures/indexes/constraints,
1407
+ permissions/RLS/encryption, tenancy/sharding/partitioning, provider compatibility, IDs/timezones/collation,
1408
+ and query-performance baselines. Data planning covers transformations, batching, checkpoints, resumability,
1409
+ idempotency, PII/retention, seed data, validation and reconciliation. Cutover uses expand/backfill/
1410
+ dual-compatibility/contract phases with deployment ordering, locks, backup, tested restore, rollback,
1411
+ irreversible-change disclosure, monitoring, reconciliation, and explicit approval.
1412
+ All three artifacts require the same migration_id and database_tag. Baseline schema_snapshots cover
1413
+ code, migration, applied, live, and proposed structures with source-file SHA-256, structure hash,
1414
+ timestamp, and evidence; stale source evidence blocks readiness. structural_comparison must be matched
1415
+ or contain explicit approved differences. Data transformations require versioned source/target field
1416
+ mappings, positive batch/concurrency/memory/timeout limits, and an atomic persistent checkpoint with
1417
+ replay-test evidence. Cutover phases require unique positive order and valid prerequisite IDs.
1418
+ Inventory Prisma, TypeORM, Sequelize, Mongoose, SQL, Flyway, Liquibase, Hibernate/JPA,
1419
+ Entity Framework, golang-migrate, Goose, and other migration/schema sources.
1420
+ The planner only identifies possible schema and migration source files. It does not parse them into
1421
+ a proposed Ductape schema. The AI must inspect models, relations, indexes, constraints, migrations,
1422
+ repository behavior, tests, live/provider semantics, and applied history before proposing or writing
1423
+ ductape/database/schema.json.
1424
+ Existing migrations are recorded in migration-imports.json with order and SHA-256 checksums. Review
1425
+ their intent, then generate portable reversible files under ductape/database/migrations/<db-tag>/.
1426
+ Raw source SQL is never silently executed or wrapped because Ductape migrations deliberately use
1427
+ provider-portable operations and require honest rollback behavior.
1428
+ Preserve applied order, identifiers, indexes, constraints, defaults, nullability, and rollback semantics.
1429
+ Never mark converted migrations applied merely because source files exist. Compare live schema in snd,
1430
+ run db schema generate, inspect the diff, then db migrate --dry-run before applying.
1431
+ Composite/partial/provider-specific indexes remain explicit Ductape migration operations.
1432
+
1433
+ THIRD-PARTY APIS
1434
+ Group repeated HTTP calls by stable base host into one reusable Ductape App. Model stable operations as
1435
+ Actions with auth, headers, input mapping, output mapping, retry/timeout policy, and environment-specific
1436
+ base URLs. Prefer OpenAPI/Postman import when available. Do not create one App per call site and do not
1437
+ route internal application services through fake HTTP Apps; use Events for internal boundaries.
1438
+
1439
+ COMPONENT DECISIONS
1440
+ Databases/transactions → Ductape Database; brokers/queues → Events; object stores → Storage;
1441
+ SMTP/SMS/push/callbacks → Notifications; Redis/cache → Cache; Neo4j/Neptune/Arango/Memgraph → Graph;
1442
+ Pinecone/Qdrant/Weaviate/OpenSearch → Vector; JWT/session middleware → Sessions.
1443
+ Named reusable product capabilities with a stable managed-execution boundary → code-first Features,
1444
+ including synchronous multi-step capabilities and durable/scheduled/signal-driven orchestration.
1445
+ Retries, health checks, fallbacks, quotas, circuit breakers → Resilience.
1446
+ Keep low-level deterministic rules as ordinary domain functions when they do not form a useful
1447
+ independent capability boundary. Wrap or compose them into Features when the combined operation
1448
+ represents a reusable product capability.
1449
+
1450
+ LANGUAGE RUNTIME SHAPES
1451
+ TypeScript: @ductape/sdk; NestJS uses @ductape/nestjs, @Events.Consumer, and request-scoped context.
1452
+ Go: explicit services, context.Context, cancellation, typed errors, and owned worker shutdown.
1453
+ Java: DI/Spring integration where present, executor ownership, CompletableFuture boundaries.
1454
+ .NET: DI, hosted services, async/await, CancellationToken, configuration binding.
1455
+
1456
+ SESSIONS AND DURABLE ACTORS
1457
+ Immediate user work passes the original full session token. Delayed work must not persist raw JWTs
1458
+ indefinitely; use system context or an approved delegated actor plus immutable non-secret metadata.
1459
+
1460
+ ROLLOUT
1461
+ The AI migrates one vertical slice end-to-end, test snd, introduce a feature flag/dual path where safe,
1462
+ verify idempotency, concurrency, retries, duplicate delivery, logs, and rollback, then progressively cut over.
1463
+
1464
+ AI EDITING STANDARD
1465
+ Before every edit, inspect the relevant source, dependencies, installed SDK types, configuration, tests,
1466
+ and neighboring architecture. Preserve domain behavior and public contracts unless explicitly authorized.
1467
+ Do not change or invent public or internal interfaces, method signatures, types, DTOs, event schemas,
1468
+ serialized formats, error contracts, or lifecycle contracts unless the user explicitly authorizes that
1469
+ exact change. An SDK mismatch is a finding to report and resolve, not permission to reshape application code.
1470
+ Do not assume functionality from filenames, symbols, patterns, comments, documentation, or scanner hints.
1471
+ Trace the implementation, callers, callees, tests, configuration, persisted data, and runtime effects.
1472
+ If behavior remains unclear, run or add characterization tests and record the uncertainty. Never fabricate
1473
+ behavior, compatibility, defaults, rollback guarantees, idempotency, or provider support.
1474
+ Maintain full functional parity:
1475
+ - accepted inputs, returned outputs, validation, domain results, state changes, external side effects,
1476
+ serialized data, errors, events, and user-visible behavior.
1477
+ Maintain full operational parity:
1478
+ - ordering, timing-sensitive guarantees, concurrency, transactions, retries, duplicate delivery,
1479
+ idempotency, authorization, privacy, observability, performance-sensitive behavior, startup,
1480
+ shutdown, cancellation, recovery, and degraded/failure behavior.
1481
+ Compilation and happy-path tests alone do not demonstrate parity. Use existing tests, characterization
1482
+ tests, contract tests, integration tests, failure injection, and snd smoke tests appropriate to the slice.
1483
+ If parity cannot be demonstrated, stop short of cutover and report the exact unverified behavior.
1484
+ Use Events for internal async boundaries and Apps/Actions for external APIs. Keep low-level deterministic
1485
+ rules in code, while allowing a coherent synchronous capability composed from those rules to be a Feature.
1486
+ Immediate work propagates the full session; durable work uses approved actor metadata or system context.
1487
+ Consumers are idempotent, retry ownership is singular and bounded, and external effects are not duplicated.
1488
+ After each slice: format, build, test, rescan, reconcile assets through ductape_cli, smoke-test in snd,
1489
+ and report unresolved findings. A clean scanner result alone never proves a correct migration.
1490
+
1491
+ CONTEXTUAL FILE REVIEW PROTOCOL
1492
+ Use review_queue as a coverage aid. Review relevant files individually, starting with repository
1493
+ instructions, manifests, entrypoints, configuration, dependency injection, tests, and deployment files.
1494
+ For each file record: purpose; imports/dependencies; callers/callees; configuration and secret-name
1495
+ references; interfaces/types/signatures/DTOs/event schemas/serialized contracts; database behavior;
1496
+ events/background work; external APIs; sessions/authorization;
1497
+ cache/storage/notifications/graph/vector use; failure policy; tests/invariants; and follow-up files.
1498
+ Follow wrappers and references until the actual external effect and domain intent are understood.
1499
+ Classify each ledger finding:
1500
+ observed — directly supported by source/configuration
1501
+ inferred — likely, but requires more context
1502
+ proposed — possible Ductape design, not yet approved
1503
+ confirmed — verified through source, installed SDK types, tests, inventory, or user confirmation
1504
+ Do not claim coverage until every relevant queue item is reviewed or excluded with a written reason.
1505
+ Do not read .env secret values into MCP context: record names only and use standalone CLI import.
1506
+
1507
+ AUDITABLE REVIEW LEDGER
1508
+ After write=true creates migration-guidance/analysis.json, initialize the ledger:
1509
+ ductape_cli("migration-review init --analysis <path>/analysis.json --json")
1510
+ Record contextual evidence through a validated JSON input file:
1511
+ ductape_cli("migration-review record --ledger <ledger> --file <relative-file> --data <evidence.json> --json")
1512
+ The evidence file may contain purpose, dependencies, follow_up_files, interfaces, findings, and
1513
+ references. Reference kinds are import | caller | callee | implements | event | test | config | schema.
1514
+ Every finding requires location: { start_line, end_line } with positive, ordered source lines.
1515
+ Every finding also requires symbol: { kind, name, qualified_name? } so evidence identifies the
1516
+ affected module/class/interface/function/method/field/route/event/schema rather than only a filename.
1517
+ Internal references must point to reviewed/excluded ledger files before readiness.
1518
+ Add a newly discovered repository file without dropping review coverage:
1519
+ ductape_cli("migration-review follow-up --ledger <ledger> --file <source> --follow-up <target> --json")
1520
+ Record parity with structured validation:
1521
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern interface --status verified --evidence <evidence> --json")
1522
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern functional --status verified --evidence <evidence> --json")
1523
+ ductape_cli("migration-review parity --ledger <ledger> --file <file> --concern operational --status verified --evidence <evidence> --json")
1524
+ For a genuine not-applicable concern, use --status not_applicable --reason <reason>.
1525
+ For each entry the ledger records purpose, dependencies, follow-up files, references, interfaces,
1526
+ findings, exclusion metadata where applicable, and:
1527
+ interface_parity, functional_parity, operational_parity
1528
+ Each parity status is pending | verified | not_applicable.
1529
+ verified requires concrete evidence. not_applicable requires a reason.
1530
+ After completing a file, snapshot the exact reviewed content:
1531
+ ductape_cli("migration-review snapshot --ledger <path>/review-ledger.json --file <relative-file> --json")
1532
+ A later checksum change makes that review stale. Follow-up files must also exist in the ledger;
1533
+ never silently omit a referenced file. Reopen a review explicitly when needed:
1534
+ ductape_cli("migration-review reopen --ledger <ledger> --file <relative-file> --json")
1535
+ Exclude only with a classification and reason:
1536
+ ductape_cli("migration-review exclude --ledger <ledger> --file <file> --classification <type> --reason <reason> --json")
1537
+ Types: generated | vendor | build | snapshot | other. Generated exclusions additionally require
1538
+ --generator and --regeneration-test so generated contracts are not silently ignored.
1539
+ If a reviewed file disappears, validation reports checksum-matched probable_moves without changing
1540
+ history. Accept a verified move only when content is identical:
1541
+ ductape_cli("migration-review move --ledger <ledger> --from <old-file> --to <new-file> --json")
1542
+ A stale file transitively invalidates reviewed entries that reference it through internal references,
1543
+ follow-up files, or finding follow-ups. Re-review the dependency chain before readiness.
1544
+ Every structured ledger mutation uses an exclusive lock, checks the expected revision, appends an
1545
+ actor/tool/version/timestamp operation event, chains it to the previous SHA-256 hash, and binds the
1546
+ newest event to the current ledger-entry state. Never edit review-ledger.json directly after audit
1547
+ events exist: validation treats that as tampering. A concurrent conflict must be retried after re-reading
1548
+ the latest ledger; never overwrite another reviewer.
1549
+ For parallel branches, merge only against an explicit common base:
1550
+ ductape_cli("migration-review merge --base <base.json> --current <current.json> --incoming <incoming.json> --output <merged.json> --json")
1551
+ Non-overlapping file reviews merge into a new ledger; divergent edits to the same file return conflicts
1552
+ and never overwrite either input. For trusted release attestation, sign outside MCP with a protected
1553
+ Ed25519 private-key file and verify using the independently distributed public key:
1554
+ ductape_cli("migration-review sign --ledger <ledger> --private-key <private.pem> --key-id <identity> --json")
1555
+ ductape_cli("migration-review verify-signature --ledger <ledger> --signature <ledger.sig.json> --public-key <public.pem> --json")
1556
+ Never pass private-key contents through MCP or prompts.
1557
+ Check progress without claiming readiness:
1558
+ ductape_cli("migration-review validate --ledger <path>/review-ledger.json --json")
1559
+ Before proposing cutover, require strict validation:
1560
+ ductape_cli("migration-review validate --ledger <path>/review-ledger.json --strict --json")
1561
+
1562
+ Before writing SDK integration code, query the exact supported language/version catalog:
1563
+ ductape_cli("migration-capabilities --language <typescript|go|java|dotnet> --version <exact-version> --json")
1564
+ The catalog is source-evidenced but does not replace inspection of the package actually installed in the target.
1565
+ Strict readiness requires no pending or stale files, reasoned exclusions, complete follow-ups,
1566
+ covered internal references, recorded file purpose, and verified or reasoned-not-applicable
1567
+ interface/functional/operational parity.
1568
+
1569
+ GENERATED, VENDORED, AND SNAPSHOT CONTRACTS
1570
+ Scanner generated_source_hints are navigation evidence, never permission to ignore a file. Contextually
1571
+ classify every hint and any discovered generated or vendored file in a definition, then:
1572
+ ductape_cli("migration-generated init --analysis <analysis.json> --definition <generated-vendor-definition.json> --json")
1573
+ ductape_cli("migration-generated validate --file <generated-vendor-evidence.json> --strict --json")
1574
+ For generated files record contract_kind (public_api | generated_client | schema | ui_snapshot | internal),
1575
+ owner, generator name/version/command, repository-relative generator inputs, passing clean-workspace
1576
+ regeneration evidence, the regenerated output file, and compatibility_tests. The CLI records SHA-256
1577
+ input/checked-in/regenerated checksums and compares output; it never executes an arbitrary generator command.
1578
+ public_api, generated_client, schema, and ui_snapshot are contracts and require compatibility tests.
1579
+ A clean-regenerated mismatch or changed generator input blocks readiness.
1580
+ For vendored source record upstream source/version/SHA-256 checksum, owner, locally_modified, diff_evidence,
1581
+ and compatibility tests. The validator derives modification from current versus upstream checksum; it rejects
1582
+ a false classification, and locally modified vendor source requires owned diff evidence.
1583
+ Never overwrite or normalize checked-in generated/vendor output to make validation pass. Re-run the real
1584
+ generator in an isolated clean workspace using normal development tools, inspect the diff, and record evidence.
1585
+
1586
+ REPOSITORY-WIDE ASSURANCE MATRIX
1587
+ Create a version:1, artifact_kind:"ductape_migration_assurance" JSON artifact and validate it with:
1588
+ ductape_cli("migration-assurance --file <assurance.json> --strict --json")
1589
+ This is an evidence gate, not a test runner. The AI runs the referenced tests with normal development tools.
1590
+ It requires tested session flows from frontend through backend, Events, Features, and scheduled work, including
1591
+ refresh, revocation, logout, account switching, expiry, and actor-audit evidence that is not authorization.
1592
+ It requires Feature duplicate-delivery, signal, compensation, restart, layered retry-budget, fallback, quota,
1593
+ and health-check evidence.
1594
+ Every third_party_calls entry records the inspected wrapper chain and client family (Axios, Fetch, Java, .NET,
1595
+ Go, GraphQL, gRPC, or generated), base URL, auth, headers, timeout, retries, pagination, rate limits, normalized
1596
+ errors, webhook/replay behavior, parity evidence, and tests.
1597
+ Component matrices require:
1598
+ graph — schema, edges, indexes, traversal, reconciliation
1599
+ vector — dimensions, metric, embedding version, metadata schema, batching, quality
1600
+ storage — object keys, metadata, ACL, encryption, retention, multipart, checksums
1601
+ cache — keys, TTL, invalidation, stampede, consistency, fallback
1602
+ notifications — templates, channels, providers, suppression, retry, delivery, privacy
1603
+ analytics — event schema, identity, consent, masking, delivery, dashboard parity
1604
+ Provider migrations require tested resumability evidence.
1605
+ Runtime evidence covers safe procedures for TypeScript, Go, Java, and .NET; request/query/Event/Feature/external
1606
+ effect correlation; trace/log compatibility; load/concurrency/retry/duplicate delivery; lifecycle/restart;
1607
+ redaction; dashboards and alert thresholds.
1608
+ The sdk_matrix requires each supported language's exact package/version, installed capability evidence,
1609
+ equivalent parity tests, lifecycle and error-mapping requirements, examples, anti-patterns, and an explicit
1610
+ block/escalate policy for unsupported capabilities. Never silently emulate a missing SDK capability.
1611
+
1612
+ COMPREHENSIVE VERIFICATION MATRIX
1613
+ Record automation that the AI actually ran with normal project tools in a version:1,
1614
+ artifact_kind:"ductape_migration_verification_matrix" file, then:
1615
+ ductape_cli("migration-verification --file <verification-matrix.json> --strict --json")
1616
+ This command validates evidence; it never executes the recorded commands. Every one of 63 requirements
1617
+ must be passed and include tests, structured details, automation tool/command/result/environment, and
1618
+ source citations containing absolute repository, relative file, exact line range, and current SHA-256.
1619
+ A changed or missing cited file invalidates readiness.
1620
+ Categories cover multi-repository summaries/checkpoints/contracts; normalized before/after parity,
1621
+ nondeterminism, test strength, mutation and safe shadow signals; frontend browser/accessibility/visual/
1622
+ performance/security/mobile evidence; complete database modeling, data movement and cutover drills;
1623
+ component asset design/inventory/environment/provider/payload/dependency evidence; and contextual
1624
+ third-party client and App/Action designs.
1625
+ Dependency records require nodes, edges, and an evidenced order. Before/after records require explicit
1626
+ normalization and comparison. Nondeterminism requires named fields and approved differences. Visual,
1627
+ irreversible, and residual-uncertainty decisions require actor, authority, and approval evidence.
1628
+ Never manufacture an automation result or approval to satisfy the matrix. A blocked or failed record
1629
+ remains a blocker and must be reported as residual risk.
1630
+
1631
+ DEPENDENCY-AWARE LARGE-REPOSITORY PROPOSAL
1632
+ After contextual references exist in the review ledger, generate a non-authoritative proposal:
1633
+ ductape_cli("migration-portfolio propose --ledger <ledger> --max-bytes <bytes> --max-tokens <tokens> --json")
1634
+ The proposer builds the internal reference graph, condenses strongly connected components so cyclic files
1635
+ stay together, topologically orders dependencies before consumers, and records byte plus ceil(bytes/4)
1636
+ token estimates. An indivisible SCC over either configured limit is marked oversized_scc for human/AI
1637
+ review; it is never split unsafely. The output authority is advisory_only and must be contextually reviewed
1638
+ before it becomes a portfolio definition.
1639
+ Verification-matrix records may declare details.depends_on using category.requirement identifiers. A stale
1640
+ cited dependency transitively invalidates dependent service/package summaries and readiness.
1641
+
1642
+ MIGRATION ARTIFACT SAFETY
1643
+ Migration JSON is size-limited, secret-material scanned, version checked, and written through exclusive
1644
+ locks plus atomic rename. Mutating manifests retain a recoverable .bak copy. Validate or recover locally:
1645
+ ductape_cli("migration-artifact validate --file <artifact.json> --json")
1646
+ ductape_cli("migration-artifact recover --file <artifact.json> --json")
1647
+ Controlled legacy upgrades never rewrite the source artifact:
1648
+ ductape_cli("migration-artifact migrate --file <legacy.json> --output <v1.json> --json")
1649
+ Inspect the machine-readable schema catalog:
1650
+ ductape_cli("migration-artifact schemas --json")
1651
+ Errors include stable codes such as ARTIFACT_TOO_LARGE, ARTIFACT_SECRET_MATERIAL, ARTIFACT_LOCKED,
1652
+ ARTIFACT_VERSION_UNSUPPORTED, and ARTIFACT_RECOVERY_FAILED. Never bypass these checks with direct JSON edits.
1653
+
1654
+ PARITY-GATED MIGRATION SLICES
1655
+ Create a JSON array containing the reviewed repository-relative files for one vertical slice, then:
1656
+ ductape_cli("migration-slice init --ledger <ledger> --tag <tag> --name <name> --files <files.json> --json")
1657
+ Complete the generated slice manifest with:
1658
+ product_boundary, sdk_capabilities,
1659
+ interface_contracts, functional_requirements, operational_requirements,
1660
+ required_assets, tests, failure_tests, runtime_evidence, smoke_checks,
1661
+ cutover_conditions, rollback_conditions, deployment_cutover.
1662
+ Apply those fields through a validated definition JSON file:
1663
+ ductape_cli("migration-slice define --slice <slice.json> --data <definition.json> --json")
1664
+ Each required asset records kind, tag, action (reuse | create | update | blocked), and inventory_evidence.
1665
+ Inventory evidence must come from ductape_cli administrative inventory, never an assumed asset.
1666
+ product_boundary records product_tag, included services, target environments, and repository/inventory
1667
+ evidence. Never assume one repository equals one service or one Ductape product.
1668
+ sdk_capabilities records language, installed package, exact version, capability, and evidence from
1669
+ installed exports/types or version-matched primary documentation. Never assume cross-language parity.
1670
+ runtime_evidence and failure_tests cover behavior static review cannot prove: external effects,
1671
+ transactions, ordering, concurrency, retry/duplicate delivery, startup/shutdown, and degraded behavior.
1672
+ deployment_cutover records the implementation commit, per-environment deployed versions, feature-flag/
1673
+ dual-run/traffic state, explicit no-return points and mitigations, a timed observation window with success
1674
+ thresholds, dashboard/alert evidence, and a passing executed rollback rehearsal. Unrecorded deployment
1675
+ state or an untested rollback blocks strict readiness.
1676
+ Validate during work:
1677
+ ductape_cli("migration-slice validate --slice <slice.json> --json")
1678
+ Gate cutover:
1679
+ ductape_cli("migration-slice validate --slice <slice.json> --strict --json")
1680
+ A slice cannot be ready with stale/unreviewed files, incomplete parity, missing tests/smoke checks,
1681
+ missing failure/runtime evidence, an unproven product boundary or SDK capability, missing cutover or
1682
+ rollback conditions, incomplete asset evidence, or blocked reconciliation.
1683
+
1684
+ LARGE CODEBASES AND CONTEXT BOUNDARIES
1685
+ Never load a huge repository into one model context or rely on conversational memory for coverage.
1686
+ Partition reviewed files into bounded, non-overlapping groups with an explicit context_budget,
1687
+ durable summary, and file-checksum provenance. Define partitions, slice paths, and cross-slice contracts:
1688
+ ductape_cli("migration-portfolio init --ledger <ledger> --definition <portfolio-definition.json> --json")
1689
+ The CLI computes provenance checksums; changed files stale the affected partition summary.
1690
+ Validate resumable repository-wide coverage:
1691
+ ductape_cli("migration-portfolio validate --portfolio <portfolio.json> --json")
1692
+ Gate repository cutover:
1693
+ ductape_cli("migration-portfolio validate --portfolio <portfolio.json> --strict --json")
1694
+ Strict portfolio validation requires every ledger file in exactly one partition, current provenance,
1695
+ every slice ready, and evidenced provider/consumer cross-slice contracts. Summaries are navigation
1696
+ aids only; reopen source review whenever provenance becomes stale.
1697
+
1698
+ FRONTEND MIGRATION PARITY
1699
+ Mark frontend slices with surfaces: ["frontend"] (or include backend/worker for a mixed slice).
1700
+ Frontend strict readiness requires evidence for routes/navigation, rendered loading/empty/error/success
1701
+ states, forms/validation, accessibility, responsive behavior, browser storage, authentication transitions,
1702
+ SSR/hydration, realtime reconnect/resubscription, analytics/privacy, performance budgets,
1703
+ visual regression, and cross-browser behavior.
1704
+ Inspect installed @ductape/client, @ductape/react, or @ductape/vue exports before editing. Preserve UI
1705
+ contracts and application state semantics; do not replace domain state with analytics. Verify full-session
1706
+ identify/clearSession lifecycle, route pageviews, privacy masking, hidden-state exclusion, trace correlation,
1707
+ unsubscribe/teardown, reconnect duplication, SSR browser boundaries, and accessibility behavior.
1708
+
1709
+ PARITY CLAIMS
1710
+ Never promise or report "100% parity" merely because gates pass. The gates require the strongest available
1711
+ evidence and make unverified behavior explicit; arbitrary software cannot receive a mathematical parity
1712
+ guarantee from static review and finite tests. Each slice records before/after evidence from appropriate
1713
+ characterization, contract, golden, side-effect, database-state, event-order, failure-injection,
1714
+ load/concurrency, or safe shadow-comparison checks. Report residual uncertainty honestly.
1715
+ `.trim(),
1275
1716
  frontend: `
1276
1717
  DUCTAPE FRONTEND SDK GUIDE
1277
1718
 
@@ -1860,6 +2301,18 @@ An App must be fully set up in Ductape before any code can use it:
1860
2301
  4. Action endpoints must be defined (each action = one HTTP endpoint spec: method, path, body/query/header shape, response shape)
1861
2302
  5. The App must be connected to the product (product.apps.add) and its envs mapped
1862
2303
 
2304
+ DISCOVER BEFORE CREATING:
2305
+ ductape_cli("marketplace search payments --json")
2306
+ ductape_cli("marketplace search paystack --json")
2307
+ ductape_cli("marketplace categories --json")
2308
+ ductape_cli("marketplace get <app_tag> --json")
2309
+
2310
+ marketplace search matches capability terms against public app names, tags, descriptions,
2311
+ categories, actions, and webhooks. marketplace get returns the complete public app definition,
2312
+ including the exact current-version action tags and body/query/header/param schemas. Never infer
2313
+ Paystack action names such as "initialize" or "verify": inspect the marketplace record first.
2314
+ If no suitable app exists, create one or import Paystack's OpenAPI/Postman definition.
2315
+
1863
2316
  ONLY after all five steps can any code call:
1864
2317
  ctx.api.run({ app: '<app_tag>', event: '<action_tag>', input: { ... } }) ← in a feature handler
1865
2318
  actions.run([{ product, env, app: '<app_tag>', action: '<action_tag>', input }]) ← at runtime
@@ -1922,6 +2375,22 @@ Run an action at runtime:
1922
2375
  ductape_execute("actions.run", [{ product, env, app, action, input: { "body:field": value } }])
1923
2376
  ductape_execute("actions.dispatch", [{ product, env, app, action, input, schedule? }])
1924
2377
 
2378
+ In a Ductape feature handler, call the registered action through:
2379
+ await ctx.api.run({ app: "<app_tag>", event: "<action_tag>", input: { ... } })
2380
+ ctx.api is the supported feature-context surface (also described as ctx.action in older code).
2381
+ There is no ctx.apps, ctx.integrations, or generic external-HTTP feature surface.
2382
+
2383
+ PAYSTACK CONFIGURATION:
2384
+ - Store the secret key as a workspace secret such as PAYSTACK_SECRET_KEY.
2385
+ - Reference it from app auth as: Authorization = "Bearer $Secret{PAYSTACK_SECRET_KEY}".
2386
+ - Never place the key in feature input, source code, logs, or marketplace app metadata.
2387
+ - Initialization and verification are raw app actions unless the inspected app explicitly
2388
+ publishes a higher-level contract. Ductape has no universal application payment abstraction.
2389
+ - Model inbound events as app webhook events. Verify x-paystack-signature against the raw
2390
+ request body using HMAC-SHA512 and PAYSTACK_SECRET_KEY before processing.
2391
+ - Acknowledge quickly, process asynchronously, deduplicate by event/reference, and verify the
2392
+ transaction through the inspected verification action before granting value.
2393
+
1925
2394
  Auth schemes (how the app authenticates outbound requests):
1926
2395
  Setup types: header | bearer | basic | oauth2 | apikey
1927
2396
  Configure auth in Workbench (administrative).
@@ -2578,9 +3047,90 @@ PAYLOAD RECIPES
2578
3047
  features: `
2579
3048
  DUCTAPE FEATURES
2580
3049
 
2581
- A feature is an orchestrated workflow of durable steps. Steps can call app actions, database
2582
- operations, graph queries, storage uploads, notifications, broker publishes, child features,
2583
- quotas, fallbacks, and more. Features support rollback, signals, checkpoints, and sleep.
3050
+ A Feature is a named, reusable product capability with a stable input/output contract that
3051
+ benefits from managed execution, composition, observability, retries, versioning, policy
3052
+ enforcement, or explicit execution steps.
3053
+
3054
+ A Feature may be synchronous or asynchronous and may be entirely local. Signals, Events, waits,
3055
+ schedules, checkpoints, retries, compensation, and rollback are optional capabilities—not
3056
+ prerequisites. Asynchronous behavior is not the primary definition of a Feature.
3057
+
3058
+ Common Feature patterns:
3059
+ - synchronous capability
3060
+ - multi-step computation
3061
+ - event-driven orchestration
3062
+ - signal-driven human workflow
3063
+ - scheduled capability
3064
+ - parent/child Feature composition
3065
+
3066
+ ━━━ CAPABILITY CLASSIFICATION — explain the evidence for every classification ━━━
3067
+
3068
+ Use exactly these categories while reviewing application code:
3069
+ FEATURE
3070
+ An independently meaningful product/domain capability with a useful managed-execution boundary.
3071
+ Recommendation: "Make this a standalone Ductape Feature."
3072
+ FEATURE_STEP
3073
+ A meaningful stage inside a larger capability, but not a useful independent execution boundary.
3074
+ Recommendation: "Expose this as a named ctx.step(...) inside another Feature."
3075
+ DOMAIN_SERVICE
3076
+ Reusable domain logic without a useful independent managed-execution boundary.
3077
+ Recommendation: "Keep this as ordinary domain logic called by a Feature."
3078
+ UTILITY
3079
+ A low-level helper such as hashing, formatting, redaction, normalization, conversion, or a type guard.
3080
+ Recommendation: "Keep this as a utility."
3081
+ INFRASTRUCTURE_ADAPTER
3082
+ Database, Event, HTTP, cache, storage, provider, transport, or framework integration code.
3083
+ Recommendation: "Keep this as an infrastructure adapter."
3084
+
3085
+ TypeScript export is only evidence of reuse. It is neither sufficient nor necessary for Feature
3086
+ classification. Never classify every exported function as a Feature.
3087
+
3088
+ Evaluate a candidate by asking:
3089
+ - Does it represent a recognizable product or domain capability?
3090
+ - Does it have a coherent responsibility?
3091
+ - Can it have a stable, typed input/output contract?
3092
+ - Is it reused across entry points, services, or other Features?
3093
+ - Would independent execution or composition be useful?
3094
+ - Would execution history or step-level observability be valuable?
3095
+ - Does it need explicit versioning, authorization, quotas, retries, or policy?
3096
+ - Does it contain several meaningful stages?
3097
+ - Would users or developers naturally name it as a product feature?
3098
+ A positive answer to several questions makes it a Feature candidate even when it is synchronous
3099
+ and local. No single answer is sufficient, and signals, Events, or long runtime are never required.
3100
+
3101
+ Keep low-level deterministic rules as ordinary domain functions when they do not form a useful
3102
+ independent capability boundary. Wrap or compose them into Features when the combined operation
3103
+ represents a reusable product capability.
3104
+
3105
+ When inspecting a TypeScript repository, examine:
3106
+ exported functions; public service methods; controller entry points; Event consumers; scheduled
3107
+ jobs; repeated orchestration sequences; domain operations reused in several locations; functions
3108
+ with substantial typed inputs/outputs; functions composing several stages; and product terminology
3109
+ in documentation and API routes. Do not restrict discovery to *.feature.ts or features.define calls.
3110
+
3111
+ Group related low-level operations into one coherent capability candidate. For example,
3112
+ resolveNationOrders, applyProvinceStockpileProduction, applyProvinceStockpileTransfers, and
3113
+ resolveFormationCommands may collectively suggest resolve-match-boundary or resolve-nation-turn.
3114
+ They must not automatically become four separate Features.
3115
+
3116
+ For repository analysis, return a structured inventory for every recommendation:
3117
+ {
3118
+ "candidate": "resolve-nation-turn",
3119
+ "classification": "FEATURE",
3120
+ "executionStyle": "synchronous-multistep",
3121
+ "evidence": [
3122
+ "Represents a recognizable game capability",
3123
+ "Has a stable input/output boundary",
3124
+ "Composes validation, production, resolution, and reporting",
3125
+ "Useful as an independently observable execution"
3126
+ ],
3127
+ "suggestedSteps": ["validate-orders", "apply-production", "resolve-orders", "build-reports"],
3128
+ "signalsRequired": false,
3129
+ "eventsRequired": false,
3130
+ "recommendation": "Make this a standalone Ductape Feature."
3131
+ }
3132
+ Every classification needs concrete code, caller, contract, or product-language evidence. If the
3133
+ boundary remains ambiguous, report both plausible categories and the missing evidence; do not guess.
2584
3134
 
2585
3135
  ━━━ AI DESIGN WORKFLOW — follow this process every time a user asks you to build or plan a feature ━━━
2586
3136
 
@@ -2616,12 +3166,14 @@ STEP 2 — INVENTORY existing Ductape components
2616
3166
 
2617
3167
  STEP 3 — PLAN each step
2618
3168
  For every logical step:
2619
- a. Identify which existing component handles it, or flag it as needing creation.
3169
+ a. Identify whether it is local domain logic, a child Feature, or an existing Ductape component.
3170
+ Local typed domain logic may run inside ctx.step; it does not require an Event or App.
2620
3171
  If a step calls an external service, it MUST go through a registered Ductape App.
2621
3172
  If no App for that service exists in the product → mark it "App to create: <service name>".
2622
3173
  DO NOT plan a raw HTTP call, a direct dispatch to a URL, or any workaround in place of a missing App.
2623
3174
  b. Note how inputs flow: ctx.input fields, or return values from earlier steps (plain JS variables — no special notation needed)
2624
- c. Decide if a rollback handler is needed (e.g. charge → refund on later failure)
3175
+ c. Decide if a rollback handler is needed (e.g. charge → refund on later failure).
3176
+ Rollback is optional and is not a Feature qualification requirement.
2625
3177
  d. Decide allow_fail: true for non-critical steps (email, analytics, audit logs)
2626
3178
 
2627
3179
  STEP 4 — PRESENT the plan and get approval BEFORE writing any code or creating anything
@@ -2675,8 +3227,40 @@ STEP 8 — SET rollbacks for reversible steps
2675
3227
  async (result) => ctx.api.run({ app: 'stripe', event: 'refund', input: { chargeId: result.id } })
2676
3228
  );
2677
3229
 
2678
- Step types: action | database | graph | notification | storage | produce | quota | fallback |
2679
- vector | child_feature | sleep | wait_for_signal | checkpoint
3230
+ Step types: local_domain | action | database | graph | notification | storage | produce | quota |
3231
+ fallback | vector | child_feature | sleep | wait_for_signal | checkpoint
3232
+
3233
+ Valid synchronous Feature candidates include generate-world, resolve-nation-turn,
3234
+ calculate-route-capacity, price-subscription, evaluate-entitlement, and build-replay.
3235
+
3236
+ Synchronous multi-step Feature (no Event, schedule, sleep, signal, or external system):
3237
+ await ductape.features.define({
3238
+ product: 'example-product',
3239
+ tag: 'resolve-nation-turn',
3240
+ name: 'Resolve Nation Turn',
3241
+ input: {
3242
+ nationId: { type: 'string', required: true },
3243
+ tick: { type: 'number', required: true },
3244
+ },
3245
+ output: {
3246
+ acceptedOrders: { type: 'number' },
3247
+ rejectedOrders: { type: 'number' },
3248
+ },
3249
+ handler: async (ctx) => {
3250
+ const validated = await ctx.step('validate-orders', async () => {
3251
+ return validateOrders(ctx.input);
3252
+ });
3253
+ const resolved = await ctx.step('resolve-orders', async () => {
3254
+ return resolveOrders(validated);
3255
+ });
3256
+ return ctx.step('build-result', async () => {
3257
+ return buildResult(resolved);
3258
+ });
3259
+ },
3260
+ });
3261
+ This is a valid Feature despite requiring no signal and producing no Event. Its qualification comes
3262
+ from the named capability, stable contract, meaningful stages, reuse/composition value, and useful
3263
+ step-level execution history.
2680
3264
 
2681
3265
  Define a feature (write this into the project's source files — do NOT use features.create):
2682
3266
  // src/features/onboard-user.ts (or the equivalent path/language for the project)
@@ -2749,12 +3333,16 @@ When you call features.define({ handler }), the handler runs TWICE:
2749
3333
  outer handler body. Code in the outer body runs during recording with proxy values and
2750
3334
  may behave unexpectedly (e.g. typeof proxy === 'object' is true but .someField is a proxy).
2751
3335
 
2752
- Features do NOT execute arbitrary NestJS or server code directly. A feature handler can only
2753
- call Ductape component primitives (ctx.api, ctx.database, ctx.notification, etc.) as steps.
2754
- To invoke internal application business logic, produce a broker event from a feature step
2755
- (ctx.events.produce in the currently published SDK) and consume it in your NestJS service.
2756
- ctx.publish is deprecated; do not use it. Do not assume a ctx.messaging alias exists unless the
2757
- installed SDK types explicitly expose it.
3336
+ A ctx.step callback may call ordinary local domain functions and injected/application services
3337
+ available to the registration scope. This is the normal shape for a synchronous capability such
3338
+ as pricing, entitlement evaluation, route-capacity calculation, or turn resolution. Keep the
3339
+ meaningful work inside ctx.step callbacks so recording does not execute it.
3340
+
3341
+ Use an Event when the operation genuinely crosses an asynchronous process/service boundary,
3342
+ needs broker delivery semantics, or must be consumed independently. Do not produce an Event merely
3343
+ to reach local domain logic. When an Event is appropriate, use ctx.events.produce in the currently
3344
+ published SDK and consume it in the NestJS service. ctx.publish is deprecated; do not use it.
3345
+ Do not assume a ctx.messaging alias exists unless installed SDK types explicitly expose it.
2758
3346
 
2759
3347
  ━━━ ORCHESTRATION DECISION RULE ━━━
2760
3348
 
@@ -2764,7 +3352,10 @@ When you call features.define({ handler }), the handler runs TWICE:
2764
3352
  e.g. ductape.api.dispatch({ ..., schedule: { start_at: ... } })
2765
3353
  e.g. ductape.database.dispatch({ ..., schedule: { start_at: ... } })
2766
3354
 
2767
- Several durable Ductape component operations in sequence (with rollback / retry / state):
3355
+ A named synchronous or asynchronous product capability with meaningful managed steps:
3356
+ → define a Feature; execute it directly when immediate, or dispatch it when scheduled/background
3357
+
3358
+ Several durable Ductape component operations in sequence (with optional rollback / retry / state):
2768
3359
  → define a Feature, then features.dispatch to schedule it
2769
3360
 
2770
3361
  Invoke internal application business logic (your own NestJS/backend service code):
@@ -3786,7 +4377,9 @@ async function main() {
3786
4377
  }
3787
4378
  const firstWord = args.command.trim().split(/\s+/)[0];
3788
4379
  const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
3789
- if (!isAuthCommand) {
4380
+ const isLocalMigrationGuidance = (firstWord === 'migrate-codebase' && !args.command.includes('--ensure-product')) ||
4381
+ firstWord.startsWith('migration-');
4382
+ if (!isAuthCommand && !isLocalMigrationGuidance) {
3790
4383
  // Cache successful authentication, but re-check a missing/expired session on every call.
3791
4384
  // The user may complete `ductape login` in another terminal while this MCP process remains
3792
4385
  // alive; caching "none" would otherwise make the MCP blind to the newly written session.
@@ -3836,6 +4429,35 @@ async function main() {
3836
4429
  ...(result.success ? {} : { isError: true }),
3837
4430
  };
3838
4431
  };
4432
+ const migrationHandler = async (args) => {
4433
+ if (args.mode === 'new-codebase' && !args.destination) {
4434
+ return {
4435
+ content: [{ type: 'text', text: 'Error: destination is required for new-codebase mode.' }],
4436
+ isError: true,
4437
+ };
4438
+ }
4439
+ const client = server.server?.getClientVersion?.();
4440
+ const command = [
4441
+ 'migrate-codebase',
4442
+ '--source', shellArgument(args.source),
4443
+ '--e2e-baseline', shellArgument(args.e2e_baseline),
4444
+ '--mode', args.mode,
4445
+ ...(args.destination ? ['--destination', shellArgument(args.destination)] : []),
4446
+ ...(args.product ? ['--product', shellArgument(args.product)] : []),
4447
+ ...(args.name ? ['--name', shellArgument(args.name)] : []),
4448
+ ...(args.database ? ['--database', shellArgument(args.database)] : []),
4449
+ '--max-file-bytes', String(args.max_file_bytes),
4450
+ ...(args.include.length ? ['--include', shellArgument(args.include.join(','))] : []),
4451
+ ...(args.exclude.length ? ['--exclude', shellArgument(args.exclude.join(','))] : []),
4452
+ ...(args.ensure_product ? ['--ensure-product'] : []),
4453
+ ...(args.write ? ['--write'] : []),
4454
+ ...(client?.name && client?.version
4455
+ ? ['--mcp-client-name', shellArgument(client.name), '--mcp-client-version', shellArgument(client.version)]
4456
+ : []),
4457
+ '--json',
4458
+ ].join(' ');
4459
+ return cliHandler({ command });
4460
+ };
3839
4461
  const executeHandler = async (args) => {
3840
4462
  try {
3841
4463
  const runtimeMutationMethods = {
@@ -4023,9 +4645,22 @@ async function main() {
4023
4645
  'index strategy, operation types) that should be confirmed with the user first.\n\n' +
4024
4646
  'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
4025
4647
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
4026
- 'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue',
4648
+ 'notifications, resilience, features, events, logs, migration, frontend, frontend-analytics, client, react, vue',
4027
4649
  inputSchema: docsInputSchema,
4028
4650
  }, docsHandler);
4651
+ server.registerTool('ductape_migration_plan', {
4652
+ title: 'Ductape AI Migration Guidance',
4653
+ description: 'Inspect a TypeScript, Go, Java, or .NET repository without exposing secret values. ' +
4654
+ 'Builds a relevant-file review queue, secret-name inventory, checksummed migration evidence, and low-confidence navigation hints. ' +
4655
+ 'The review standards classify capability candidates as FEATURE, FEATURE_STEP, DOMAIN_SERVICE, UTILITY, or INFRASTRUCTURE_ADAPTER; ' +
4656
+ 'they inspect exports, public methods, entry points, consumers, jobs, repeated orchestration, typed operations, routes, and product terminology. ' +
4657
+ 'Synchronous local multi-step capabilities may be Features, while related low-level functions must be grouped rather than promoted one-by-one. ' +
4658
+ 'Every recommendation must return classification, execution style, evidence, suggested steps, and whether signals or Events are actually required. ' +
4659
+ 'The AI must review files contextually and maintain an evidence ledger before proposing components or schemas. ' +
4660
+ 'It never generates or rewrites application code or executable assets. ' +
4661
+ 'Supports in-place and new-codebase guidance destinations. Read-only unless write or ensure_product is explicitly enabled.',
4662
+ inputSchema: migrationInputSchema,
4663
+ }, migrationHandler);
4029
4664
  server.registerTool('ductape_cli', {
4030
4665
  title: 'Ductape CLI',
4031
4666
  description: 'Run a Ductape CLI command for administrative operations.\n\n' +
@@ -4135,6 +4770,7 @@ async function main() {
4135
4770
  server.tool('ductape_generate_snippet', snippetGenerateInputSchema.shape, snippetGenerateHandler);
4136
4771
  server.tool('ductape_schema', schemaInputSchema.shape, schemaHandler);
4137
4772
  server.tool('ductape_docs', docsInputSchema.shape, docsHandler);
4773
+ server.tool('ductape_migration_plan', migrationInputSchema.shape, migrationHandler);
4138
4774
  server.tool('ductape_cli', cliInputSchema.shape, cliHandler);
4139
4775
  }
4140
4776
  else {