Command-line interface for the Effect migration toolkit.
⚠️ Early Stage Development
This package is under active development. Core commands work, but some features are still in progress.
| Command | Status | Description |
|---|---|---|
init |
🧪 Dogfooding | Create configuration file |
audit |
🧪 Dogfooding | Detect migration issues |
thread add |
🧪 Dogfooding | Track Amp thread URLs |
thread list |
🧪 Dogfooding | List tracked threads |
checkpoints list |
🧪 Dogfooding | List audit checkpoint history |
checkpoints show |
🧪 Dogfooding | Show specific checkpoint |
checkpoints diff |
🧪 Dogfooding | Compare two checkpoints |
metrics |
🧪 Dogfooding | Show migration progress |
docs |
📅 Not Started | Validate documentation |
--help |
✅ Complete | Show command help |
Install as a dev dependency:
pnpm add -D @effect-migrate/cliOr globally:
pnpm add -g @effect-migrate/cliNote: APIs are unstable and may change. Pin to specific versions in production.
Then run commands:
effect-migrate --help
effect-migrate audit
effect-migrate thread listeffect-migrate --help
effect-migrate audit --help
effect-migrate thread --help
effect-migrate checkpoints --helpAll commands support:
--help— Show command-specific help--version— Show version information--log-level <level>— Set minimum log level (all, trace, debug, info, warning, error, fatal, none)--completions <shell>— Generate shell completion script (sh, bash, fish, zsh)
Create a new effect-migrate.config.ts file with type-safe defaults.
Usage:
effect-migrate initGenerated config:
import { defineConfig } from "@effect-migrate/core"
export default defineConfig({
version: 1,
presets: ["@effect-migrate/preset-basic"],
paths: {
include: ["src/**/*.{ts,tsx}"],
exclude: ["**/{node_modules,dist,build}/**"]
}
})Options:
- Currently no options; future versions may support
--preset,--output, etc.
Run pattern and boundary rules against your codebase to detect migration issues.
Usage:
# Basic audit
effect-migrate audit
# With custom config
effect-migrate audit --config my-config.ts
# Output as JSON
effect-migrate audit --json
# Write Amp context files
effect-migrate audit --amp-out .amp/effect-migrate
# Strict mode (fail on warnings)
effect-migrate audit --strictOptions:
| Option | Type | Default | Description |
|---|---|---|---|
--config, -c |
string |
effect-migrate.config.ts |
Path to configuration file |
--json |
boolean |
false |
Output results as JSON |
--amp-out |
string |
(optional) | Directory to write Amp context files |
--strict |
boolean |
false |
Fail on warnings (not just errors) |
Console Output:
🔍 Running migration audit...
Pattern Violations
══════════════════
❌ src/api/fetchUser.ts:23
Replace async/await with Effect.gen (no-async-await)
Boundary Violations
═══════════════════
❌ src/services/FileService.ts:5
Use @effect/platform instead of Node.js APIs (no-node-in-services)
Import: node:fs/promises
Summary
═══════
Errors: 1
Warnings: 1
JSON Output (--json):
{
"summary": {
"total": 2,
"errors": 1,
"warnings": 1
},
"findings": [
{
"id": "no-async-await",
"file": "src/api/fetchUser.ts",
"line": 23,
"column": 1,
"severity": "error",
"message": "Replace async/await with Effect.gen",
"docsUrl": "https://effect.website/docs/essentials/effect-type"
}
]
}Amp Context Output (--amp-out):
When you specify --amp-out, the following files are generated:
index.json— Entry point for Amp and other agentsaudit.json— Detailed findings with schema version and revisionthreads.json— Tracked threads (if any exist)
Add an Amp thread URL to track migration work and context.
Usage:
# Basic usage
effect-migrate thread add --url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc
# With tags
effect-migrate thread add \
--url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc \
--tags "migration,services"
# With scope (file globs)
effect-migrate thread add \
--url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc \
--tags "migration,api" \
--scope "src/api/**,src/services/**"
# With description
effect-migrate thread add \
--url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc \
--description "Migrated user authentication to Effect"
# Write to custom directory
effect-migrate thread add \
--url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc \
--amp-out .amp/customOptions:
| Option | Type | Required | Description |
|---|---|---|---|
--url |
string |
✅ Yes | Amp thread URL (format: https://ampcode.com/threads/T-{uuid}) |
--tags |
string |
No | Comma-separated tags (e.g., migration,api) |
--scope |
string |
No | Comma-separated file globs (e.g., src/api/**) |
--description |
string |
No | Optional description of thread context |
--amp-out |
string |
No | Directory to write threads.json (default: .amp/effect-migrate) |
Thread URL Validation:
URLs must match the format https://ampcode.com/threads/T-{uuid} (case-insensitive). The thread ID is normalized to lowercase.
Behavior:
- Adding new thread: Creates entry with
createdAttimestamp - Re-adding same thread: Replaces tags and scope (no merging); preserves original
createdAt - Sorting: Threads are sorted by
createdAtdescending (newest first)
Output:
✓ Added thread T-abc12345-6789-abcd-ef01-234567890abc
or
✓ Updated thread T-abc12345-6789-abcd-ef01-234567890abc: replaced tags/scope
Display all tracked Amp threads.
Usage:
# Human-readable format
effect-migrate thread list
# JSON format
effect-migrate thread list --json
# Read from custom directory
effect-migrate thread list --amp-out .amp/customOptions:
| Option | Type | Default | Description |
|---|---|---|---|
--json |
boolean |
false |
Output as JSON |
--amp-out |
string |
.amp/effect-migrate |
Directory to read threads.json from |
Console Output:
T-abc12345-6789-abcd-ef01-234567890abc
URL: https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc
Tags: migration, services
Scope: src/services/**
Created: 2025-11-07T10:00:00Z
T-def67890-1234-5678-90ab-cdef12345678
URL: https://ampcode.com/threads/T-def67890-1234-5678-90ab-cdef12345678
Tags: migration, api
Created: 2025-11-06T15:30:00Z
JSON Output:
{
"threads": [
{
"id": "T-abc12345-6789-abcd-ef01-234567890abc",
"url": "https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc",
"tags": ["migration", "services"],
"scope": ["src/services/**"],
"description": "Migrated user services to Effect",
"createdAt": "2025-11-07T10:00:00Z"
}
]
}View and compare checkpoint history from time-series audit snapshots.
Display all audit checkpoints with deltas showing progress over time.
Usage:
# List all checkpoints
effect-migrate checkpoints list
# JSON format
effect-migrate checkpoints list --json
# Custom amp-out directory
effect-migrate checkpoints list --amp-out .amp/customOptions:
| Option | Type | Default | Description |
|---|---|---|---|
--json |
boolean |
false |
Output as JSON |
--amp-out |
string |
.amp/effect-migrate |
Directory to read checkpoints from |
Console Output:
Checkpoint ID | Timestamp | Thread | Errors | Warnings | Info | Delta
────────────────────────────────────────────────────────────────────────────────────────────────────
2025-11-08T14-30-00Z | 2025-11-08 14:30:00 | T-abc123 | 5 | 12 | 3 | -2 errors, -3 warnings
2025-11-08T10-00-00Z | 2025-11-08 10:00:00 | T-def456 | 7 | 15 | 3 | +1 error, +2 warnings
2025-11-07T16-45-00Z | 2025-11-07 16:45:00 | | 6 | 13 | 3 | (initial)
JSON Output:
{
"checkpoints": [
{
"id": "2025-11-08T14-30-00Z",
"timestamp": "2025-11-08T14:30:00.000Z",
"thread": "T-abc123-uuid",
"summary": {
"errors": 5,
"warnings": 12,
"info": 3,
"totalFiles": 42,
"totalFindings": 20
},
"delta": {
"errors": -2,
"warnings": -3,
"info": 0,
"totalFindings": -5
}
}
]
}Display the most recent checkpoint details.
Usage:
# Show latest checkpoint
effect-migrate checkpoints latest
# JSON format
effect-migrate checkpoints latest --jsonDisplay details for a specific checkpoint by ID.
Usage:
# Show checkpoint
effect-migrate checkpoints show 2025-11-08T14-30-00Z
# JSON format
effect-migrate checkpoints show 2025-11-08T14-30-00Z --jsonCompare two checkpoints and show what changed between them.
Usage:
# Compare two checkpoints
effect-migrate checkpoints diff 2025-11-08T10-00-00Z 2025-11-08T14-30-00Z
# JSON format
effect-migrate checkpoints diff 2025-11-08T10-00-00Z 2025-11-08T14-30-00Z --jsonConsole Output:
Comparing checkpoints:
From: 2025-11-08T10-00-00Z (2025-11-08 10:00:00)
To: 2025-11-08T14-30-00Z (2025-11-08 14:30:00)
Changes:
Errors: 7 → 5 (-2)
Warnings: 15 → 12 (-3)
Info: 3 → 3 (0)
Total: 25 → 20 (-5)
Progress: ✅ Improved (5 fewer findings)
⏳ In Progress — This command is under development.
Show migration progress metrics based on rule violations and file coverage.
Planned usage:
# Show metrics
effect-migrate metrics
# Write metrics.json for Amp
effect-migrate metrics --amp-out .amp/effect-migrate
# JSON output
effect-migrate metrics --jsonThe CLI automatically loads and merges rules from presets specified in your config.
- Sequential loading: Presets are loaded in the order specified in
presets: [...] - Rule merging: All preset rules are combined with your custom
patternsandboundaries - Config merging: Preset defaults (like
paths.exclude) are merged with your config - User config precedence: Your config values always override preset defaults
// Preset provides:
{
paths: {
exclude: ["node_modules/**", "dist/**"]
}
}
// Your config:
{
presets: ["@effect-migrate/preset-basic"],
paths: {
exclude: ["vendor/**"] // MERGES with preset excludes
}
}
// Effective config:
{
paths: {
exclude: ["node_modules/**", "dist/**", "vendor/**"]
}
}Missing preset module:
$ effect-migrate audit
⚠️ Failed to load preset @myteam/custom-rules: Cannot find module '@myteam/custom-rules'
✓ Loaded 1 preset(s)The CLI logs a warning and continues with remaining presets. User-defined rules still execute.
Invalid preset shape:
If a preset doesn't export the correct structure ({ rules: Rule[], defaults?: {} }), the CLI logs:
⚠️ Failed to load preset @myteam/broken-preset: Invalid preset shapeUse log level to see which rules are loaded:
effect-migrate audit --log-level debugOutput shows:
- Which presets loaded successfully
- Number of rules from each preset
- Effective config after merging
The CLI uses standard exit codes:
0— Success (audit passed, no errors)1— Failure (audit found errors, or command failed)2— Invalid usage (missing required arguments, invalid options)
Audit behavior:
- Returns
0if no violations or only warnings - Returns
1if any violations withseverity: "error"
Thread URLs must be valid Amp thread URLs matching the format:
https://ampcode.com/threads/T-{uuid}
Examples:
# ✅ Valid
effect-migrate thread add --url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abc
# ✅ Valid (case-insensitive)
effect-migrate thread add --url https://ampcode.com/threads/t-abc12345-6789-abcd-ef01-234567890abc
# ❌ Invalid (missing https://)
effect-migrate thread add --url ampcode.com/threads/T-abc123
# ❌ Invalid (wrong format)
effect-migrate thread add --url https://ampcode.com/threads/abc123The --url flag is required when adding threads:
effect-migrate thread add --url https://ampcode.com/threads/T-abc12345-6789-abcd-ef01-234567890abcThread metadata is stored in threads.json and referenced in audit.json. Run audit after adding threads to regenerate context files:
effect-migrate thread add --url https://ampcode.com/threads/T-...
effect-migrate audit --amp-out .amp/effect-migrateAdding the same thread URL multiple times replaces the existing entry. Tags and scope from the new command override previous values; they are not merged.
If you want to preserve existing tags, include them in the new command:
# First add
effect-migrate thread add --url https://... --tags "migration"
# Later, to add another tag, include both:
effect-migrate thread add --url https://... --tags "migration,services"By default, the CLI looks for effect-migrate.config.ts in the current directory. Use --config to specify a different path:
effect-migrate audit --config ./config/migration.config.tsWhen developing locally in the monorepo, preset loading via import() may fail due to workspace resolution. This is expected and handled gracefully:
⚠️ Failed to load preset @effect-migrate/preset-basic: Cannot find moduleThis is a known limitation of local development. Once published to npm, preset loading works correctly. Your custom rules defined in the config will still execute.
If effect-migrate command is not found:
For local development:
Use the workspace filter:
pnpm -w --filter @effect-migrate/cli exec effect-migrate --helpFor global installation (after publishing):
pnpm add -g @effect-migrate/cliWant to try the CLI before it's published?
git clone https://github.com/aridyckovsky/effect-migrate.git
cd effect-migrate
pnpm install
pnpm buildDuring development (recommended, no build needed):
# Run from source using tsx
pnpm cli --help
pnpm cli audit
pnpm cli thread list --json
pnpm cli --versionUsing built version:
node packages/cli/build/esm/index.js --help
node packages/cli/build/esm/index.js audit
node packages/cli/build/esm/index.js thread list --json- Main Repository
- AGENTS.md — Development guidelines and Effect patterns
- @effect-migrate/core — Migration engine
- @effect-migrate/preset-basic — Default rules
MIT © 2025 Ari Dyckovsky