hugpy-video
The video arm of Hugpy (import name hugpy_video). The source tree is at
0.3.5; the installed deb and running service on this host are 0.3.4.
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 toolset API (/api/video/*,/api/movie/*), served by its own service on127.0.0.1:7341. Hugpy Core proxies both.
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.
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
The old top-level module paths (hugpy_video.api, .jobstream, .jobs,
.hooks, .render_catalog, .studio_assist_log, ...) still import. They are
transparent sys.modules aliases to the new locations. 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
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.
Metadata
Release files for hugpy-video 0.3.6
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.6.tar.gz | 1.3 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hugpy_video-0.3.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.5 MB
Release files / hugpy_video-0.3.6.tar.gz
| Download URL | hugpy_video-0.3.6.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ab68463e950cf496ccde4082e201739869de79875e1187056af941d26270131
|
|
BLAKE2b-256 checksum How to use checksums |
023ef37e1c834fbae757e0147383ba56be587f619e69910364fb340dafcd5a69
|
| 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.6-py3-none-any.whl
| Download URL | hugpy_video-0.3.6-py3-none-any.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1f44a0d44d95ceac472f270525b14cc2f0a83514be5f63f1265b7f0417c89fd5
|
|
BLAKE2b-256 checksum How to use checksums |
2b2d672afea57dbdb40f632e0850dc14d999afb7ad567b21cc54fca2a79d4242
|
| 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.6
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.