hypabolic-trajectory
Normalize coding-agent session transcripts into deterministic, versioned Trajectory contracts. Independent native Python 3.11+ runtime of the Hypabolic Trajectory product — same wire contracts and shared conformance suite as .NET, TypeScript, and Rust. No FFI to other language runtimes.
| PyPI name | hypabolic-trajectory (org Hypabolic) |
| Import root | hypabolic_trajectory |
| Requires-Python | >=3.11 |
| Normalizer contract | 0.2.0 (identity-stable; embedded in canonical output) |
| Wire package version | WIRE_PACKAGE_VERSION — tip pin "0.1.0" (must match peer runtimes + goldens on the same tag; not auto-bound to package SemVer) |
| License | MIT |
Published vs tree: NuGet / npm / crates
0.1.0already ship without AHP. The first public PyPI cut of this package ships on the next synchronized multi-registry tag (with tip sources including AHP Shape A). Until that tag, install from this monorepo (editable) or wait for the tag.
Package map
| Dist / extra | Import | Role |
|---|---|---|
hypabolic-trajectory (core wheel) |
hypabolic_trajectory |
Normalize, project (including pure project_otel_genai), listing, bundled contracts + runtime-capabilities.json, core streaming apply APIs, and hypabolic_trajectory.otel (SpanSetSink / emit_to, no SDK) |
hypabolic-trajectory[otel] |
same hypabolic_trajectory.otel |
Optional OpenTelemetry SDK sink helpers + opentelemetry-* deps only. Does not gate pure projection or emit_to with a pure sink. |
hypabolic-trajectory[io] |
hypabolic_trajectory.io |
Optional file poll/follow stream I/O (stream-file-io; stdlib only). Modules ship in the core wheel; extra marks install intent. |
hypabolic-trajectory[ahp] |
hypabolic_trajectory.ahp_client |
Optional AHP live-host client (stream-ahp-client; stdlib only; auth via callback). |
hypabolic-trajectory[hermes] |
hypabolic_trajectory.hermes_provider |
Optional Hermes SQLite/provider stream (stream-hermes-provider; stdlib sqlite3). Shared hermes-provider-* cases cover core apply_hermes_export; SQLite I/O is package-test-gated. |
| Conformance runner | not published | python/tools/trajectory_conformance — stdin/stdout protocol v1 for conformance/verify.py |
| Sample CLI | not published | python/samples/trajectory_cli — browse/list/show/stream/ahp-stream (no console script; monorepo sample only) |
Cross-ecosystem map (same product):
| Ecosystem | Core | Optional |
|---|---|---|
| .NET | Hypabolic.Trajectory |
.OpenTelemetry, .Testing, .IO, .Ahp, .Hermes |
| TypeScript | @hypabolic/trajectory |
@hypabolic/trajectory-node, @hypabolic/trajectory-otel, @hypabolic/trajectory-ahp, @hypabolic/trajectory-hermes |
| Rust | hypabolic-trajectory |
hypabolic-trajectory-opentelemetry, -io, -ahp, -hermes |
| Python | hypabolic-trajectory |
[otel], [io], [ahp], [hermes] |
Install
# After first public tag (replace with the tag SemVer):
pip install hypabolic-trajectory==<tag-semver>
pip install 'hypabolic-trajectory[otel]==<tag-semver>' # optional SDK sinks
pip install 'hypabolic-trajectory[io]==<tag-semver>' # stream file I/O intent
pip install 'hypabolic-trajectory[ahp]==<tag-semver>' # AHP client intent
pip install 'hypabolic-trajectory[hermes]==<tag-semver>' # Hermes provider intent
# From this monorepo (development):
python -m pip install -e './python[dev]'
# Stream extras (optional install intent; modules already in the src tree):
python -m pip install -e './python[io,ahp,hermes,dev]'
The published wheel has no console scripts. The conformance runner and sample
CLI (stream / ahp-stream included) are monorepo-only unpublished samples.
Sample CLI (unpublished)
# After editable install of the core package:
PYTHONPATH=python/samples python -m trajectory_cli list --source pi
PYTHONPATH=python/samples python -m trajectory_cli show \
--source pi \
--path conformance/cases/pi/tool-calls/input.jsonl
PYTHONPATH=python/samples python -m trajectory_cli browse
PYTHONPATH=python/samples python -m trajectory_cli stream \
--source pi \
--path conformance/cases/pi/tool-calls/input.jsonl \
--max-updates 1
See samples/trajectory_cli/README.md.
Supported public imports (semver-stable)
Only these paths are supported:
- Package root
hypabolic_trajectory— names in root__all__ hypabolic_trajectory.ir— multi-project IR surface (ir.__all__)hypabolic_trajectory.otel— always importable from the core wheelhypabolic_trajectory.io— optional file stream I/O ([io]extra intent)hypabolic_trajectory.ahp_client— optional AHP client ([ahp]extra intent)hypabolic_trajectory.hermes_provider— optional Hermes provider ([hermes]extra intent)
Any other module path (api, engine, normalize, sources, …) is
unsupported and may break without notice.
from hypabolic_trajectory import (
# free functions
normalize_to_ir,
normalize_to_letta,
normalize_to_canonical,
normalize_to_hypabolic,
project_letta,
project_canonical,
project_hypabolic,
project_openai,
project_minimal_jsonl,
project_otel_genai,
list_trajectories,
serialize_projection,
canonical_json,
# engine
TrajectoryEngine,
# request / errors
NormalizeRequest,
SourceContext,
NormalizeOptions,
Bounds,
Filters,
TrajectoryError,
Diagnostic,
TrajectorySource,
# versions
NORMALIZER_CONTRACT_VERSION, # "0.2.0"
WIRE_PACKAGE_VERSION, # tip "0.1.0" until coordinated bump
PACKAGE_VERSION,
__version__,
)
from hypabolic_trajectory.ir import TrajectoryIR # also re-exported at root
from hypabolic_trajectory.otel import SpanSetSink, emit_to
OTEL import matrix
| Import / call | Without opentelemetry-* |
With [otel] extra |
|---|---|---|
from hypabolic_trajectory import project_otel_genai |
Succeeds | Succeeds |
from hypabolic_trajectory.otel import SpanSetSink, emit_to |
Succeeds | Succeeds |
emit_to(pure_sink, ir) |
pure project + sink.emit; no SDK |
Same |
| Concrete SDK helper symbols (if shipped) | ImportError with install hint |
Succeeds when deps present |
Whole hypabolic_trajectory.otel package |
Always in the core wheel | Same |
Quick usage
from pathlib import Path
from hypabolic_trajectory import (
NormalizeRequest,
TrajectorySource,
list_trajectories,
normalize_to_ir,
project_hypabolic,
project_letta,
project_otel_genai,
serialize_projection,
TrajectoryEngine,
)
# Listing always takes an explicit root (no home default in library APIs).
page = list_trajectories(
source=TrajectorySource.CLAUDE_CODE,
root=Path.home() / ".claude" / "projects",
limit=20,
)
session = page.items[0]
transcript = Path(session.path).read_bytes()
request = NormalizeRequest(
source=TrajectorySource.CLAUDE_CODE,
transcript=transcript,
)
ir = normalize_to_ir(request)
hypabolic = project_hypabolic(ir)
messages = project_letta(ir)
spans = project_otel_genai(ir) # pure; no OTEL SDK required
# Product JSON emit (shared Trajectory string-escape; never stdlib json.dumps
# for identity/product schemas):
wire = serialize_projection(hypabolic)
# Engine (tip matrix including pure otel); free functions ignore engine mutations.
engine = TrajectoryEngine.create_default()
out = engine.project(ir, "hypabolic-trajectory-v1")
Filters (normalize options)
NormalizeOptions.filters controls content inclusion during normalization:
| Field | Values | Default | Effect |
|---|---|---|---|
filters.tool_results |
"include" | "omit" |
"include" |
When "omit", tool-result record bodies are dropped while structure/diagnostics remain policy-correct |
Bounds (options.bounds.tool_arguments / tool_results) cap argument/result
character lengths with documented truncation strategies. Domain validation of
options runs at free-function / engine entry (DTO construction does not raise
TrajectoryError).
from hypabolic_trajectory import (
Filters,
NormalizeOptions,
NormalizeRequest,
TrajectorySource,
normalize_to_ir,
)
request = NormalizeRequest(
source=TrajectorySource.PI,
transcript=b"...",
options=NormalizeOptions(filters=Filters(tool_results="omit")),
)
ir = normalize_to_ir(request)
Dual timestamps
Source adapters and the normalizer preserve dual timing when present (never fabricated):
| Clock | Field | Role |
|---|---|---|
| Millisecond | timestamp_ms (int) |
Filled / synthesized body clock used for public message, canonical, Hypabolic, and jsonl-minimal timestamps |
| Precise | timestamp_precise (str, optional) |
Source-native high-resolution string when present; copied onto IR records and model invocations |
Public timestamp formats (filled timestamp_ms only — never source_timestamp_ms):
| Surface | Format |
|---|---|
| Message / canonical / Hypabolic | yyyy-MM-ddTHH:mm:ss.fffZ |
Listing updated_at |
Z form |
jsonl-minimal |
yyyy-MM-ddTHH:mm:ss.fff+00:00 (three fractional digits; omit key when filled ms is absent) |
| OTEL span bounds | precise as-is; else ms → seven-digit pad (Z → 0000+00:00) |
Identity formulas and string escape
Authority: contracts/spec/identity.md, contracts/spec/canonical-json.md, and
peer goldens. Digests are 64 lowercase hex.
| Product field | Formula |
|---|---|
Hypabolic trajectory_id |
sha256(utf8(compact_json([source_wire_name, group_id]))) |
Model-invocation id |
sha256(utf8(compact_json([group_id, identity, "model-invocation"]))) |
| Model-invocation absolute offset | checked decoded.source_offset + base_byte_offset (signed int64; overflow → invalid_input) |
segment.partial |
config.partial or base_byte_offset != 0 |
Trajectory string-escape (shared by canonical_json, serialize_projection,
and each project_minimal_jsonl line):
- Walk the string as UTF-16 code units.
- Short escapes for
",\\,\b,\t,\n,\f,\r. \uXXXXfour uppercase hex forU+0000–001F,U+E000–F8FF,U+2028,U+2029, and surrogates; else UTF-8.- Do not escape solidus
/; no Unicode normalization; no BOM.
Only identity hashing sorts object keys by UTF-16 code unit order via
canonical_json. Product serialize_projection preserves insertion order.
Capabilities and sources
Advertised surface is the tip matrix in
python/runtime-capabilities.json (must equal
contracts/compatibility.json and peer TS/Rust manifests at ship):
- Sources:
pi,claude-code,codex,openclaw,hermes,ahp(Shape A offline ChatState snapshot; listing Phase 3 stub) - Outputs:
letta-trajectory-v1,letta-canonical-v1,hypabolic-trajectory-v1,openai-chat-messages,jsonl-minimal,otel-genai-spans-v1 - Capabilities:
normalize,normalize-partial,list-explicit-root,typed-diagnostics,typed-fatal-errors,deterministic-rerun - Slice:
ML13(historical id; AHP is a post-0.1.0source addition on tip)
Do not treat IMPLEMENTED_SOURCES as a registry claim — the capabilities
file is authoritative for CI and advertising.
Conformance (filtered runner argv)
Protocol v1 runner (unpublished): python/tools/trajectory_conformance.
# Editable install + unit tests
python -m pip install -e './python[dev]'
python -m pytest python/tests -q
# Tip suite (unfiltered verify defaults to compatibility tip set):
python conformance/verify.py --repository-root . -- \
env PYTHONPATH=python/src:python/tools python -m trajectory_conformance
# Progressive / filtered argv from claimed capabilities (fail-closed when ⊂ tip):
python conformance/verify.py --repository-root . \
$(python tools/conformance_argv_from_capabilities.py --repository-root .) \
-- \
env PYTHONPATH=python/src:python/tools python -m trajectory_conformance
# Manual filters while iterating:
python conformance/verify.py --repository-root . \
--source pi --operation normalize-letta --operation normalize-canonical -- \
env PYTHONPATH=python/src:python/tools python -m trajectory_conformance
When claimed sources/outputs are a proper subset of tip, CI must pass
explicit --source / --operation filters (generator: tools/conformance_argv_from_capabilities.py).
Never run unfiltered verify while claimed ⊂ tip.
Identity baseline:
sha256sum --check conformance/identity-baseline.sha256
Version pins
| Symbol / field | Value / rule |
|---|---|
NORMALIZER_CONTRACT_VERSION |
"0.2.0" — wire identity contract |
WIRE_PACKAGE_VERSION |
"0.1.0" tip pin until all runtimes + goldens move together |
PACKAGE_VERSION / __version__ |
From installed dist metadata (stamp-synced with root VERSION) |
Canonical normalizer_version |
Contract version 0.2.0 (never package SemVer) |
Hypabolic normalizer.version |
WIRE_PACKAGE_VERSION |
OTEL instrumentation_version |
WIRE_PACKAGE_VERSION |
Development
From the monorepo root:
python -m pip install -e './python[dev]'
python -m pytest python/tests -q
Wire authority: contracts/ and conformance/. Product docs:
docs/architecture.md,
docs/live-session-streaming.md.
License
MIT — Copyright 2026 Hypabolic
Release files for hypabolic-trajectory 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hypabolic_trajectory-0.1.3.tar.gz | 129.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hypabolic_trajectory-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 310.4 kB
Release files / hypabolic_trajectory-0.1.3.tar.gz
| Download URL | hypabolic_trajectory-0.1.3.tar.gz |
|---|---|
| Size | 129.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b7766ec26a7d77d3271688b6ca9b824b1b1ac702eedae9282ddd3bd82f45af1
|
|
BLAKE2b-256 checksum How to use checksums |
7ec764f7acdd5999595b49ad8ba96b40f2b28dc415b4192f21ba660671a3078a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / hypabolic_trajectory-0.1.3-py3-none-any.whl
| Download URL | hypabolic_trajectory-0.1.3-py3-none-any.whl |
|---|---|
| Size | 181.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7087d31adab8de5cc664ee970f03431aec27e4fa6759c80a40cd3f8227a902e1
|
|
BLAKE2b-256 checksum How to use checksums |
53448034e90d604cea5d94a238b5d001352b5e49f7c6100cb112a651f4787fe1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency log