alc.services¶
The execution layer — business logic and external integrations. Services operate on models; they don't define them. This page covers the core state services; specialized services (media, AI, deadline) get their own pages as they stabilize.
Task state — MSD_SERVICE¶
alc.services.task_msd ¶
Entity ¶
Bases: BaseModel
A logical grouping of tasks (e.g., a specific Shot or Asset).
TaskRegistry ¶
Bases: BaseModel
The 'State' of a project's tasks. This replaces TaskCollection.
for_assignee ¶
Every task that is "mine" for a set of assignment keys — I'm an
explicit assignee OR I've contributed a version (see
TaskManifest.is_assigned_to). Keys come from
alc.services.people.assignment_keys (email + aliases + local
login), so both canonical emails and legacy login strings match.
Source code in alc\services\task_msd.py
MsdService ¶
Bases: BaseModel
Stateful service for querying project tasks.
tasks
property
¶
Returns a flat list of all TaskEntry objects for the current project.
model_post_init ¶
Runs automatically after MSD_SERVICE = MsdService() is called. Hydrates the service with the project currently defined in CFG.
Source code in alc\services\task_msd.py
load_project ¶
load_project(
project_id: str = None,
force_reload: bool = False,
company_id: str = None,
) -> TaskRegistry
Deterministic hydration of the Task Manifest.
Grounded to the ACTIVE company (request-scoped in the web app,
CFG-current elsewhere) unless company_id says otherwise. Cache is
keyed {company}:{project} — project ids repeat across companies.
Source code in alc\services\task_msd.py
get_manifest_assets ¶
Loads the published JSON asset manifest and instantiates clean Entity models using native Pydantic dictionary unpacking, ensuring zero naming mutations.
Source code in alc\services\task_msd.py
sync_task ¶
Fold a manifest that just hit disk back into the cached registry.
The registry is hydrated once per (company, project) and then held for
the life of the process, while every write goes through a fresh
TaskManifest (PathObject.task_msd builds a new one each call). So a
commit — a new version, a status change, an auto-assignment — landed on
disk but left the cached copy stale, and the views that read the
registry (My Tasks, the tracker grid) kept showing the pre-commit
state until the server restarted. Called from TaskManifest.commit,
the one choke point every write passes through.
Source code in alc\services\task_msd.py
get_project ¶
backhydrate_registries ¶
backhydrate_registries(
project_id: str,
asset_types: Union[str, List[str]] = "all",
split_profiles: bool = False,
)
Sweeps a legacy project task layout, instantiates master asset registries based on requested category flags, and serializes the tracking architecture to disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str
|
The unique string registry ID of the destination project. |
required |
asset_types
|
Union[str, List[str]]
|
"all", "scn", "chr", "env", "prp", or a list like ["chr", "prp"] |
'all'
|
split_profiles
|
bool
|
If True, writes out deep independent profiles to standalone files. |
False
|
Source code in alc\services\task_msd.py
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | |
Asset registry — PROJECT_REGISTRY¶
alc.services.project ¶
ProjectStore ¶
Bases: BaseModel
A unified data proxy representing a single project's fully hydrated asset registry universe. Cached in-memory by the ProjectRegistry service.
has_script
property
¶
True once a screenplay file has been dropped into the scr task source area.
docs_dir
property
¶
The latest published crew-docs directory (scr/docs render area) —
where character_profiles.md / location_profiles.md / breakdown.xlsx
live. The single source of truth shared by the analysis passes, the design
publish image step, and the manual populate route. Mirrors the PathObject the
AnalyzeScript recipe writes to (VERSIONS/render, latest version).
scenes
property
¶
Returns a flat, chronologically ordered list of screenplay SCENES.
Scene-typed only. Videos (beat boards) share the scene registry — same model,
same keyspace, told apart by SceneAsset.type — so this is the one filter
that keeps them out of everything downstream: the sidebar count, the Scenes
grid, the tracker, the schedule and the bid all read this list. Videos have
their own accessor (video_entries) and their own grid.
video_entries
property
¶
The REGISTERED videos / beat boards — the type="videos" half of the
scene registry, carrying each board's location(s), cast and props. Distinct
from the Videos grid's list_videos(), which scans the disk for boards that
exist; a board only appears here once its roster has been registered (previs
prep does that).
asset_media_registry
property
¶
Dynamically aggregates all environment and character asset identifiers registered to the project, mapping them to their canonical pipeline media paths.
merge_script_output ¶
Merge published script output (chr.json, prp.json, env.json, script.json) from a render version directory into the live production registries at msd_root.
- Characters / Props / Environments: tracking arrays (scene_ids, scene blocks) are extended; existing production metadata is never overwritten.
- Scenes: character_ids and prop_ids merged; timing preserved. The canonical msd_root/scn/script.json is updated to the new version.
enrich=True runs the LLM script-analysis passes after the merge to fill
EMPTY production-metadata fields (e.g. environment description / art-direction)
from the script — merge-safe (never clobbers human edits). See
:mod:alc.services.ai.analysis. Enrichment failure never fails the publish.
Call this after a full audit commit where all rows are confirmed.
Source code in alc\services\project.py
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | |
force_reload ¶
Purges memory cache and forces a fresh disk read pass on subsequent access hits.
Source code in alc\services\project.py
refresh_registries ¶
Drop only the asset-registry caches (char/env/prop) so the next access re-reads from disk. Cheap (~20ms each) and leaves the heavier script-model cache intact — used by the asset grid so out-of-band writes (analysis passes, Blender, other tools) show up without an app restart.
Source code in alc\services\project.py
ProjectRegistry ¶
Bases: BaseModel
Stateful service manager for caching and switching between hydrated ProjectStore instances. Prevents costly re-hydration when bouncing between different active projects in UI views.
current
property
¶
The ACTIVE project's store.
Inside a web request this is the (company, project) named by the URL —
every existing PROJECT_REGISTRY.current call site becomes
request-correct without edits. Outside a request it is the mutable
global selection, exactly as before (DCC/CLI unchanged).
get_project ¶
get_project(
project_id: str,
company_id: Optional[str] = None,
force_reload: bool = False,
) -> ProjectStore
Retrieves a project's store instance from cache memory, or initializes and validates a fresh instance if it doesn't exist.
Cache is keyed {company}:{project} — project ids repeat across
companies (elc/tpa vs nca/tpa), so a bare project id is ambiguous.
company_id defaults to the ACTIVE company (request-scoped in the
web app, CFG-current elsewhere).
Source code in alc\services\project.py
store_for ¶
The ProjectStore for the coordinate po addresses — its OWN company/project.
Use this for any work driven by a path rather than by the UI: cookbook steps, DCC
calls, farm jobs, CLI runs. PROJECT_REGISTRY.current is the wrong tool there.
Inside a web request current is request-correct, but outside one it is the
mutable global selection — whichever project the app happens to have open — so a
step handed a cgl/loj path while the app sits on bse/imm reads imm's
registries. Nothing errors: lookup_asset just returns None and the asset
"isn't in the registries", and it flips from run to run as the selection changes.
Resolving from the address makes the same path mean the same thing every time.
refresh=True mirrors the old …current.refresh_registries() call shape.
Raises ValueError when po carries no project — guessing would reintroduce the exact silent cross-project read this exists to prevent.
Source code in alc\services\project.py
Selection — POM¶
alc.services.selection ¶
SelectionManager ¶
The 'You Are Here' utility for the Alchemy Ecosystem. Replaces the legacy PathObjectManager by removing GUI signals.
path_object
property
¶
Standardized shorthand for the active PathObject.
set_path_object ¶
Updates the selection context using .copy() to ensure we don't mutate the underlying state accidentally.
Source code in alc\services\selection.py
Events¶
alc.services.event_service ¶
EventService ¶
Orchestrator for decentralized task telemetry. Events are stored as individual JSON files to prevent race conditions.
Source code in alc\services\event_service.py
log_event ¶
log_event(
action: str,
version: str = "v000",
user: Optional[str] = None,
app: Optional[str] = None,
recipe_type: Optional[str] = None,
name: Optional[str] = None,
details: Optional[Dict[str, Any]] = None,
parent_event_id: Optional[str] = None,
shared_data: Optional[Dict[str, Any]] = None,
dev_mode: Optional[bool] = False,
) -> EventEntry
Creates and immediately persists a new event file.
Source code in alc\services\event_service.py
update_step ¶
update_step(
step_key: str,
status: str,
feedback: str = "",
duration: Optional[float] = None,
extra: Optional[Dict[str, Any]] = None,
) -> StepData
Updates a step on the current (latest) event and re-commits the file.
Source code in alc\services\event_service.py
get_history ¶
Gathers individual event files into a list. Useful for UI displays or audits.
Source code in alc\services\event_service.py
update_shared_data ¶
Updates shared data on the current active event.