GLM workspace defaults and model migration¶
The model picker uses the existing glm model (GLM-5.3-Flash). Its terminal
capability is enabled, while every other declared model inherits terminal: false.
GLM declares glm-terminal-pilot as its default terminal; native Open WebUI
selects it only when the current user can access that connection.
The former glm-terminal preset is removed from models.yaml and disabled in
place when found live. Its model record and saved conversations are not deleted.
To continue a conversation that used the retired alias, select the existing GLM
model; the migration does not rewrite any chat's history or selections.
Focused migration¶
Run scripts/sync_terminal_pilot.py to inspect the plan before applying it. The
script keeps its original filename so the existing operational entry point works.
Use --api-key-file for a local token file, or --snapshot-file for an offline
snapshot. --json prints a summary without model prompts or metadata;
--plan-file writes complete request bodies to a new mode-0600 file.
The ordered plan performs these changes only:
- Preserve global model metadata and its unset
terminalId, and set its terminal capability to false. A nonempty global terminal default is refused instead of spreading an owner's connection choice to other models. The deployed API uses a one-key partial import ofmodels.default_metadataafter verifying the flat config namespace. Model order, pinned models, and other config keys stay intact. - Set terminal to false on other observed model records, including undeclared
records and inactive records returned by export. For
glm-terminal, also setis_active: false, preserving its prompt, tools, and sharing grants. - Set terminal to true on the existing
glmrecord and apply the explicitly declareddefault_terminal_idandworkspace_layouttometa.terminalIdandmeta.workspaceLayout. Preserve the name, route, tool IDs, prompt, sharing grants, suggestions, and all other capabilities. Keep existing parameters; only an explicitfunction_calling: legacyis changed tonative, which native terminal tools require. Missing function-calling configuration already uses the native path and is preserved.
The script never creates or deletes a model, and never writes a chat. It refuses
to replace a missing/inactive GLM model or overwrite a record that changed after
planning. Before enabling GLM and after applying, it reads the effective model
list to catch non-GLM terminal access, including synthetic models. Model export
can omit other owners' records, so visible record IDs are also fetched individually.
Each write must return an object, then a fresh read must match every written
field before the action counts as applied. A 200 response containing null is
a failure. On partial failure the script reports how many actions were verified,
the uncertain action, and those remaining. Re-fetch and review a new plan before
retrying; a failed request may still have reached the server.
For a read-only policy audit, run python3 scripts/sync_terminal_pilot.py --check
with the same credentials. It exits 1 on drift and never writes. The nightly
live-goals workflow runs this check to detect terminal access enabled through
later UI edits, including on undeclared models.
The broader scripts/sync_models.py --apply writes declared parameters, including
function_calling, and the allowlisted terminal: false default across every
declared model. Inspect its dry run first. Use the focused script above when only
the GLM terminal migration is intended.
Measured read-only after the focused migration on 2026-09-05: 49 live records passed terminal policy (48 denied, GLM enabled). The full model-sync dry run planned 0 creates and 0 updates, with 38 declared presets already current and 6 unresolvable existing GPT-5/mini/o3/o4-mini aliases. It separately reported 7 missing public grants (those 6 aliases and Inkling). That broader apply was not run. Resolve route/grant work separately rather than using a terminal migration to change unrelated model exposure.
The pinned Open WebUI version really does merge global defaults into
record-less entries: see
utils/models.py at the reviewed upstream commit.
The audit still inspects the effective /api/models metadata and fails closed
if it does not show denial; it does not assume that an absent response flag is
safe. Each models-default import also re-reads the entire models namespace,
checking pins, ordering and other keys alongside the changed metadata.
Model-specific defaults and user access¶
Open WebUI's default selection code
uses meta.terminalId to auto-select a terminal. Capability alone exposes the
selector. GLM deliberately declares the trial connection as its default; the
frontend checks that connection is available to the current user before attaching.
Users can disconnect it from the composer. The migration preserves saved chat
choices and never changes connection grants.
The request middleware
adds terminal tools only when a chat has selected a terminal and the model allows it.
The terminal connection's user/group grants remain the actual access control;
the existing public GLM model does not grant other users access to a private terminal.
default_terminal_id and workspace_layout are accepted only on individual model
declarations, never in global defaults or bundles. An absent key preserves any
hand-set value; the general model sync accepts explicit null to clear it. The
focused trial sync requires GLM's declared trial connection. Layout fields are validated against
the frontend schema: absolute POSIX filePath without traversal, boolean
terminalExpanded, terminalHeight from 80–800 px, and panelWidth from
300–1200 px. An optional terminalHeightRatio from 0.2–0.8 takes precedence
over the pixel height until the user drags the terminal divider. The service
does not require layout metadata or a patched frontend. Layout defaults have no
effect until the separate frontend support is deployed; terminal auto-selection
already exists natively.
Keep browser instructions on the terminal, not in GLM's system prompt. The
content of docker/open-terminal/terminal-info.md is a terminal-only appendix for
OPEN_TERMINAL_INFO: Open Terminal adds it to its generated /system prompt,
and Open WebUI fetches that prompt when the terminal is selected. No model
system_prompt_file is declared for this migration.
For rollback, keep the private before-snapshot/plan and restore only the fields this migration changed after checking for later edits. Re-enabling the old alias does not require recovering a deleted model or reconstructing conversations.