switchit-harness 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SwitchIt! contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: switchit-harness
3
+ Version: 0.1.0
4
+ Summary: Evidence-based migration of AI workflows between providers: import traces, replay them through adapters, and report what survives the switch.
5
+ Author: SwitchIt! contributors
6
+ License: MIT
7
+ Keywords: ai,llm,migration,evaluation,traces,otel,openai,anthropic,bedrock,agents,replay,mcp
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: parquet
24
+ Requires-Dist: pyarrow>=14; extra == "parquet"
25
+ Provides-Extra: bedrock
26
+ Requires-Dist: boto3>=1.34; extra == "bedrock"
27
+ Provides-Extra: all
28
+ Requires-Dist: pyarrow>=14; extra == "all"
29
+ Requires-Dist: boto3>=1.34; extra == "all"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pyarrow>=14; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # SwitchIt!
35
+
36
+ SwitchIt! helps teams move AI workflows from one provider to another with evidence that the important behavior survives the move.
37
+
38
+ The harness ingests authorized traces and application configuration, maps the workflows people actually use, selects representative replay cases, runs them against a target provider, and compares task outcomes, tool behavior, latency, and token usage. It produces a migration report with failures, uncertainties, and concrete changes needed.
39
+
40
+ The companion skill guides an agent through reviewing the evidence, resolving ambiguous workflows, and preparing a migration plan. The harness performs the reproducible imports, replays, comparisons, and checks. Use `$switchit` from any project to ask for a provider migration plan or a verified switch; see the [skill](skills/switchit/SKILL.md), the [system map](docs/system-map.svg), and the [migration run](docs/migration-run.svg).
41
+
42
+ First milestone — shipped in `switchit/`: JSON/JSONL, OTLP, Langfuse-style, and Parquet importers; one recorded baseline adapter; mock and live (OpenAI-compatible, Anthropic, Bedrock Converse) target adapters; and a complete offline replay loop with JSON + HTML reports on synthetic traces.
43
+
44
+ ## Install
45
+
46
+ ```sh
47
+ pip install switchit-harness # from PyPI, once published
48
+ # or from this repository:
49
+ pip install .
50
+
51
+ switchit --version
52
+ python3 -m switchit.cli --version # same thing without the entry point
53
+ ```
54
+
55
+ The core is stdlib-only. Add extras only if you need them: `pip install 'switchit-harness[parquet]'` for Parquet imports, `'switchit-harness[bedrock]'` for the Bedrock adapter.
56
+
57
+ To install the companion `$switchit` agent skill for tools that read `~/.agents/skills`:
58
+
59
+ ```sh
60
+ ./scripts/install-skill.sh
61
+ ```
62
+
63
+ ## Quick start (fully offline, no credentials)
64
+
65
+ ```sh
66
+ # One command on the bundled synthetic demo dataset:
67
+ python3 -m switchit.cli run --demo --state-dir /tmp/switchit-demo
68
+ open /tmp/switchit-demo/run/report.html
69
+
70
+ # Or step by step on the files in examples/:
71
+ python3 -m switchit.cli import --jsonl examples/traces.jsonl --app-config examples/app_config.json --state-dir .switchit
72
+ python3 -m switchit.cli map --state-dir .switchit # provisional workflow map; edit workflows.json to correct it
73
+ python3 -m switchit.cli map --keep-edits --state-dir .switchit # re-runs keep your edits
74
+ python3 -m switchit.cli cases --state-dir .switchit # replay set; edit cases.json to add real success checks
75
+ python3 -m switchit.cli replay --state-dir .switchit # recorded baseline vs mock target, checkpointed
76
+ python3 -m switchit.cli report --state-dir .switchit # report.json + report.html
77
+ ```
78
+
79
+ ## What each stage produces
80
+
81
+ | Stage | Artifact | Notes |
82
+ |---|---|---|
83
+ | `import` | `<state-dir>/store.json` | Canonical sessions, traces, calls. Secrets redacted at import — redacted content is the only content stored, replayed, or reported. Usage provenance kept separate: `recorded` / `estimated` / `unknown`. Sources: your exports **and** coding-agent session folders you already have (`--agents` reads Codex, Claude Code, and OpenCode locally). |
84
+ | `profile` | `profile.json` + `app_config.inferred.json` | Digs through the sessions: system prompts, tool inventory with schemas inferred from observed calls, provider/model mix, error samples. The inferred app config is a ready-to-edit starting point. |
85
+ | `map` | `workflows.json` | TF-IDF + tool-overlap grouping with confidence and uncertainty flags. Labels are triage aids; set `"edited": true` and fix names/members to correct them. |
86
+ | `cases` | `cases.json` | One case per selected trace covering common, costly, risky, and failed workflows, with default checks. Edit to add explicit success checks — a historical model response alone is not proof of success. |
87
+ | `replay` | `run/results.json` + `run/run_state.json` | Same cases through baseline and target adapters. Tool proposals are captured, never executed. Checkpointed after every case; a fingerprint refuses to resume after cases, adapters, or runner code changed. |
88
+ | `report` | `run/report.json` + `run/report.html` | Verdicts (pass / fail / error / uncertain), failure groups, capability gaps, prioritized fixes, usage by provenance. Local, self-contained HTML. |
89
+
90
+ ## Connectors
91
+
92
+ - **Inputs:** OpenTelemetry/OTLP JSON (`--otlp`), JSON/JSONL (`--jsonl`), Langfuse-style exports (`--langfuse`), and Parquet / ZIP-of-`traces.parquet` (`--parquet`, needs the optional `pyarrow` package). A simple app-configuration JSON (`--app-config`) supplies prompts and tool definitions.
93
+ - **Providers:** recorded baseline and mock adapters for offline work; OpenAI-compatible HTTP, Anthropic Messages, and Amazon Bedrock Converse for live tests. Provider presets fill in the details: `--target grok` (xAI), `groq`, `deepseek`, `mistral`, `openrouter`, `together`, `fireworks`, `ollama` (free, fully local), `vllm` (local). Meta Llama runs through `ollama`/`vllm`/`together`/`fireworks`/`bedrock`.
94
+ - **Secrets:** environment variables only — `OPENAI_API_KEY`, `XAI_API_KEY`, `GROQ_API_KEY`, `ANTHROPIC_API_KEY`, the standard AWS chain, and so on per provider. Keys are never accepted on the command line or written to files. Local import and analysis do not contact a provider.
95
+ - **Memory services:** products like Supermemory are business tools your agent calls, not chat-completion providers — so they are captured as tool proposals during replay, never executed, and are not replay targets.
96
+
97
+ ## Live replay is an explicit opt-in
98
+
99
+ ```sh
100
+ export OPENAI_API_KEY='...'
101
+ python3 -m switchit.cli replay --target openai --target-model gpt-4o-mini --remote --state-dir .switchit
102
+ ```
103
+
104
+ Without `--remote`, live targets refuse to run. With it, the redacted case requests are sent to the target provider and billed accordingly; usage is recorded from provider responses, and requests that fail before a response keep their consumption counted separately as unknown.
105
+
106
+ ## Traces you already have: coding agents
107
+
108
+ Most developers already have rich agent traces on disk without ever instrumenting anything. SwitchIt reads them directly, with the same redaction and provenance rules as every other source:
109
+
110
+ ```sh
111
+ switchit import --agents # Codex, Claude Code, OpenCode session folders
112
+ switchit profile --state-dir .switchit # prompts, tool schemas, provider mix — dug out automatically
113
+ ```
114
+
115
+ - **Codex**: `~/.codex/sessions/**/*.jsonl` — model calls, `function_call`s and outputs, token counts
116
+ - **Claude Code**: `~/.claude/projects/**/*.jsonl` — transcripts with `tool_use` blocks and per-message usage
117
+ - **OpenCode**: `~/.local/share/opencode/opencode.db` — message/part tables (read-only SQLite)
118
+ - **Cursor**: `~/.cursor/chats/*/*/store.db` — chat messages per workspace, system prompts, agentic tool calls (Cursor reports no usage, so those calls land in the `unknown` bucket)
119
+ - **Cline**: `~/.cline/data/sessions/` and VS Code `globalStorage/saoudrizwan.claude-dev/tasks/` — SDK message files with per-message metrics, legacy task conversations with usage from `ui_messages.json`
120
+ - **Gemini CLI**: `~/.gemini/tmp/*/chats/session-*.jsonl` — records with `toolCalls` (args, results, status) and per-message token counts; `$set`/`$patch`/`$rewindTo` update records applied by id
121
+ - **Copilot CLI** (incl. Desktop-bundled sessions): `~/.copilot/session-state/*/events.jsonl` — the event log: prompts, `assistant.message` with `toolRequests`, tool results, `session.usage_record` usage, system prompt
122
+ - **Aider**: explicit paths only (`--aider .aider.chat.history.md`) — histories live per-project. Task-level evidence: prompts, assistant text, tool output as blockquotes; no structured tool calls or usage, and traces are marked accordingly
123
+ - **Devin** (cloud): explicit opt-in (`--devin`, needs `DEVIN_API_KEY` + `DEVIN_ORG_ID` in the environment) via the official v3 API — task-level metadata per session (prompt, status, pull requests, ACU consumption; ACUs are compute units and stay out of token totals). Message-level transcripts are not exposed by the API, so these traces support workflow discovery, not replay
124
+ - **Windsurf**: not supported — no publicly documented chat-store format (it is mid-migration to Devin per community research); will follow once a format is public
125
+
126
+ Everything downstream — workflow map, replay cases with tool fixtures, migration report — works the same on these as on any other source. `--agent-limit` caps how many session files are read (newest first, default 200).
127
+
128
+ ## If your workflow already uses business tools (Supermemory, internal APIs, …)
129
+
130
+ Their calls are treated as first-class evidence at every stage, and a chained replay can complete the workflow offline:
131
+
132
+ 1. **Import** — the tool calls are already in your traces; import captures them, and the workflow map shows which workflows depend on which tools.
133
+ 2. **Cases** — each case carries `tool_fixtures`: what the tool actually returned in history, extracted automatically. Edit them in `cases.json` if needed.
134
+ 3. **Replay with `--chain`** — when the target proposes a tool call, the recorded result is fed back and the model continues, so success checks evaluate the workflow's **final answer**, not just the first proposal. If the target invents a tool history never used, it gets an explicit placeholder result and the gap is reported.
135
+ 4. **The line that never moves** — the harness never executes a real business tool. No reads against your live Supermemory, no writes to your data. Live read-only fixtures against an authorized environment are a possible future opt-in, separate from the default offline path.
136
+
137
+ The same mechanism covers every business tool, not just memory services — Supermemory, Stripe, internal CRUD APIs — because the fixture layer is tool-agnostic by design.
138
+
139
+ ## Any agent can drive it (MCP)
140
+
141
+ The harness ships a built-in MCP server, so any MCP-capable agent — Claude Code, Codex, OpenCode, Cursor, or your own — can run the whole pipeline as native tools instead of shelling out:
142
+
143
+ ```sh
144
+ switchit-mcp # stdio MCP server; register it in your client as:
145
+ ```
146
+
147
+ ```json
148
+ { "switchit": { "command": "switchit-mcp", "args": [] } }
149
+ ```
150
+
151
+ Exposed tools: `switchit_import`, `switchit_profile`, `switchit_map`, `switchit_cases`, `switchit_replay`, `switchit_report`, `switchit_run`, `switchit_status`, `switchit_read_report`, `switchit_list_providers`. The safety model carries over unchanged: everything is offline until the agent explicitly passes `remote: true` with a live target, and keys still come from the environment — an agent cannot talk a key out of you through a tool argument. The `$switchit` skill and the CLI remain equivalent entry points; use whichever your agent speaks.
152
+
153
+ ## Tests
154
+
155
+ ```sh
156
+ python3 -m unittest discover -s tests -p "test_*.py" -t .
157
+ ```
158
+
159
+ All tests are offline and use only synthetic data: connector shapes, redaction, usage reconciliation ("every call counted exactly once"), grouping behavior, verdict logic, checkpoint/resume, fingerprint refusal, report contents, and the no-secrets guarantee.
160
+
161
+ ## Publishing
162
+
163
+ ```sh
164
+ python3 -m pip install build twine
165
+ python3 -m build # sdist + wheel into dist/
166
+ python3 -m twine check dist/* # metadata + README rendering
167
+ python3 -m twine upload dist/* # to PyPI (configure credentials first)
168
+ ```
169
+
170
+ Cut a release by bumping `version` in `pyproject.toml` and adding a `CHANGELOG.md` entry.
171
+
172
+ ## Code layout
173
+
174
+ ```text
175
+ switchit/
176
+ core.py import, normalize, redact, workflow map, replay selection
177
+ providers.py provider adapters and capability descriptions
178
+ runner.py replay, compare, report, checkpoints
179
+ cli.py import → map → cases → replay → report; one-command run
180
+ demo_data.py bundled synthetic dataset for --demo
181
+ tests/ offline end-to-end and connector-shape checks
182
+ examples/ synthetic traces and offline provider config
183
+ skills/switchit/ SKILL.md: guide the agent through evidence and migration decisions
184
+ ```
185
+
186
+ ## Boundaries
187
+
188
+ Workflow labels and similarity scores are triage aids, not measured accuracy. For a workflow that needs a real tool to complete, a single-call replay can verify the proposed tool request but must leave the end-to-end outcome unverified until a safe tool fixture or authorized test environment exists. The Hyde assessment dataset and results are not inputs to this project.
@@ -0,0 +1,155 @@
1
+ # SwitchIt!
2
+
3
+ SwitchIt! helps teams move AI workflows from one provider to another with evidence that the important behavior survives the move.
4
+
5
+ The harness ingests authorized traces and application configuration, maps the workflows people actually use, selects representative replay cases, runs them against a target provider, and compares task outcomes, tool behavior, latency, and token usage. It produces a migration report with failures, uncertainties, and concrete changes needed.
6
+
7
+ The companion skill guides an agent through reviewing the evidence, resolving ambiguous workflows, and preparing a migration plan. The harness performs the reproducible imports, replays, comparisons, and checks. Use `$switchit` from any project to ask for a provider migration plan or a verified switch; see the [skill](skills/switchit/SKILL.md), the [system map](docs/system-map.svg), and the [migration run](docs/migration-run.svg).
8
+
9
+ First milestone — shipped in `switchit/`: JSON/JSONL, OTLP, Langfuse-style, and Parquet importers; one recorded baseline adapter; mock and live (OpenAI-compatible, Anthropic, Bedrock Converse) target adapters; and a complete offline replay loop with JSON + HTML reports on synthetic traces.
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ pip install switchit-harness # from PyPI, once published
15
+ # or from this repository:
16
+ pip install .
17
+
18
+ switchit --version
19
+ python3 -m switchit.cli --version # same thing without the entry point
20
+ ```
21
+
22
+ The core is stdlib-only. Add extras only if you need them: `pip install 'switchit-harness[parquet]'` for Parquet imports, `'switchit-harness[bedrock]'` for the Bedrock adapter.
23
+
24
+ To install the companion `$switchit` agent skill for tools that read `~/.agents/skills`:
25
+
26
+ ```sh
27
+ ./scripts/install-skill.sh
28
+ ```
29
+
30
+ ## Quick start (fully offline, no credentials)
31
+
32
+ ```sh
33
+ # One command on the bundled synthetic demo dataset:
34
+ python3 -m switchit.cli run --demo --state-dir /tmp/switchit-demo
35
+ open /tmp/switchit-demo/run/report.html
36
+
37
+ # Or step by step on the files in examples/:
38
+ python3 -m switchit.cli import --jsonl examples/traces.jsonl --app-config examples/app_config.json --state-dir .switchit
39
+ python3 -m switchit.cli map --state-dir .switchit # provisional workflow map; edit workflows.json to correct it
40
+ python3 -m switchit.cli map --keep-edits --state-dir .switchit # re-runs keep your edits
41
+ python3 -m switchit.cli cases --state-dir .switchit # replay set; edit cases.json to add real success checks
42
+ python3 -m switchit.cli replay --state-dir .switchit # recorded baseline vs mock target, checkpointed
43
+ python3 -m switchit.cli report --state-dir .switchit # report.json + report.html
44
+ ```
45
+
46
+ ## What each stage produces
47
+
48
+ | Stage | Artifact | Notes |
49
+ |---|---|---|
50
+ | `import` | `<state-dir>/store.json` | Canonical sessions, traces, calls. Secrets redacted at import — redacted content is the only content stored, replayed, or reported. Usage provenance kept separate: `recorded` / `estimated` / `unknown`. Sources: your exports **and** coding-agent session folders you already have (`--agents` reads Codex, Claude Code, and OpenCode locally). |
51
+ | `profile` | `profile.json` + `app_config.inferred.json` | Digs through the sessions: system prompts, tool inventory with schemas inferred from observed calls, provider/model mix, error samples. The inferred app config is a ready-to-edit starting point. |
52
+ | `map` | `workflows.json` | TF-IDF + tool-overlap grouping with confidence and uncertainty flags. Labels are triage aids; set `"edited": true` and fix names/members to correct them. |
53
+ | `cases` | `cases.json` | One case per selected trace covering common, costly, risky, and failed workflows, with default checks. Edit to add explicit success checks — a historical model response alone is not proof of success. |
54
+ | `replay` | `run/results.json` + `run/run_state.json` | Same cases through baseline and target adapters. Tool proposals are captured, never executed. Checkpointed after every case; a fingerprint refuses to resume after cases, adapters, or runner code changed. |
55
+ | `report` | `run/report.json` + `run/report.html` | Verdicts (pass / fail / error / uncertain), failure groups, capability gaps, prioritized fixes, usage by provenance. Local, self-contained HTML. |
56
+
57
+ ## Connectors
58
+
59
+ - **Inputs:** OpenTelemetry/OTLP JSON (`--otlp`), JSON/JSONL (`--jsonl`), Langfuse-style exports (`--langfuse`), and Parquet / ZIP-of-`traces.parquet` (`--parquet`, needs the optional `pyarrow` package). A simple app-configuration JSON (`--app-config`) supplies prompts and tool definitions.
60
+ - **Providers:** recorded baseline and mock adapters for offline work; OpenAI-compatible HTTP, Anthropic Messages, and Amazon Bedrock Converse for live tests. Provider presets fill in the details: `--target grok` (xAI), `groq`, `deepseek`, `mistral`, `openrouter`, `together`, `fireworks`, `ollama` (free, fully local), `vllm` (local). Meta Llama runs through `ollama`/`vllm`/`together`/`fireworks`/`bedrock`.
61
+ - **Secrets:** environment variables only — `OPENAI_API_KEY`, `XAI_API_KEY`, `GROQ_API_KEY`, `ANTHROPIC_API_KEY`, the standard AWS chain, and so on per provider. Keys are never accepted on the command line or written to files. Local import and analysis do not contact a provider.
62
+ - **Memory services:** products like Supermemory are business tools your agent calls, not chat-completion providers — so they are captured as tool proposals during replay, never executed, and are not replay targets.
63
+
64
+ ## Live replay is an explicit opt-in
65
+
66
+ ```sh
67
+ export OPENAI_API_KEY='...'
68
+ python3 -m switchit.cli replay --target openai --target-model gpt-4o-mini --remote --state-dir .switchit
69
+ ```
70
+
71
+ Without `--remote`, live targets refuse to run. With it, the redacted case requests are sent to the target provider and billed accordingly; usage is recorded from provider responses, and requests that fail before a response keep their consumption counted separately as unknown.
72
+
73
+ ## Traces you already have: coding agents
74
+
75
+ Most developers already have rich agent traces on disk without ever instrumenting anything. SwitchIt reads them directly, with the same redaction and provenance rules as every other source:
76
+
77
+ ```sh
78
+ switchit import --agents # Codex, Claude Code, OpenCode session folders
79
+ switchit profile --state-dir .switchit # prompts, tool schemas, provider mix — dug out automatically
80
+ ```
81
+
82
+ - **Codex**: `~/.codex/sessions/**/*.jsonl` — model calls, `function_call`s and outputs, token counts
83
+ - **Claude Code**: `~/.claude/projects/**/*.jsonl` — transcripts with `tool_use` blocks and per-message usage
84
+ - **OpenCode**: `~/.local/share/opencode/opencode.db` — message/part tables (read-only SQLite)
85
+ - **Cursor**: `~/.cursor/chats/*/*/store.db` — chat messages per workspace, system prompts, agentic tool calls (Cursor reports no usage, so those calls land in the `unknown` bucket)
86
+ - **Cline**: `~/.cline/data/sessions/` and VS Code `globalStorage/saoudrizwan.claude-dev/tasks/` — SDK message files with per-message metrics, legacy task conversations with usage from `ui_messages.json`
87
+ - **Gemini CLI**: `~/.gemini/tmp/*/chats/session-*.jsonl` — records with `toolCalls` (args, results, status) and per-message token counts; `$set`/`$patch`/`$rewindTo` update records applied by id
88
+ - **Copilot CLI** (incl. Desktop-bundled sessions): `~/.copilot/session-state/*/events.jsonl` — the event log: prompts, `assistant.message` with `toolRequests`, tool results, `session.usage_record` usage, system prompt
89
+ - **Aider**: explicit paths only (`--aider .aider.chat.history.md`) — histories live per-project. Task-level evidence: prompts, assistant text, tool output as blockquotes; no structured tool calls or usage, and traces are marked accordingly
90
+ - **Devin** (cloud): explicit opt-in (`--devin`, needs `DEVIN_API_KEY` + `DEVIN_ORG_ID` in the environment) via the official v3 API — task-level metadata per session (prompt, status, pull requests, ACU consumption; ACUs are compute units and stay out of token totals). Message-level transcripts are not exposed by the API, so these traces support workflow discovery, not replay
91
+ - **Windsurf**: not supported — no publicly documented chat-store format (it is mid-migration to Devin per community research); will follow once a format is public
92
+
93
+ Everything downstream — workflow map, replay cases with tool fixtures, migration report — works the same on these as on any other source. `--agent-limit` caps how many session files are read (newest first, default 200).
94
+
95
+ ## If your workflow already uses business tools (Supermemory, internal APIs, …)
96
+
97
+ Their calls are treated as first-class evidence at every stage, and a chained replay can complete the workflow offline:
98
+
99
+ 1. **Import** — the tool calls are already in your traces; import captures them, and the workflow map shows which workflows depend on which tools.
100
+ 2. **Cases** — each case carries `tool_fixtures`: what the tool actually returned in history, extracted automatically. Edit them in `cases.json` if needed.
101
+ 3. **Replay with `--chain`** — when the target proposes a tool call, the recorded result is fed back and the model continues, so success checks evaluate the workflow's **final answer**, not just the first proposal. If the target invents a tool history never used, it gets an explicit placeholder result and the gap is reported.
102
+ 4. **The line that never moves** — the harness never executes a real business tool. No reads against your live Supermemory, no writes to your data. Live read-only fixtures against an authorized environment are a possible future opt-in, separate from the default offline path.
103
+
104
+ The same mechanism covers every business tool, not just memory services — Supermemory, Stripe, internal CRUD APIs — because the fixture layer is tool-agnostic by design.
105
+
106
+ ## Any agent can drive it (MCP)
107
+
108
+ The harness ships a built-in MCP server, so any MCP-capable agent — Claude Code, Codex, OpenCode, Cursor, or your own — can run the whole pipeline as native tools instead of shelling out:
109
+
110
+ ```sh
111
+ switchit-mcp # stdio MCP server; register it in your client as:
112
+ ```
113
+
114
+ ```json
115
+ { "switchit": { "command": "switchit-mcp", "args": [] } }
116
+ ```
117
+
118
+ Exposed tools: `switchit_import`, `switchit_profile`, `switchit_map`, `switchit_cases`, `switchit_replay`, `switchit_report`, `switchit_run`, `switchit_status`, `switchit_read_report`, `switchit_list_providers`. The safety model carries over unchanged: everything is offline until the agent explicitly passes `remote: true` with a live target, and keys still come from the environment — an agent cannot talk a key out of you through a tool argument. The `$switchit` skill and the CLI remain equivalent entry points; use whichever your agent speaks.
119
+
120
+ ## Tests
121
+
122
+ ```sh
123
+ python3 -m unittest discover -s tests -p "test_*.py" -t .
124
+ ```
125
+
126
+ All tests are offline and use only synthetic data: connector shapes, redaction, usage reconciliation ("every call counted exactly once"), grouping behavior, verdict logic, checkpoint/resume, fingerprint refusal, report contents, and the no-secrets guarantee.
127
+
128
+ ## Publishing
129
+
130
+ ```sh
131
+ python3 -m pip install build twine
132
+ python3 -m build # sdist + wheel into dist/
133
+ python3 -m twine check dist/* # metadata + README rendering
134
+ python3 -m twine upload dist/* # to PyPI (configure credentials first)
135
+ ```
136
+
137
+ Cut a release by bumping `version` in `pyproject.toml` and adding a `CHANGELOG.md` entry.
138
+
139
+ ## Code layout
140
+
141
+ ```text
142
+ switchit/
143
+ core.py import, normalize, redact, workflow map, replay selection
144
+ providers.py provider adapters and capability descriptions
145
+ runner.py replay, compare, report, checkpoints
146
+ cli.py import → map → cases → replay → report; one-command run
147
+ demo_data.py bundled synthetic dataset for --demo
148
+ tests/ offline end-to-end and connector-shape checks
149
+ examples/ synthetic traces and offline provider config
150
+ skills/switchit/ SKILL.md: guide the agent through evidence and migration decisions
151
+ ```
152
+
153
+ ## Boundaries
154
+
155
+ Workflow labels and similarity scores are triage aids, not measured accuracy. For a workflow that needs a real tool to complete, a single-call replay can verify the proposed tool request but must leave the end-to-end outcome unverified until a safe tool fixture or authorized test environment exists. The Hyde assessment dataset and results are not inputs to this project.
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "switchit-harness"
7
+ version = "0.1.0"
8
+ description = "Evidence-based migration of AI workflows between providers: import traces, replay them through adapters, and report what survives the switch."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "SwitchIt! contributors" }]
13
+ keywords = [
14
+ "ai", "llm", "migration", "evaluation", "traces", "otel",
15
+ "openai", "anthropic", "bedrock", "agents", "replay", "mcp",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Environment :: Console",
20
+ "Intended Audience :: Developers",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Software Development :: Quality Assurance",
29
+ "Topic :: Software Development :: Testing",
30
+ ]
31
+ # The core is stdlib-only by design: local import, mapping, and offline replay
32
+ # never need a third-party package or a network call.
33
+ dependencies = []
34
+
35
+ [project.optional-dependencies]
36
+ parquet = ["pyarrow>=14"]
37
+ bedrock = ["boto3>=1.34"]
38
+ all = ["pyarrow>=14", "boto3>=1.34"]
39
+ dev = ["pyarrow>=14"]
40
+
41
+ [project.scripts]
42
+ switchit = "switchit.cli:main"
43
+ switchit-mcp = "switchit.mcp_server:main"
44
+
45
+ [tool.setuptools]
46
+ packages = ["switchit"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,21 @@
1
+ """SwitchIt! — evidence-based migration of AI workflows between providers.
2
+
3
+ The harness imports authorized traces, normalizes them into a canonical
4
+ store, maps provisional workflows, selects replay cases, replays them
5
+ through recorded/offline or live provider adapters, and produces a local
6
+ JSON + HTML migration report.
7
+
8
+ Boundaries kept honest throughout:
9
+ - Workflow labels and similarity scores are triage aids, not measured accuracy.
10
+ - Proposed tool calls are captured, never executed.
11
+ - A historical model response is reference behavior, not proof of success.
12
+ - Token provenance stays separated: recorded, estimated, unknown.
13
+ """
14
+
15
+ __version__ = "0.1.0"
16
+
17
+ USAGE_BASES = ("recorded", "estimated", "unknown")
18
+
19
+ from . import core, providers, runner # noqa: E402,F401
20
+
21
+ __all__ = ["__version__", "core", "providers", "runner", "USAGE_BASES"]
@@ -0,0 +1,8 @@
1
+ """Allow ``python -m switchit`` as a shorthand for ``python -m switchit.cli``."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())