{#- data-theme-mode is present ONLY when web.theme named a concrete theme id, i.e. the deployment pinned light/dark rather than just a palette. Its absence is meaningful: it tells theme-manager.js's hub to leave the mode on 'auto' and follow the operator's OS. Never emit it empty. -#} {#- data-osprey-storage-scope is likewise present ONLY on a multi-user mount (/u//), where every user shares one origin and therefore one localStorage. It is THE source of truth for the storage namespace — JS storage sites read this attribute and never parse the URL. Its absence means single-user: keys stay unscoped, exactly as they were. Never emit it empty. See resolve_storage_scope() in app.py. -#} {#- data-header-bar / data-status-bar are present ONLY as "hidden", when the effective bar layout hides that bar. They are stamped here, with the other pre-paint layout facts, because each changes .shell-body's height: a page that learned it from JS would paint the bar and then reflow the whole shell under it on every single load. Absence means the bar is shown. -#} {#- data-bar-context is what this deployment OFFERS, in the vocabulary bar-catalog.js's available(ctx) predicates ask in — always present, and the only place the browser learns these facts. bar-sync.js reads it and hands it to bar-layout.js's normalize(); it used to infer the same three answers from the page, which made a deployment that offers an item but does not place it look like one that cannot render it, and that drop latches the stored layout read-only for the session. JSON in an attribute, exactly as the shells carry data-bar-options; SINGLE-quoted because Jinja's tojson escapes ' (and < > &) but leaves " alone. -#} {#- data-panel-labels is the registry's roster of built-in panel labels, which panel-catalog.js reads at module load. It is stamped rather than fetched because /api/panels answers for the ENABLED panels only and resolves after that module's array is built, so it can never name the full roster the rail's catalog list needs. Same single-quoted JSON, for the same reason. -#} OSPREY Web Terminal {#- ===== Bar items: the adopted chrome ===================================== Both bars are item HOSTS: an ordered run of `.bar-item` shells, emitted below from the effective layout (app.py's bar_render_plan()). Most item bodies are built by JS, keyed by type, so the same code runs at first paint and when the operator drags the item in later. These five are the exception. Every one of them is resolved BY ID by some other module — #docs-link, #command-palette-btn, #display-menu-settings, #logout-btn, the identity trigger and menu — so they are rendered on EVERY request whichever way the layout falls: into their shell when the layout places them, into #bar-item-pool at the end of this document when it does not. A removed item must never make an id go dark; the module looking it up cannot tell "the operator took this out of the bar" from "this build is broken". That is why they live in one macro rather than inline: the shell run and the pool render the same block from the same place, so the two can never drift into rendering different markup for the same item. -#} {% macro bar_body(type) -%} {%- if type == 'logo' -%} {%- elif type == 'identity' -%} {#- Where the deployment knows a user, this chip is the identity menu's trigger: operators read the name in the corner as "who am I / where am I" and reach for it to leave. It opens a popover holding the identity and Log out. Without a user (single-user terminals) there is nothing to open, so it stays the plain label it has always been. The popover is rendered here rather than built on demand: `#logout-btn` is looked up BY ID by app.js's initLogoutButton(), so it has to be in the DOM while the menu is closed. Hidden by CSS, not by absence. The command palette's Log out does not go through this button: it reads `data-landing-url` off , so it works with this item removed. -#} {% if terminal_user %}
{% elif app_name %}{{ app_name }}{% endif %} {%- elif type == 'search' -%} {%- elif type == 'display' -%} {% if terminal_user and landing_url %} {% endif %} {%- elif type == 'docs' -%} {%- endif -%} {%- endmacro %}
{%- for item in bar_header %}
{% if item.adopted %}{{ bar_body(item.type) }}{% endif %}
{%- endfor %}
Session Connected
⚙ Settings

Files the agent reads at the start of every session: what it knows, and who it delegates to. Guidance it follows, not a limit enforced.

Programs the runtime runs itself around every tool call. A hook can block a call before it executes, independent of the agent's decision.

Notes the agent writes for itself between sessions.

This deployment's own config.yml — connectors, approval policy, service wiring. Saving restarts the session.

Apply Settings?
Applying settings will restart the terminal session. Any running processes will be terminated.