# Assess and replay a Hume migration

These standalone tools use Python 3.10+ and its standard library on macOS or Linux. No repository checkout or package installation is needed. Start with the offline examples below; neither command submits audio or needs an API key.

Reviewed October 3, 2026. [Hume's published notice](https://dev.hume.ai/intro) gives the EVI/TTS cutoff as **November 13, 2026 at 05:01 UTC**, or **November 12 at 9:01 p.m. PST**. Current Hume Tagger/Prosody products need separate qualification. Oruk does not provide an EVI-compatible conversation service, TTS, cloned-voice portability, or interchangeable Hume scores. See the [migration hub](https://oruk.ai/hume-migration) and [EVI migration guide](https://oruk.ai/guides/hume-evi-migration).

## 1. Save the five downloads

Create a working folder under a physical, non-symlinked path:

```sh
umask 077
mkdir -p hume-migration-tools/public/samples/conversations
cd hume-migration-tools
```

Save each download at the path in the second column, relative to this folder. The nested WAV path is intentional: it matches the batch manifest exactly.

| Download | Save as |
| --- | --- |
| [Assessment script](https://oruk.ai/examples/hume-migration-assess.py) | `hume-migration-assess.py` |
| [Example assessment requirements](https://oruk.ai/examples/hume-migration-manifest.example.json) | `hume-migration-manifest.example.json` |
| [Batch replay script](https://oruk.ai/examples/hume-batch-replay.py) | `hume-batch-replay.py` |
| [Example batch manifest](https://oruk.ai/examples/hume-batch-manifest.example.json) | `hume-batch-manifest.example.json` |
| [Public demonstration WAV](https://oruk.ai/samples/conversations/03-scooter-charge.wav) | `public/samples/conversations/03-scooter-charge.wav` |

The WAV is a public demonstration, not customer migration evidence. The requirements example is synthetic. Neither establishes production compatibility or expression accuracy.

## 2. Run the assessment offline

<!-- offline-command: assessment -->
```sh
python3 hume-migration-assess.py \
  --requirements hume-migration-manifest.example.json \
  --output assessment.json
```

This creates a private local `assessment.json` with candidate routes, blockers, unknowns, and an export checklist. It does not contact Hume or Oruk, execute customer code, inspect audio, verify active usage, or perform exports. Existing output files are never overwritten; choose a new output name for another run.

For your integration, copy and edit the requirements JSON to declare your actual features, languages, and audio limits. Add `--source path/to/client.py` for explicitly selected UTF-8 source/configuration files and `--archive path/to/saved-response.json` for saved response envelopes; both flags are repeatable. Select at most 16 files, each at most 2 MiB and 8 MiB in total. No directories are crawled. Reports omit source text, paths, credentials, transcripts, labels, and scores. Lexical findings can come from comments or examples and require human review.

## 3. Preflight the recording offline

<!-- offline-command: replay-preflight -->
```sh
python3 hume-batch-replay.py \
  hume-batch-manifest.example.json --audio-root .
```

The expected result is `valid: true`, one request, 25.25 audio seconds, 808044 input bytes, and an unknown monetary estimate. Preflight checks the original WAV's SHA-256, byte count and sample frames. It prints an immutable manifest digest and creates no ledger or network request. Any invalid file blocks the whole batch.

Supported replay routes:

| Model | HTTP endpoint |
| --- | --- |
| `oruk-spectra-2` | `POST https://speech-api.oruk.ai/v1/audio/analysis` or `/v1/audio/transcriptions` |
| Original `oruk-resonance` | `POST https://speech-api.oruk.ai/v1/audio/analysis`, `/v1/audio/affect`, `/v1/audio/emotions`, or `/v1/audio/styles` |

All recordings must already be **mono 16 kHz PCM16 RIFF WAV**, 45 milliseconds through 60 seconds, at most 4 MiB each. The tool preserves every audio byte and does not crop, split, transcode, resample, or infer missing scores. Spectra-2 returns clip scores; original Resonance provides its own timed segments. This replay tool excludes Resonance-2, streaming, EVI, TTS, diarization flags, language overrides, and other optional flags. Current model contracts are in [Oruk's API documentation](https://oruk.ai/docs).

Limits are 500 explicit recordings, 256 MiB total audio, 4 concurrent requests (default 1), 4 MiB per response, and a 1–300 second socket timeout (default 120). A socket timeout bounds each blocking operation, not total wall time. Files and parent directories cannot be symlinks. Duplicate audio hashes, traversal paths, unknown fields, duplicate JSON keys, nonfinite numbers, and excessive JSON structure are rejected.

## 4. Execute only after reviewing a real batch

**Execution sends the listed audio to Oruk and may incur charges.** Use only recordings you are authorized to submit. The tools do not export a Hume account. Preserve originals, exports, permissions, and any transformation provenance separately.

Copy the batch example to `batch.json`. Give your batch a new UUID once, choose a non-secret account alias, and list each intended recording with its relative path, SHA-256, byte count, and frame count. Keep that batch UUID fixed afterward. Set `pricing.declared_usd_per_minute` to the decimal-string rate applicable to your account, or leave it `null`; describe the source in `pricing.source`. Preflight the new manifest before execution.

The estimate applies a one-second minimum; it is not an invoice or a spend cap. Allowances, credits, taxes, and account terms may differ. Unknown pricing requires the additional explicit flag `--acknowledge-unpriced` when executing.

Load your key into the `ORUK_API_KEY` environment variable through your shell or secret manager. Never place it in a command argument, manifest, or evidence reference. Replace `EXACT_PREFLIGHT_SHA256` below with the digest printed for **your `batch.json`**:

```sh
python3 hume-batch-replay.py batch.json \
  --audio-root . --state-dir batch-state \
  --confirm-manifest EXACT_PREFLIGHT_SHA256 \
  --execute --concurrency 1
```

The normal target is fixed to `https://speech-api.oruk.ai`; manifest URLs cannot change it. The private state directory uses mode 0700 and files use mode 0600. **Saved responses can contain transcripts and scores.** Apply your approved storage and retention policy to the entire directory. Do not share it as a public issue attachment.

## Resume and reconcile safely

Keep the manifest, recordings, account context, and state directory together. Run the same execution command to resume: only never-attempted `pending` entries are sent. There are **zero automatic retries**, including for 429 responses. Stable request IDs and payload hashes, an exclusive process lock, and atomic ledger writes prevent accidental redispatch within the retained ledger. Changed inputs or completed results fail closed.

A timeout, disconnect, truncated response, contract mismatch, 409, or 5xx can leave a billed request without a usable response. Such entries remain `uncertain`; ordinary 4xx entries are `rejected`. Neither is automatically resent. Ctrl+C stops queued work, but already dispatched requests may finish and be charged. Do not delete the ledger, reset an attempted entry, or invent a new batch UUID to bypass uncertainty.

Check the request ID in [Oruk Usage](https://oruk.ai/account/usage) or contact [the Oruk team](mailto:access@oruk.ai). A lost response is not recoverable through this tool. After manual reconciliation, record an attestation without sending audio:

```sh
python3 hume-batch-replay.py batch.json \
  --audio-root . --state-dir batch-state \
  --confirm-manifest EXACT_PREFLIGHT_SHA256 \
  --resolve-item YOUR_ITEM_ID --resolution completed \
  --evidence-reference support-ticket-1234 \
  --acknowledge-manual-reconciliation
```

Use `--resolution abandoned` to close an unresolved item without retransmission. Neither resolution verifies the server independently or recovers a result; an abandoned item may still have been billed. Keep evidence references free of credentials and personal data.

Replay exit codes: **0** means a valid offline preflight or all entries completed/reconciled/abandoned; **2** means an input, state, lock, or acknowledgement error; **3** means unresolved per-file outcomes. Inspect each status: abandoned does not mean successfully migrated. Assessment exits **0** after writing its report and **1** on an input/output failure; invalid CLI arguments exit **2**.
