hugpy-video
Identity storage uses one shared implementation for HTTP handlers and render jobs. See identity storage for transaction behavior, deployment requirements, and the remaining HTTP wiring. The identity revival roadmap maps the archived initialization, versions, cleanup, and 3D-continuity plans onto the current packages, including staged controls and the remaining renderer-adapter work. The video handler inventory lists current inference operations, connection gaps, qualification requirements, and the wiring order derived from the archived IDEA_PHASE lifecycle.
The staged HTTP arm includes Oracle as a child Blueprint of video_bp.
Core mounts this one Blueprint; /api/oracle/* and the full
/api/video/script/* REST API run in the same process as Video. The standalone
Video app mounts the same composite Blueprint. The hugpy.arms entry point
exports hugpy_video.routes:video_bp; dictionary/tool consumers may still use
categories.ALL_CATEGORIES. Its legacy script adapters are excluded from HTTP
registration so Oracle's native methods, status codes, and error bodies own
those resources without overlapping routes. This requires Oracle 0.3.12+,
which no longer publishes a separate hugpy.arms entry point.
The video arm of Hugpy (import name hugpy_video). The source version is
declared in pyproject.toml; /api/video/health reports the running package.
It covers execution and artifacts for video work:
- the media library jail and the sqlite media job bus, with its local runners (ffmpeg crop, frames and audio);
- engine-backed generation (image, scene and movie), the studio spine (t2v/i2v clips, segmented movies, the model battery) and the GPU reservation engine;
- the identity-profile library with relays to the identity render service;
- LLM prompt assist;
- the
/videoVideo Intelligence console (SPA) and its API (/api/video/*,/api/movie/*), mounted inside Core through its arm hooks or served by the standalone Video service.
The arm contract (toolset → Blueprint → standalone server → arms.d → core
proxy) is in docs/arms.md. How engine-backed routes choose
and fall back between models is in
docs/execute_prompt.md.
2026-10-21 studio overhaul (0.3.9)
Read ../docs/README.md for the full index of findings and build notes. In short:
- Real renders go through the wrapper engine (
studio_i2v.render_clip→execute_prompt→{HUGPY_CORE_URL}/v1/videos/generations), with honest phases (queued/loading/rendering/done), wrapper request-id correlation, 503 retry, load/stall deadlines, cancel →orphaned, and the placement verdict recorded on the job. Proven: Wan2.1-T2V-1.3B 480p/33f in ~45 s from the NVMe hot tier. - Legible backend state: per-job JSONL event log (
<state>/job_logs/<job_id>.jsonl), a full job view (timeline,lifecycle,engine,placement,model_id,worker,log_tail),GET /video/status,hugpy-video jobs tail <id> [--follow],hugpy-video status, SSE events fixed (HUGPY_VIDEO_EVENT_URL, default self) and persisted across restarts. - Render templates:
intel/studio/render_templates.json(preference + tolerance + ordered stages per call type),GET /video/studio/templates,GET /video/studio/template?template_id=,POST /video/studio/template/run,template_idonPOST /video/studio/i2v; executed contiguously as onestudio_templatejob. - Render battery ledger:
GET /video/battery(HTML) /GET /video/battery.json,hugpy-video battery [--since 24h] [--html PATH] [--json PATH]; every real render also lands a row in the k71 model-battery root (HUGPY_MODEL_BATTERY_ROOT, live root/srv/vm_mgr/share/projects/hugpy/model-battery). - Text roles from the aptitude tests:
intel/studio/studio_text_roles.json,GET /video/studio/roles,hugpy-video roles; call sites default to the measured winners, request/env still win. - Registry/presets:
RunnerSpec.readygates Err-stub runners, presets report live presence and refusal reasons, frame clamps carry a recorded reason, routing VRAM comes from the wrapper's/v1/verdicts. - UI: unified Job Inspector, Media Viewer, render template picker; the embedded bundle is a local
0.3.11 build (see
src/hugpy_video/ui_dist/PROVENANCE.md).
Testing note: never run the suite with HUGPY_CORE_URL pointing at a live wrapper or core — several tests
call the render path for real. Use HUGPY_CORE_URL=http://127.0.0.1:9 (and HUGPY_FITEVICT_FRONT_DOOR), and do not
export HUGPY_VIDEO_STATE_DIR / DEFAULT_ROOT (conftest isolates storage per process). See ../docs/README.md.
Dependency on hugpy-oracle
hugpy-oracle is a hard dependency (hugpy-oracle>=0.3.11,<0.4 in 0.3.5;
>=0.3.10 in 0.3.4; operator ruling 2026-10-15). The dependency graph runs
video → oracle. The oracle's use of video is lazy and optional: its video extra pulls in hugpy-video, and
it reaches video's studio registry, runners and media bus only inside the
functions that need them. Video imports the oracle lazily, inside the
toolset callables that need it (studio/plan, producer/plan,
performance/probe, script/runs, script/sources), so import hugpy_video
loads no planner. The oracle's planners install into video's hooks
(hugpy_video.bus.hooks) through hugpy_oracle.install_hooks(). That call is
made idempotently by the planner routes, and by the hugpy.video.hooks entry
point when hugpy_video.web.api loads.
Layout
src/hugpy_video/
imports/ the shared layer: imports no optional or heavy backend
constants.py ARM_NAME="video", UI_PREFIX="/video/", every env-var NAME and default
functions.py env_value()/env_bool(), parse_env_file(), lazy()/first_lazy()
classes.py VideoError, ToolError (the toolset error, which becomes {"error": ...}),
JobError (the job error-as-data, lifted from hugpy_control in 0.3.5)
store.py stdlib cross-process sqlite helpers, lifted from hugpy_control in 0.3.5
(used by the studio-assist log and the reservation ledger; same env
names and paths, so existing stores keep working)
init_imports.py, __init__.py
toolset.py get_toolset() -> {"video": {...}, "movie": {...}}, get_manifest()
routes.py video_bp = register_categories(get_bp("video"), get_toolset())
plus the native SSE escape hatches
serve/ the standalone service: `hugpy-video serve` (app.py: create_app, serve)
ui.py dist_dir() -> ui_dist/ (built @hugpy/video-intelligence-ui)
web/ the Flask view implementation the toolset adapts: api (read surface,
presets, identity library, media/clip bytes), generate, identity_write,
movie_routes, assist, studio_planning, render_catalog, jobstream (SSE),
studio_assist_log, video_intent
bus/ the job-bus control plane: jobs (public API, register_job), job_events
(worker -> core transitions), hooks (PromptCoordinator and planner seams)
intel/ media_store (refs and jail), media_bus (sqlite bus), job_bridge,
job_schema, presets, reservation/, runners/ (ffmpeg, diffusers plane,
studio, identity relays, MLT), studio/ (the studio spine), plane.py
(the one seam onto hugpy_engine.execute_prompt)
chat_video/ chat-side frame analysis over a hugpy_media vision runner
video_gen/ StudioVideoRunner / VideoGenRequest (engine runner for t2v/i2v)
plugin.py hugpy_engine.tasks entry point: text-to-video, image-to-video
state.py injectable state roots; config.py HUGPY_API_KEY / HUGPY_BASE loader
cli.py `hugpy-video`; selftest.py; sql/001_video_jobs_notify.sql
_lifted/ helpers lifted from the retired monolith
Import HTTP modules directly from hugpy_video.web and job-bus modules from
hugpy_video.bus. The old top-level aliases have been removed. Wildcard imports
are forbidden (tests/test_import_policy.py).
The toolset (video/* 56 routes, movie/* 2 routes)
Each route is GET+POST at /api/<category>/<route>, with a trailing-slash
variant. Ids are kwargs (?job_id=, ?slug=, ?preset_id=, ?movie_id=), not
path segments. The return value comes back as {"result": ...} and an error as
500 {"error": "<real message>"}. Byte routes return the file Response
directly (status 200, 206 or 404 preserved). Source: toolset.get_toolset(),
verified against the live GET /api/video/manifest.
Works standalone (no core, no GPU)
| Route | Notes |
|---|---|
health, manifest |
identity; the manifest includes escape_hatches |
jobs |
job bus listing; reads ?all, ?stale, ?limit, ?owner |
job, job/cancel, job/private |
job_id; job/private reads private from the body |
media |
handle: raw bytes for a jailed MediaRef (Range supported) |
projects, presets |
catalog reads |
studio/clips, studio/clip, studio/clip/detail, studio/clip/archive, studio/clip/unarchive |
job_id; studio/clip streams the mp4. Archive never deletes. |
studio/presets, studio/presets/apply |
preset_id |
identity-profiles, identity-profile, identity-profile/delete, identity-profile/private |
slug; delete archives, never hard-deletes |
ingest |
turns a path under the video storage root into a MediaRef |
jobs/crop, jobs/frame_extract, jobs/audio_extract |
ffmpeg runners on the local bus (needs ffmpeg; the deb depends on it) |
prompt/assist/log, prompt/assist/ticket (ticket), studio/movies |
local reads |
performance/probe |
the oracle's (oracle, performance) readiness, reported as data: ready, bound, unbound with the operator step for each gap |
script/sources, script/runs |
the oracle's script-first run store. GET script/runs lists runs; POST starts one. |
movie/presets, movie/presets/apply |
preset_id |
Needs a reachable core and GPU fleet
Each of these first checks HUGPY_CORE_URL (default http://127.0.0.1:7020,
1.5 s). If nothing answers, the route raises ToolError naming the variable and
/etc/hugpy/video.env, and does not enqueue anything. The check proves only
that something answers HTTP at that URL; the fleet itself is reached later,
through execute_prompt.
jobs/generate_image, jobs/generate_scene, jobs/generate_movie,
studio/i2v, studio/tester, studio/movie, studio/movie/pause
(movie_id), studio/movie/resume (movie_id), studio/plan and
producer/plan (oracle-backed planners), prompt/assist, prompt/intent,
prompt/assist/models, render/presets.
Needs the identity render service
These require IDENTITY_RENDER_URL (and IDENTITY_RENDER_TOKEN). Without it
they raise a ToolError that names the variables:
identity-profiles/create, identity-profiles/from-video,
identity-profiles/from-images, identity-profiles/video-extract,
identity-profile/reconstruction (slug), identity-profile/canonical
(slug), identity-profile/generate (slug). The identity extra installs
the abstract-identity client. It does not start a GPU service.
Stubs: reachable, not implemented in this build
These always answer 500 {"error": "<route> is not implemented in this hugpy-video build: <what it needs>"}. They never return 404:
| Route | Missing piece |
|---|---|
identity-render/probe |
the identity render service probe |
studio/clip/to-editor |
the Filmora editor handoff (ffprobe/remux) |
identity-profile/settings |
the identity gen_settings write (not ported) |
identity-profile/update |
the identity profile name/notes write (not ported) |
identity-profile/versions |
identity version management (not ported) |
Escape hatches (native Blueprint routes)
| Route | Kind |
|---|---|
GET /api/video/jobs/stream |
SSE. Sends a stream.ready marker, then one row per job transition, filtered to what the caller may see. Capped at one hour; the client re-seeds from video/jobs. |
GET /api/video/prompt/assist/log/stream |
SSE: the studio assist log |
POST /api/video/jobs/event |
internal ingest: a worker reports {job_id, status}. Returns 202. Not listed in escape_hatches. |
The job stream is single-process by default. With
HUGPY_VIDEO_JOBS_PG_DSN unset, a reported transition goes straight into this
process's in-memory event ring and no Postgres listener starts. Set it (for
example dbname=hugpy_video) only when several processes share one bus and
need Postgres LISTEN/NOTIFY to fan events out. That needs
sql/001_video_jobs_notify.sql and psycopg. If Postgres is then unreachable,
the listener retries and the stream degrades to the initial seed.
Not served (pending)
POST /video/jobs/performance. The Oracle station's performance submit is not in the toolset, and the standalone service returns 404. The legacyweb/api.pyregisters it only as a "501 not available" placeholder. Useperformance/probeto see which seams are unbound.- Video UI uploads. The SPA's file stations (image crop, audio crop, frame
extract, identity upload, studio generate) upload to
/api/uploads. Neither this service nor core 0.4.40 serves that route (404).
Standalone service
hugpy-video serve [--host H] [--port P] [--env-file /etc/hugpy/video.env]
create_app() does the following:
- loads the env file without overriding the environment;
- creates the state directories and initialises the sqlite job bus;
- builds
abstract_flask.get_Flask_app(name="hugpy-video", routes=hugpy_video.routes, url_prefix="api"); - serves the SPA at
/video/with history fallback./and/videoredirect to/video/. A build withoutui_distserves only the API. - forwards
/v1/*(streamed) toHUGPY_CORE_URL. This exists because the UI's model pickers read core's/v1/modelsand/v1/task-bindings. With core unreachable it answers503 {"error": "hugpy core unreachable at ..."}.
Then it runs Flask threaded, so SSE does not block other requests.
Demo media. The served index.html marker
window.__HUGPY_MEDIA_BASE__ = window.__HUGPY_MEDIA_BASE__ ?? null; is
rewritten from the environment. HUGPY_DEMO_MEDIA_DIR (served by this process
at /demo-media/) takes precedence over HUGPY_DEMO_MEDIA_BASE (a URL).
curl -s 127.0.0.1:7341/api/video/health # {"result":{"arm":"video","ok":true,"version":"0.3.4"}}
curl -s '127.0.0.1:7341/api/video/jobs?limit=5'
curl -s 127.0.0.1:7341/api/video/performance/probe
curl -sN 127.0.0.1:7341/api/video/jobs/stream
Merged into core
The arm also runs in-process inside hugpy-core (operator decision 2026-10-21;
docs/CORE-MERGE-PLAN.md). Core does not run serve/app.run, does not
read /etc/hugpy/video.env, and does not mount the /v1 forwarder or the
/ redirect. Instead it loads two entry points by group name:
hugpy.arm_prepare→serve.embed:prepare()— creates the state tree + sqlite job bus and starts the media_bus runner pool and thehugpy.video.hooksplanners in the core process.hugpy.arm_ui→serve.embed:wrap_ui()— serves the built SPA at/video/(history fallback, demo-media marker rewrite) as a pure-WSGI wrapper.
Core mounts the routes explicitly (from hugpy_video.routes import video_bp in
hugpy_core.routes) and keeps arms_group disabled so media/oracle are not
auto-mounted (see ROUTES-CONVENTION.md). Under core the config is a single
root-only env source (/etc/hugpy/core.env), not video.env:
| Variable | Value under core | Why |
|---|---|---|
DEFAULT_ROOT |
/var/lib/hugpy-core/root |
state resolves to <DEFAULT_ROOT>/video_intel; keeps /video_intel/ in artifact paths for the guest jail |
HUGPY_VIDEO_STATE_DIR, HUGPY_MEDIA_JOBS_DB, STUDIO_OUTPUT_ROOT, HUGPY_RESERVATIONS_DB, UPLOADS_HOME, PROJECTS_HOME, IDENTITIES_HOME |
unset | compose from DEFAULT_ROOT; do not reuse /var/lib/hugpy-video |
HUGPY_VIDEO_EVENT_URL |
http://<core-host>:<core-port>/api (core itself) |
the HTTP job-event fallback posts to core's own /api; the default dead 127.0.0.1:7341 is never used |
HUGPY_CORE_URL |
http://<core-host>:<core-port> (self) |
engine preflight + /v1/videos/generations relay to the model-holding box |
HUGPY_AUTH_MODE |
open |
every caller nginx admits is the operator (matches the console) |
HUGPY_VIDEO_JOBS_PG_DSN |
unset | single-process ring (core is one werkzeug process) |
STUDIO_WEIGHTS_ROOT, HF_HUB_OFFLINE=1, HUGPY_MODEL_BATTERY_ROOT |
as in the plan | presence/routing, offline HF probes, battery ledger |
HUGPY_VIDEO_EMBED_DAEMON |
unset (= start pool) | set 0 for a control-plane-only profile: routes + SPA, no runner threads |
CLI
| Command | What it does |
|---|---|
hugpy-video serve [...] |
the standalone service |
hugpy-video jobs list [--all] [--limit N] [--json] |
the media job bus |
hugpy-video jobs registry |
registered job names, runner keys, queues and timeouts |
hugpy-video selftest |
in-process checks (no GPU, no service); exits 1 on failure |
hugpy-video state |
prints the resolved state roots |
hugpy-video models audit [--json] |
declared studio models: runner gaps, weight pin, VRAM by precision. Loads no weights. |
hugpy-video --version |
Environment
The names are defined in imports/constants.py.
| Variable | Default | Effect |
|---|---|---|
HUGPY_VIDEO_HOST / HUGPY_VIDEO_PORT |
127.0.0.1 / 7341 |
bind address of serve |
HUGPY_VIDEO_STATE_DIR |
<DEFAULT_ROOT>/video_intel (the deb uses /var/lib/hugpy-video) |
job bus and studio sessions |
HUGPY_MEDIA_JOBS_DB |
<state>/media_jobs.db |
sqlite job bus |
HUGPY_RESERVATIONS_DB |
<PROJECTS_HOME>/reservations.db |
GPU reservation ledger |
STUDIO_OUTPUT_ROOT |
<state>/studio |
studio sessions and renders |
DEFAULT_ROOT, UPLOADS_HOME, IDENTITIES_HOME, PROJECTS_HOME |
hugpy_platform (the deb sets DEFAULT_ROOT=/var/lib/hugpy-video/root) |
platform storage roots; the media jail is UPLOADS_HOME plus DEFAULT_ROOT |
HUGPY_CORE_URL |
http://127.0.0.1:7020 |
engine preflight, /v1 forwarder, engine relays |
HUGPY_VIDEO_JOBS_PG_DSN |
unset (single-process) | multi-process job-stream fan-out |
IDENTITY_RENDER_URL, IDENTITY_RENDER_TOKEN |
unset | identity render service |
HUGPY_DEMO_MEDIA_DIR, HUGPY_DEMO_MEDIA_BASE |
unset | demo-media marker rewrite |
HUGPY_WORKER_NAME |
unset | worker identity on reported job events |
HUGPY_API_KEY, HUGPY_BASE |
"", https://dev.hugpy.ai/api |
config.load_config() credentials. The legacy aliases CONSOLE_API, HUGPY_API_TOKEN, HUGPY_AGENT_API, HUGPY_API_KEY_NEWVM / HUGPY_BASE_URL, HUGPY_URL, HUGPY_CENTRAL are accepted and recorded in Config.deprecations. |
Tuning knobs read by the runners include HUGPY_MEDIA_BUS_* (runners,
lookahead, stale and reap timing), HUGPY_RESERVATION*, STUDIO_WEIGHTS_ROOT,
STUDIO_MAX_VRAM_GB, STUDIO_ALLOW_UNPINNED and HUGPY_SCENE_CONCURRENCY.
Their defaults live next to the code that reads them.
Debian package
BUILD_PYTHON=/usr/bin/python3 packaging/debian/build.sh # -> build/debian/hugpy-video_<ver>_amd64.deb (Python 3.12)
sudo apt install ./build/debian/hugpy-video_<ver>_amd64.deb # 0.3.4 is the newest deb built so far
build.sh bundles offline wheels for hugpy-video and its local siblings
(hugpy-oracle, hugpy-platform, hugpy-media, hugpy-engine) and their
public dependencies. The 0.3.4 deb also bundled hugpy-control and
hugpy-storage. Neither is needed since video 0.3.5, oracle 0.3.11 and
media 0.3.4. build.sh asserts that the wheel contains ui_dist/index.html
and sql/001_video_jobs_notify.sql.
The control file declares Depends: python3 (>= 3.12), python3 (<< 3.13), python3-venv, systemd, ffmpeg.
postinst:
- builds
/opt/hugpy-video/venvoffline and force-reinstalls the bundled siblings; - creates the
hugpy-videosystem user, a member of thehugpygroup; - creates
/var/lib/hugpy-video(mode 0750) withroot/inside it; - writes
/etc/hugpy/video.envif it is absent; - writes
hugpy-video.service(WorkingDirectory=/var/lib/hugpy-video,ProtectSystem=strict,ReadWritePathsset to the state directory); - writes
/usr/share/hugpy/arms.d/video.json(categoriesvideoandmovie, UI/video/; the upstream port followsvideo.env); - restarts the service.
Core then proxies /api/video/*, /api/movie/* and /video/*. postrm
removes the unit and the arms.d file. On purge it also removes the venv, the
state, video.env and the user. Host-level steps are in
docs/install.md.
Dependencies
Runtime (pyproject.toml, 0.3.5): flask>=2, pydantic>=2,
abstract-essentials, requests>=2.28, abstract-flask>=0.0.0.1052,
hugpy-platform>=0.3.0, hugpy-media>=0.2.8, hugpy-engine>=0.3.2,
hugpy-oracle>=0.3.11,<0.4.
hugpy-control is no longer a dependency as of 0.3.5. Its sqlite store helpers
and JobError now live in hugpy_video.imports (store.py, classes.py).
Version 0.3.4 depended on hugpy-control>=0.3.0.
Extras: render (numpy, Pillow, requests), studio (torch, diffusers,
transformers and the rest of the GPU set), identity (abstract-identity),
test. GPU and runtime pieces are never imported at module scope.
Entry points
| Group | Name → target |
|---|---|
console_scripts |
hugpy-video → hugpy_video.cli:main |
hugpy.arms |
video → hugpy_video.routes:video_bp |
hugpy.toolsets |
video → hugpy_video.toolset:get_toolset |
hugpy_engine.tasks |
video → hugpy_video.plugin:register (text-to-video, image-to-video) |
Rules
- Heavy imports are lazy. The package must import on a CPU-only box.
- The version is single-sourced from
pyproject.tomlthroughimportlib.metadata. - Credentials come only through
hugpy_video.config.load_config.
UI
The SPA source is ui/video_intelligence_ui.
Its build is copied into src/hugpy_video/ui_dist/, and the provenance is in
ui_dist/PROVENANCE.md.
Downloads and feature gallery
Get the Debian packages, architecture details, SHA-256 checksums and installation commands from Hugpy Downloads. The feature gallery shows the console, Agent, Station, Media and Video interfaces. Screenshots reflect the versions captured; the current interface may differ.
Video studio
A clip viewer, shot staging, model settings and generation controls.
Metadata
Release files for hugpy-video 0.3.15
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hugpy_video-0.3.15.tar.gz | 1.2 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hugpy_video-0.3.15-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.5 MB
Release files / hugpy_video-0.3.15.tar.gz
| Download URL | hugpy_video-0.3.15.tar.gz |
|---|---|
| Size | 1.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d31869d017ab100476db516f625714c8e9f91845b17d5951aa8b3354300bbe6e
|
|
BLAKE2b-256 checksum How to use checksums |
2dcc1a23ef578f8e2c5cd2b67e42a56f4ee2b8f6d204ba3b1f4c889e5d78f2e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / hugpy_video-0.3.15-py3-none-any.whl
| Download URL | hugpy_video-0.3.15-py3-none-any.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6351b47f96e7bbd458ff3f47ef08bf78f9009b0b67f4328137416bd3bf72f4d9
|
|
BLAKE2b-256 checksum How to use checksums |
39934233a74ac2e66fa73ea46a4338662043218d74e157d09c1ca085d9974d8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for hugpy-video 0.3.15
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.