rahcp SDK
Async Python SDK & CLI for the Hitachi Content Platform (HCP) Unified API — S3
object storage, IIIF image downloads, and Transkribus exports, with resumable
parallel bulk transfers.
Install — one package
rahcp bundles everything; there are no separate rahcp-* packages. Heavy deps
are extras.
pip install rahcp # client, CLI, IIIF, Transkribus, tracker
pip install "rahcp[validate]" # image validation (Pillow)
pip install "rahcp[etl]" # NATS JetStream (rahcp_etl)
pip install "rahcp[alto]" # Transkribus PAGE->ALTO (ocrd)
pip install "rahcp[postgres]" # Postgres tracker backend
pip install "rahcp[all]" # everything
Import names are stable: from rahcp_client import HCPClient,
from rahcp_iiif import download_batch, from rahcp_transkribus import export_collection.
Mental model — read before writing code
- Presigned URLs, not proxying. Every transfer is
POST /presign → signed URL
→ direct PUT/GET to HCP S3; data never flows through the API server. Files
≥ 100 MB use multipart automatically.
- Everything is resumable. All bulk ops take a
tracker; completed keys are
skipped instantly on re-run. Persist the tracker DB across runs.
- HCP has no overwrite-in-place. A PUT over an existing key returns
409;
ConflictPolicy.overwrite and --check-updates delete-then-PUT. moto and the
mock server allow PUT-overwrite, so they do NOT reproduce the 409 — test
overwrite against real HCP.
Quickstart
import asyncio
from pathlib import Path
from rahcp import HCPClient # reads HCP_ENDPOINT / HCP_USERNAME / HCP_PASSWORD / HCP_TENANT
async def main():
async with HCPClient.from_env() as client:
await client.s3.upload("my-bucket", "data/file.jpg", Path("file.jpg"))
print(await client.s3.list_objects("my-bucket", prefix="data/"))
asyncio.run(main())
rahcp s3 upload-all my-bucket ./scans --workers 20 --include '*.jpg' --validate
CLI config gotcha — the top cause of AuthenticationError
Config lives at ~/.rahcp/config.yaml. For a project-local config you MUST pass
--config or every command 401s (it silently reads the default path):
rahcp --config .rahcp/config.yaml s3 ls
Task references
| Task |
Reference |
| S3 upload/download, list/copy/delete, presign, staging, conflict policy |
references/s3.md |
IIIF image downloads + query_params + IIIF→HCP |
references/iiif.md |
Transkribus export/upload, scheduled sync, --check-updates |
references/transkribus.md |
| Tracker API, namespaces, auth, validation, errors, full config |
references/reference.md |
| Debug logs, perf tuning, long transfers, tracker inspection |
references/troubleshooting.md |
1---2name: hcp-sdk3description: Build workflows with the rahcp Python SDK & CLI: upload/download HCP S3 objects, bulk transfers, IIIF image downloads, Transkribus exports, transfer tracking, namespace admin. Triggers: rahcp, HCP, IIIF, Transkribus, presigned URL, bulk upload, bulk download, transfer tracker, S3 objects.4---56# rahcp SDK78Async Python SDK & CLI for the Hitachi Content Platform (HCP) Unified API — S39object storage, IIIF image downloads, and Transkribus exports, with resumable10parallel bulk transfers.1112## Install — one package1314`rahcp` bundles everything; there are no separate `rahcp-*` packages. Heavy deps15are extras.1617```bash18pip install rahcp # client, CLI, IIIF, Transkribus, tracker19pip install "rahcp[validate]" # image validation (Pillow)20pip install "rahcp[etl]" # NATS JetStream (rahcp_etl)21pip install "rahcp[alto]" # Transkribus PAGE->ALTO (ocrd)22pip install "rahcp[postgres]" # Postgres tracker backend23pip install "rahcp[all]" # everything24```2526Import names are stable: `from rahcp_client import HCPClient`,27`from rahcp_iiif import download_batch`, `from rahcp_transkribus import export_collection`.2829## Mental model — read before writing code3031- **Presigned URLs, not proxying.** Every transfer is `POST /presign` → signed URL32 → direct PUT/GET to HCP S3; data never flows through the API server. Files33 ≥ 100 MB use multipart automatically.34- **Everything is resumable.** All bulk ops take a `tracker`; completed keys are35 skipped instantly on re-run. Persist the tracker DB across runs.36- **HCP has no overwrite-in-place.** A PUT over an existing key returns `409`;37 `ConflictPolicy.overwrite` and `--check-updates` delete-then-PUT. moto and the38 mock server allow PUT-overwrite, so they do NOT reproduce the 409 — test39 overwrite against real HCP.4041## Quickstart4243```python44import asyncio45from pathlib import Path46from rahcp import HCPClient # reads HCP_ENDPOINT / HCP_USERNAME / HCP_PASSWORD / HCP_TENANT4748async def main():49 async with HCPClient.from_env() as client:50 await client.s3.upload("my-bucket", "data/file.jpg", Path("file.jpg"))51 print(await client.s3.list_objects("my-bucket", prefix="data/"))5253asyncio.run(main())54```5556```bash57rahcp s3 upload-all my-bucket ./scans --workers 20 --include '*.jpg' --validate58```5960## CLI config gotcha — the top cause of AuthenticationError6162Config lives at `~/.rahcp/config.yaml`. For a project-local config you MUST pass63`--config` or every command 401s (it silently reads the default path):6465```bash66rahcp --config .rahcp/config.yaml s3 ls67```6869## Task references7071| Task | Reference |72|------|-----------|73| S3 upload/download, list/copy/delete, presign, staging, conflict policy | [references/s3.md](references/s3.md) |74| IIIF image downloads + `query_params` + IIIF→HCP | [references/iiif.md](references/iiif.md) |75| Transkribus export/upload, scheduled sync, `--check-updates` | [references/transkribus.md](references/transkribus.md) |76| Tracker API, namespaces, auth, validation, errors, full config | [references/reference.md](references/reference.md) |77| Debug logs, perf tuning, long transfers, tracker inspection | [references/troubleshooting.md](references/troubleshooting.md) |