Skip to content

docs: document pre-GUI submission hooks for Maya - #462

Open
leon-li-inspire wants to merge 1 commit into
aws-deadline:mainlinefrom
leon-li-inspire:feature/pre-gui-hook-docs
Open

docs: document pre-GUI submission hooks for Maya#462
leon-li-inspire wants to merge 1 commit into
aws-deadline:mainlinefrom
leon-li-inspire:feature/pre-gui-hook-docs

Conversation

@leon-li-inspire

@leon-li-inspire leon-li-inspire commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Fixes: N/A — documentation gap follow-up to #437

What was the problem/requirement? (What/Why)

The pre-GUI submission hook support for the Maya submitter shipped in #437 (feat: Run pre-GUI hooks in the Maya render submitter), but the mainline README has no documentation telling studios how to use it. Sibling integrations already document this (VRED, KeyShot), so Maya users had no discoverable guidance on enabling env-sourced hooks, authoring a preGUI hook, or understanding the confirmation-prompt behavior.

What was the solution? (How)

Add a ## Pre-GUI Submission Hooks section to README.md, adapted to how Maya's submitter actually loads and applies hooks (per #437):

  • Enablingdeadline config set settings.allow_environment_hooks true and pointing DEADLINE_HOOKS_DIR at a hooks directory with a hooks.yaml preGUI: entry (Maya sources hooks only from DEADLINE_HOOKS_DIR, since there is no on-disk job bundle at pre-GUI time — bundle_dir=None).
  • Writing a hook — a pregui_hook.py sample that reads the submission metadata JSON on stdin and prints overrides for name / description / parameters (incl. deadline:priority, deadline:maxFailedTasksCount, deadline:maxRetriesPerTask, and CondaPackages / CondaChannels / RezPackages). The stdin comment reflects Maya's submitterName ("maya").
  • What gets pre-populated — Name / Description and Priority / Maximum failed tasks count / Maximum retries per task on the Shared job settings tab; and a note that the Maya render options on the Job-specific settings tab (render layers, cameras, frame range, output/project path, renderer) are not set by the hook (they come from the scene's render settings and per-scene sticky settings).
  • Confirmation prompt — the Job Submission Confirmation dialog, with No aborting cleanly, and settings.auto_accept to skip the prompt.
  • A mayapy-specific tip (point command at a clean system Python so a bundled-interpreter startup banner does not corrupt the hook's JSON), and the deadline >= 0.60.2 client floor this package pins for the pre-GUI hook API (the deadline: job-property overrides apply at this same floor — Maya's in-process submitter routes them straight to the shared job settings).

Links the base client's hook docs via a [submission-hooks] reference to https://github.com/aws-deadline/deadline-cloud#submission-hooks.

What is the impact of this change?

Documentation only. No code changes — Maya users can now discover and configure pre-GUI hooks from the README.

How was this change tested?

Docs-only change. Verified the rendered Markdown, that the new [submission-hooks] reference and existing [deadline-cloud-client] reference resolve, and that the field/behavior descriptions match the merged #437 implementation (show_maya_render_submitterrun_pre_gui_hooks / apply_pre_gui_output) and the deadline >= 0.60.2 floor in pyproject.toml.

Integ test result

N/A — no src/ changes.

Installer test result

N/A — no installer/ or src/ changes.

Did you run the "Job Bundle Output Tests"? If not, why not? If so, paste the test results here.

Not run — this change is documentation only and does not touch job bundle generation.

Was this change documented?

Yes — this PR is the documentation. It updates README.md only.

Did you modify schema files?

  • Yes
  • No

Is this a breaking change?

No. Documentation-only change.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@leon-li-inspire
leon-li-inspire requested a review from a team as a code owner August 18, 2026 22:16
@github-actions github-actions Bot added the waiting-on-maintainers Waiting on the maintainers to review. label Aug 18, 2026
Comment thread README.md
aborts opening the submitter cleanly (no error dialog). To skip the prompt on non-interactive or
studio-locked workstations, enable auto-accept:
```
deadline config set settings.auto_accept true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The settings.auto_accept recommendation deserves a security caveat here. That setting is not hook-specific — its description in the client config is "Automatically accept the default choice for any interactive prompts." Enabling it to skip this one dialog also silently auto-accepts every other confirmation prompt the client raises (e.g. job-attachment / file-conflict confirmations), which is a broader change than the surrounding text implies.

More importantly, the hook confirmation dialog is the user's only informed-consent point before arbitrary code from DEADLINE_HOOKS_DIR executes on their workstation — the client's own _generate_hooks_confirmation_message comment calls it exactly that. DEADLINE_HOOKS_DIR is an ordinary environment variable, so anything that can set it in the artist's environment gains silent code execution once allow_environment_hooks and auto_accept are both true. Recommending auto_accept for "studio-locked workstations" without flagging that tradeoff reads as a safe convenience toggle when it removes the only guardrail.

Suggest noting that (a) auto_accept is global, not hook-scoped, and (b) it should only be set where DEADLINE_HOOKS_DIR and the hooks directory contents are themselves administratively controlled.

Comment thread README.md
# pregui_hook.py
import json, sys

# jobName, submitterName ("maya"), priority, parameters, farmId, queueId, ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment advertises priority (and farmId / queueId) as useful inputs, but for the Maya submitter priority is always the hardcoded default 50, never the user's actual value.

src/deadline/maya_submitter/maya_render_submitter.py:328-334 builds the context with only four fields:

PreGuiHookContext(
    bundle_dir=None,
    job_name=render_settings.name,
    submitter_name="maya",
    parameters=dict(shared_parameter_values),
)

PreGuiHookContext.priority defaults to 50, so it is never populated from render_settings.priority — which is a sticky field (data_classes.py:49) and can legitimately be something else after load_sticky_settings. A hook author who reads this line and branches on the incoming priority (e.g. "only raise it if the artist left it at default", or "clamp whatever they set") will get wrong behaviour, and it will look like a hook bug rather than a submitter one.

Either fix the call site to pass priority=render_settings.priority, or drop priority from this list / note that Maya always sends 50 at pre-GUI time. Worth double-checking the farmId/queueId claim too: those are left None in the context and so are resolved from defaults.farm_id / defaults.queue_id config rather than from anything the artist picked in the dialog (which has not opened yet).

@leon-li-inspire
leon-li-inspire force-pushed the feature/pre-gui-hook-docs branch from 6188a12 to da86af9 Compare August 18, 2026 22:58
Comment thread README.md

Before running any hooks, the submitter shows a **Job Submission Confirmation** dialog listing the
hook scripts that will execute. Click **Yes** to run them, or **No** to cancel — clicking **No**
aborts opening the submitter cleanly (no error dialog). To skip the prompt on non-interactive or

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section documents the cancel path but not the failure path, which is the one that will actually generate support tickets.

show_maya_render_submitter only catches DeadlineOperationCanceled (maya_render_submitter.py:337). Every other hook error is a DeadlineOperationError raised out of HookManager.execute_pre_gui_hooks, which propagates past the run_pre_gui_hooks call and reaches the caller's gui_error_handler — so the submitter never opens at all. The client raises that for:

  • non-zero exit code (Pre-GUI hook [N] failed with exit code ...)
  • timeout (Pre-GUI hook [N] timed out after Ns) — default timeout is 60s
  • stdout that is not valid JSON (produced invalid JSON)
  • output containing keys outside {name, description, parameters}
  • hook.command not resolvable (Hook command not found) — note relative commands are resolved against the hooks dir and then PATH

This matters because it is a hard availability coupling: a studio that deploys a hook script referencing a Python interpreter path that does not exist on one artist's box makes the Deadline Cloud submitter completely unopenable for that artist, with a generic error dialog and no obvious link back to DEADLINE_HOOKS_DIR. It also interacts with the mayapy tip above — a stdout banner does not degrade gracefully, it blocks submission.

Suggest a sentence here (or in "Writing a pre-GUI hook") stating that any hook failure, timeout, or malformed stdout prevents the submitter from opening, and that hooks should therefore fail soft (catch their own errors and emit {}) and write diagnostics to stderr, not stdout.

Comment thread README.md Outdated

> **Version note (`deadline:` overrides):** routing of `deadline:`-prefixed job properties
> (`deadline:priority`, `deadline:maxFailedTasksCount`, `deadline:maxRetriesPerTask`) was fixed in
> `deadline` 0.60.4 ([deadline-cloud PR #1322][deadline-pr-1322]). The Maya submitter runs in-process

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stated reason for why Maya is unaffected is not the actual reason, and that matters because the real reason is fragile.

"The Maya submitter runs in-process" has nothing to do with it — apply_pre_gui_output is the same function on both paths. On 0.60.2/0.60.3 it routes by:

template_parameters = getattr(initial_settings, "parameters", None) or []
template_param_names = {p["name"] for p in template_parameters}
...
if param_name in template_param_names:     # deadline:priority IS here for job bundles
    ...                                    # -> misrouted onto settings.parameters
else:
    initial_shared_parameter_values[param_name] = param_value

Maya works on 0.60.2 purely because RenderSubmitterUISettings happens to have no parameters attribute, so template_param_names is empty and deadline:priority falls through to the else. The job-bundle path breaks only because read_job_bundle_parameters leaves deadline:* in the parameters list, putting it in template_param_names. 0.60.4 fixed it by hoisting the startswith("deadline:") test above the template-name check.

So the correctness of deadline: overrides in Maya at the >= 0.60.2 floor rests on an incidental absence, not on a designed guarantee — exactly what this repo's own test asserts: "This guards against a regression where RenderSubmitterUISettings gains a parameters attribute that would misroute hook params" (test/unit/deadline_submitter_for_maya/test_pre_gui_hooks.py:11-13).

Two consequences worth reflecting in the text:

  1. Replace "runs in-process" with the real condition, or just say Maya is unaffected without asserting a mechanism — as written, a maintainer who later adds a parameters field to RenderSubmitterUISettings will read this paragraph and conclude Maya is safe when it silently is not (on any client below 0.60.4).
  2. Given pyproject.toml pins deadline >= 0.60.2,< 0.61, 0.60.2/0.60.3 are inside the supported range, so this is a live configuration rather than a historical one. If the intent is that deadline: routing is reliable, the cheaper fix is bumping the floor to >= 0.60.4 and deleting this whole note.

Comment thread README.md
`parameters` (a map of parameter name → value). `deadline:`-prefixed keys map to shared job
properties such as `deadline:priority`, `deadline:maxFailedTasksCount`, and
`deadline:maxRetriesPerTask`, while names such as `CondaPackages` / `CondaChannels` / `RezPackages`
override the queue/package parameters the submitter seeds for the job.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth stating that a parameters name which is neither deadline:-prefixed nor an actual queue parameter is silently discarded — no error, no warning.

Because RenderSubmitterUISettings has no .parameters list, apply_pre_gui_output puts every non-deadline: name into initial_shared_parameter_values. From there it only survives if it matches a queue parameter definition returned by the farm/queue:

for parameter in queue_parameters:
    if parameter["name"] in self.initial_shared_parameter_values:
        parameter["value"] = self.initial_shared_parameter_values[parameter["name"]]

(shared_job_settings_tab.py, _handle_queue_parameters_update)

Anything else is never read again. So a hook returning {"parameters": {"Frames": "1-10"}} or {"CondaPackages": ...} misspelled as condaPackages produces zero feedback and zero effect — the dialog simply opens with the artist's original values. The Note below covers this from the UI-field angle ("hooks do not set the Job-specific settings tab"), but not the mechanism: the failure is silent even for a name the author believed was a valid queue parameter, and CondaChannels/RezPackages only work because the queue happens to define them.

Two things that would help a hook author here:

  • Say explicitly that only deadline:* job properties and names matching queue parameters defined on the target queue take effect; other names are ignored without error.
  • Note that RezPackages / CondaPackages are seeded by the submitter as mayaIO-<ver> deadline_cloud_for_maya / maya=<ver>.* maya-openjd=<ver>.* and that a hook returning them replaces the whole string rather than appending — so a hook that overrides CondaPackages and omits maya-openjd produces a job that cannot run.

Signed-off-by: Leon Li <2182521+leon-li-inspire@users.noreply.github.com>
@leon-li-inspire
leon-li-inspire force-pushed the feature/pre-gui-hook-docs branch from da86af9 to 23d8543 Compare August 18, 2026 23:26
Comment thread README.md
`deadline >= 0.60.2` (the client version this package depends on), which ships the pre-GUI hook API.
For Maya, hooks are sourced only from the directory named by the `DEADLINE_HOOKS_DIR` environment
variable — Maya has no on-disk job bundle at pre-GUI time, so bundle-sourced hooks do not apply. They
complement the `preSubmission` / `postSubmission` hooks that run at submit time (see [Submission

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph says pre-GUI hooks are "shared across DCC submitters", but the upstream client documentation this section links to states the opposite — and one of the two is wrong in a way that will mislead studio pipeline authors.

aws-deadline/deadline-cloud/docs/submission-hooks.md says, under Pre-GUI Hooks:

Supported only by deadline bundle gui-submit. Pre-GUI hooks run on the standalone GUI submitter. They do not run in in-application (DCC) submitters such as Maya, Nuke, or Blender — those build their submission dialog directly and do not invoke the pre-GUI phase.

and again in its support matrix:

  • In-application (DCC) submitters — pre-submission and post-submission hooks. The pre-GUI phase is not run by DCC submitters.

So as of the current client docs, Maya is the first and only DCC submitter wiring up run_pre_gui_hooks — the mechanism lives in the shared client library, but no other DCC invokes it. "Shared across DCC submitters" reads as "already works in Nuke/Blender too", which is not true today.

Two concrete consequences worth fixing:

  1. Reword to something like "the pre-GUI hook mechanism lives in the shared client library; the Maya submitter is currently the only DCC submitter that invokes it" — so a studio does not deploy one DEADLINE_HOOKS_DIR expecting the preGUI entries to fire from Nuke/Blender as well. Note the failure mode is silent: the other DCCs simply never call the pre-GUI phase, so there is no error to debug.
  2. Since the hooks directory is shared, hooks.yaml preGUI entries will run for deadline bundle gui-submit and Maya, but nothing else. If the hook branches on submitterName (Maya passes "maya"), that is worth mentioning here, because a single studio-wide hooks dir is exactly the deployment this section recommends.

It would also be good to get the upstream doc updated in the same breath, otherwise the two READMEs contradict each other for whoever reads both.

Comment thread README.md

Pre-GUI hooks are provided by the [AWS Deadline Cloud client library][deadline-cloud-client] and are
shared across DCC submitters; the Maya submitter invokes them each time you open it. They require
`deadline >= 0.60.2` (the client version this package depends on), which ships the pre-GUI hook API.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deadline >= 0.60.2 version floor stated here disagrees with the code comment in the submitter, and the README appears to be the wrong one.

src/deadline/maya_submitter/maya_render_submitter.py:318-320 justifies the lazy import with:

this ships in deadline-cloud 0.60.1+, and a top-level import would break importing this module — and every unit test that collects it — against older deadline-cloud releases.

I checked upstream: src/deadline/client/ui/pre_gui_hooks.py exists at tag 0.60.1 (and 0.60.2) but 404s at 0.60.0, so the code comment’s 0.60.1+ is the accurate floor for the API itself. pyproject.toml:33 pins deadline >= 0.60.2,< 0.61, which is the floor for this package’s dependency — a stricter constraint that happens to be satisfied, not the API’s requirement.

The parenthetical "(the client version this package depends on), which ships the pre-GUI hook API" conflates the two, which is what makes it misleading: it reads as "0.60.2 is where the API landed". Suggest either dropping the causal claim — e.g. "requires deadline >= 0.60.2, per this package’s dependency pin; the pre-GUI hook API itself landed in 0.60.1" — or just saying the API requires 0.60.1+ and this package pins 0.60.2+.

This matters more than typical doc nits because the import is lazy specifically to tolerate older clients. Anyone reasoning about which client versions degrade gracefully (vs. raising ImportError from inside show_maya_render_submitter, after the progress dialog has already been closed at line 305) needs the real floor. Also worth reconciling the two so they do not drift further apart.

Comment thread README.md
A pre-GUI hook receives the current submission metadata as JSON on **stdin** and returns the fields
it wants to override as JSON on **stdout**. Recognized keys are `name`, `description`, and
`parameters` (a map of parameter name → value). `deadline:`-prefixed keys map to shared job
properties such as `deadline:priority`, `deadline:maxFailedTasksCount`, and

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phrase "deadline:-prefixed keys map to shared job properties such as" implies an open, forgiving set. It is actually a closed set, and an unrecognized deadline: key is a hard crash that prevents the submitter from opening.

In the client, SharedJobSettingsWidget.__init__ loops over the shared values and calls set_parameter_value for every deadline:-prefixed name, with no try/except:

for name, value in initial_shared_parameter_values.items():
    if name.startswith("deadline:"):
        self.set_parameter_value({"name": name, "value": value})

and set_parameter_value ends its if/elif chain with:

else:
    raise KeyError(parameter_name)

Only five names are accepted: deadline:targetTaskRunStatus, deadline:maxFailedTasksCount, deadline:maxRetriesPerTask, deadline:priority, deadline:maxWorkerCount.

So the failure mode for a typo is not "ignored" — apply_pre_gui_output routes any deadline:-prefixed name into shared_parameter_values unconditionally (it only checks the prefix), and the KeyError then escapes SubmitJobToDeadlineDialog construction at maya_render_submitter.py:349. That is after the cancel except DeadlineOperationCanceled at line 337, so it lands in the caller’s gui_error_handler and the dialog never opens.

The trap is concrete for Maya specifically: the sticky-settings field is named initial_status (data_classes.py:50), so deadline:initialStatus is a very natural guess — and it is wrong; the accepted name is deadline:targetTaskRunStatus. Same for deadline:maxWorkerCount vs. the max_worker_count field. A hook author guessing from the dataclass gets a broken submitter, not a no-op.

Suggest listing the five accepted keys explicitly (they are cheap to enumerate) and stating that any other deadline:-prefixed name raises an error that prevents the dialog from opening. Two related points worth a line:

  • Values are fed straight into Qt spin boxes via setValue, so "deadline:priority": "75" (string instead of int) is also a failure rather than a coercion — the example at line 199 gets this right but nothing says the types are strict.
  • deadline:priority is where a hook can set priority successfully, which is a useful contrast to the pre-GUI priority metadata field being hardcoded to 50 on the input side.

Comment thread README.md
> **Note:** pre-GUI hooks set the shared job properties above; they do **not** set the Maya render
> options on the `Job-specific settings` tab (render layers, cameras, frame range, output path,
> project directory, renderer, etc.). Those are initialized from the Maya scene's render settings and
> the per-scene sticky settings, and are edited in the submitter UI.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Note explains what hooks do not set, but omits a side effect that will surprise studios: hook-supplied values get persisted into the per-scene sticky settings file on submit, so they keep applying even after the hook is removed.

The chain:

  1. apply_pre_gui_output writes name / description directly onto the Maya settings dataclass (initial_settings.name = ...).
  2. name and description are both metadata={"sticky": True} (data_classes.py:46-47), as are priority, initial_status, max_failed_tasks_count, max_retries_per_task, max_worker_count.
  3. On submit, on_create_job_bundle_callback calls settings.save_sticky_settings(Scene.name()) (maya_render_submitter.py:179), writing every sticky field to <scene>.deadline_render_settings.json.
  4. Next open with load_sticky_setting=True calls load_sticky_settings before hooks run (_set_render_setting at line 225, hooks at line 328), so the hook-written name/description come back as the baseline.

Consequences worth documenting:

  • A hook that stamps a name like "MyStudio Shot 010" (exactly the example above) permanently overwrites the artist’s own sticky job name for that scene. Disable the hook and the stamped value persists in the JSON file — it does not revert.
  • The sticky file lives next to the scene (Path(scene).with_suffix(".deadline_render_settings.json")), so it typically follows the scene into version control / shared project dirs and propagates to other artists.
  • The two mechanisms silently fight for the same fields. Since hooks apply after sticky load, the hook always wins on each open — which is probably intended for name, but means an artist can never make a manual priority/name change stick while the hook is deployed.

Note this asymmetry: deadline:-prefixed parameters go into shared_parameter_values, not onto the dataclass, so they only reach the sticky file indirectly via update_settings writeback from the dialog widgets — whereas name/description are written onto the dataclass unconditionally, even if the artist never touches the dialog.

A short sentence here noting that hook-set name/description are saved into the scene’s sticky settings on submit and persist after the hook is removed would save a confusing support ticket.

Comment thread README.md
- C:/deadline-hooks/pregui_hook.py
timeout: 60
```
**Tip:** point `command` at a clean system Python interpreter, not Maya's bundled `mayapy` —

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two problems with this hooks.yaml example, both of which produce a broken setup rather than an obvious error.

1. The args entry duplicates the hooks dir, defeating relative paths. The example hard-codes C:/deadline-hooks/pregui_hook.py as an absolute arg while DEADLINE_HOOKS_DIR is already C:\deadline-hooks. The client resolves relative args against the hooks directory:

def _resolve_args(self, args):
    for arg in args:
        if not _os.path.isabs(arg):
            relative_path = _os.path.join(self._script_resolve_dir, arg)
            if _os.path.exists(relative_path): ...

So args: [pregui_hook.py] is the portable form, and is what the upstream doc uses (args: [prefill.py]). As written, the example silently couples hooks.yaml to one hard-coded install path — move the directory (or deploy to Linux artists, where this example is the only one given) and the hook fails with Hook command not found / a non-zero exit, which per the client blocks the dialog from opening.

2. command is Windows-only, but step 2 documented both platforms. Step 2 gives setx and export variants; step 3 then gives only a C:/Program Files/Python311/python.exe command. A macOS/Linux artist copying this gets an absolute path that fails _os.path.isfile, raising Hook command not found. Worth adding the python3 form — which is also what makes point 1 matter, since python3 resolves via shutil.which.

Also, on the Tip about mayapy: the underlying rule is more useful than the specific example. Per the client, anything on stdout that is not the JSON contract breaks the hook (stdout is captured whole and parsed; stderr is what gets streamed as progress). So the guidance is "never write anything but the JSON object to stdout — use stderr for logging" and mayapy’s banner is one instance. A hook author using a clean python3 but calling a library that prints to stdout hits the identical failure, and the current phrasing suggests the interpreter choice alone fixes it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on-maintainers Waiting on the maintainers to review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant