Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
165e368
unreviewed: refactor(proto): share the parameter definition with engines
appaquet Nov 12, 2026
1e00509
unreviewed: refactor(backend): move engines onto the shared parameter…
appaquet Nov 12, 2026
f40398b
unreviewed: refactor(catalog): declare engine parameter visibility
appaquet Nov 12, 2026
5a800b3
unreviewed: refactor(frontend): read engine parameters through the sh…
appaquet Nov 12, 2026
a344d5a
unreviewed: feat(proto): add profile visibility overrides for engine …
appaquet Nov 12, 2026
0fce17a
unreviewed: feat(backend): validate profile visibility overrides
appaquet Nov 12, 2026
72e43bc
unreviewed: feat(frontend): apply profile visibility overrides to eng…
appaquet Nov 12, 2026
94bb3d3
unreviewed: test(backend): expect the reported apple gpu model
appaquet Nov 12, 2026
7e3cffd
unreviewed: docs(catalog): describe shared parameter visibility and p…
appaquet Nov 12, 2026
50d35e5
unreviewed: docs(catalog): write operator-facing parameter descriptions
appaquet Nov 12, 2026
c7460b5
unreviewed: feat(frontend): add a field primitive with a help popover
appaquet Nov 12, 2026
3237f88
unreviewed: feat(frontend): move deploy dialog help into field popovers
appaquet Nov 12, 2026
8285d55
unreviewed: feat(backend): let profiles and engines make any paramete…
appaquet Nov 12, 2026
33f70eb
unreviewed: feat(frontend): put deploy dialogs on the generic steps
appaquet Nov 12, 2026
02427e0
unreviewed: feat(proto): add text and secret parameters and secret at…
appaquet Nov 12, 2026
2f7e142
unreviewed: feat(backend): generate and retain secret app parameters
appaquet Nov 12, 2026
7e6e457
unreviewed: feat(backend): print deployment parameters in dotc applic…
appaquet Nov 12, 2026
2ab7132
unreviewed: feat(catalog): make the hermes login deployment parameters
appaquet Nov 12, 2026
9f8ec32
unreviewed: feat(frontend): add secret fields and the app parameters …
appaquet Nov 12, 2026
25934aa
unreviewed: feat(proto): add the bcrypt secret form
appaquet Nov 12, 2026
d8fe156
unreviewed: feat(backend): add the bcrypt secret form
appaquet Nov 12, 2026
0cbac16
unreviewed: feat(catalog): make the n8n login deployment parameters
appaquet Nov 12, 2026
a9da000
unreviewed: docs(*): state the deployment secret rule in the specs
appaquet Nov 12, 2026
39e0d2c
unreviewed: feat(backend): reject credential literals in the master c…
appaquet Nov 12, 2026
f581af3
unreviewed: feat(frontend): mask the upstream model api key
appaquet Nov 12, 2026
19a7801
unreviewed: feat(catalog): turn on the open webui login with deployme…
appaquet Nov 13, 2026
6ea0884
unreviewed: feat(proto): retain engine secrets and profile settings i…
appaquet Nov 13, 2026
c8ee20a
unreviewed: feat(backend): accept secret engine parameters
appaquet Nov 13, 2026
344bc0c
unreviewed: feat(backend): print engine parameters in dotc model show
appaquet Nov 13, 2026
47b4d23
unreviewed: feat(frontend): list engine parameters in the model sidebar
appaquet Nov 13, 2026
8478e06
unreviewed: feat(proto): declare storage placements and carry the cho…
appaquet Nov 13, 2026
2d20a9b
unreviewed: feat(backend): declare storage placements and choose one …
appaquet Nov 13, 2026
bc4383e
unreviewed: feat(catalog): declare storage placements; comfyui models…
appaquet Nov 13, 2026
bb71758
unreviewed: docs(*): describe storage placements in the specs
appaquet Nov 13, 2026
4ae0c83
unreviewed: feat(frontend): choose storage placements in the app depl…
appaquet Nov 13, 2026
3cd7349
unreviewed: feat(proto): enable bindings by a boolean parameter; drop…
appaquet Nov 13, 2026
e39719b
unreviewed: feat(backend): enable app bindings by a boolean parameter…
appaquet Nov 13, 2026
dd3e926
unreviewed: feat(catalog): make the open webui login optional; trace …
appaquet Nov 13, 2026
36028a5
unreviewed: feat(frontend): drop parameter value tags; show the secre…
appaquet Nov 13, 2026
fa986f4
unreviewed: docs(*): describe bindings enabled by a boolean parameter
appaquet Nov 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ in the same change that adds, removes or renames a folder it lists.
apart from site or development additions.
- **model-local engine configuration**: one model's launch recipe on one engine (artifact bindings,
approved engine artifacts, request kinds, sizing, hardware support).
- **model profile**: a preset of defaults for one engine configuration; never holds total context
or context per request.
- **model profile**: a preset of defaults and engine parameter visibility overrides for one engine
configuration; never holds a total context or context per request value.
- **engine release**: one version of an engine (llama.cpp, vLLM) and the parameters it exposes.
An **engine artifact** is one runnable build of it.
- **hardware class**: a kind of execution hardware, nothing model-specific. **Hardware support** is
Expand Down
6 changes: 3 additions & 3 deletions apps/comfyui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

* [`Dockerfile`](Dockerfile) builds the upstream source at `COMFYUI_REV` in
[`docker-image.nix`](docker-image.nix). [`entrypoint.sh`](entrypoint.sh) prepares the deployment's
storage, which mounts on ComfyUI's base directory. The shared models storage mounts on the base
directory's models folder.
storage, which mounts on ComfyUI's base directory. The models storage, shared by the app or per
deployment, mounts on the base directory's models folder.
* The download node in [`custom_nodes/dotcore_model_downloads`](custom_nodes/dotcore_model_downloads)
decides which missing-model downloads are allowed. Read it before changing download behavior. It
ships in the image, outside the storage, so each image version brings its own copy.
Expand Down Expand Up @@ -36,7 +36,7 @@
frontend still handing the dialog's downloads to it.
2. Gated, on an NVIDIA host: give the Docker application execution target the accelerator device,
deploy ComfyUI, and open the endpoint the console reports.
3. Place a small checkpoint in the shared models storage, then queue one workflow from the editor.
3. Place a small checkpoint in the models storage, then queue one workflow from the editor.
4. The queue completes the workflow, `/system_stats` reports the accelerator, and the deployment's
inspection attributes accelerator memory to its service. The placed checkpoint and the
generated image are still on storage after a restart, and the placed checkpoint is still there
Expand Down
14 changes: 8 additions & 6 deletions apps/comfyui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ video.
* Open it from the console.
* When a workflow needs a model you don't have, the editor offers to download it onto the server.
Public models from Hugging Face and Civitai work. Models that need a login don't; download them
yourself and place them in the shared models storage.
* Downloaded models live in storage shared by every ComfyUI deployment on the node. They survive
restarts and removing a deployment, and stay until the site is reset or an operator removes them.
yourself and place them in the models storage.
* By default, downloaded models live in storage shared by every ComfyUI deployment on the node.
They survive restarts and removing a deployment, and stay until the site is reset or an operator
removes them. Choosing "This deployment" for models in Advanced keeps them with the deployment
and deletes them at teardown.
* Custom nodes, inputs, outputs and user state live in the deployment's own storage. Removing the
deployment deletes them.

## Good to know

* It has no login, and custom nodes can run any code. Use it on a trusted network only.
* Deployments on one node share their models, so one deployment can place a model file, including
formats that run code when loaded, that another loads. Each already runs as root without a login,
so this grants no new authority.
* With shared models, deployments on one node share them, so one deployment can place a model file,
including formats that run code when loaded, that another loads. Each already runs as root without
a login, so this grants no new authority.
* It uses an NVIDIA GPU when the machine has one (driver 580 or newer), and the CPU otherwise, as
on a Mac.
* Keep the VRAM mode setting on `auto`. The other modes need an NVIDIA GPU.
Expand Down
13 changes: 7 additions & 6 deletions apps/hermes/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
its data. Read it for what it checks and sets. Its placeholder key `dotcore-no-key` is not a
secret: Hermes lists models only for a provider that has a key.
* The dashboard refuses a non-loopback bind without a login, and the Chat page's WebSockets work
only behind it. The catalog sets Hermes' `basic` login through literal bindings. Its username and
password are deliberate public placeholders, shown in the catalog `notes`, the same for every
deployment; they are not a leaked secret. They set no session secret, so a restart logs users out.
only behind it. The catalog sets Hermes' `basic` login from two parameters: a username (default
`admin`) and a generated secret password, bound to the environment. Hermes hashes the password in
memory and never writes it to its configuration. They set no session secret, so a restart logs
users out.
Its test reaches the login and chat through a published port, never from inside the container,
which sees loopback.
* The catalog declares no storage binding, so `/opt/data` is container-local on every platform.
Expand All @@ -32,10 +33,10 @@
## Validate

1. `just image-test`: against the image tagged `dotcore/hermes:dev`, the startup wrapper's
configuration and refusals, gateway readiness, the Dotcore provider selection, and the login and
Chat page WebSocket through a published port, as a browser reaches them.
configuration and refusals, gateway readiness, the Dotcore provider selection, and the login (with a
generated password) and Chat page WebSocket through a published port, as a browser reaches them.
2. Deploy Hermes with a linked inference route and open the dashboard after readiness, logging in
with the login from the console's app panel: Dotcore is the selected provider and the selectable
with the login from the deployment's sidebar: Dotcore is the selected provider and the selectable
model is the route's current name.
3. Open the dashboard's Chat page and send one prompt; the backend log shows
`POST /v1/chat/completions` with that route name as `model_id`. Rename the route and check the
Expand Down
6 changes: 2 additions & 4 deletions apps/hermes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ web dashboard.
## Using it

* Open the dashboard from the console. Its address stays the same for the deployment's life.
* Log in with the username and password shown in the console's app panel.
* Log in with the username and password in the deployment's sidebar. The password is generated at
deploy unless you type one.
* Chat with the agent on the dashboard's Chat page.
* Link an inference route to make it the default model. Without one, pick a route in the dashboard
before chatting.

## Good to know

* The login is the same for every deployment, so it doesn't protect the dashboard from anyone who
can reach it.
* The chat runs the agent with full tool and terminal access inside its container.
* Restarting the app logs you out.
* Dotcore doesn't manage its credentials or secrets.
* The Hermes agent API is off.
* Hermes keeps its data (sessions, memory, settings) inside the app. It is lost when the app is
redeployed or recreated.
Expand Down
17 changes: 14 additions & 3 deletions apps/hermes/image-workflow.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { randomInt } from "node:crypto";
import { readFileSync } from "node:fs";
import {
chmod,
Expand Down Expand Up @@ -40,10 +41,10 @@ const INVALID_STARTUPS = [
['http://127.0.0.1:50052/"/v1', ROUTE],
[INFERENCE_URL, "Fixture route"],
];
// The login the catalog sets for the dashboard: deliberate public placeholders, the same for every
// deployment.
// The login the catalog binds for the dashboard: the username's default and a generated-style
// password (32 alphanumeric characters) that differs on every run.
const LOGIN_USERNAME = "admin";
const LOGIN_PASSWORD = "dotcore";
const LOGIN_PASSWORD = randomAlphanumeric(32);
const BASE_IMAGE = dockerfileBaseImage(
readFileSync(new URL("./Dockerfile", import.meta.url), "utf8"),
/^nousresearch\/hermes-agent@sha256:[a-f0-9]{64}$/,
Expand Down Expand Up @@ -394,3 +395,13 @@ print(f"gateway running, pid {state['pid']}, dashboard 200")
`;

console.log(JSON.stringify(await verifyHermesImage(), null, 2));

/** Returns a random string of letters and digits, like a generated secret parameter. */
function randomAlphanumeric(length) {
const alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return Array.from(
{ length },
() => alphabet[randomInt(alphabet.length)],
).join("");
}
4 changes: 2 additions & 2 deletions apps/n8n/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

* [`docker-image.lock.json`](docker-image.lock.json) pins the upstream image; nothing is built here.
* The catalog declaration owns the start command, which imports the `Dotcore Inference` credential,
the fixed owner login and n8n's settings. Read it before changing them. The command stays on one
n8n's settings and the owner login (email and password parameters; the password is bound in bcrypt form because n8n accepts only a hash). Read it before changing them. The command stays on one
line because the Docker runtime rejects control characters.
* Webhook and editor URLs are fixed from the node's host and port when the deployment is created.
* A deployment keeps the declaration `notes` it was created with.
Expand All @@ -17,7 +17,7 @@

## Validate

1. On a Docker apps site, deploy a model and n8n, open the endpoint the console shows, and sign in.
1. On a Docker apps site, deploy a model and n8n, open the endpoint the console shows, and sign in with the sidebar login; a second deployment gets a different generated password and `admin` is refused.
2. Credentials lists one `Dotcore Inference`; an OpenAI Chat Model node using it lists the site's
routes, and one execution reaches a route (backend log `POST /v1/chat/completions` with that
route as `model_id`).
Expand Down
4 changes: 2 additions & 2 deletions apps/n8n/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

## Using it

* Open it from the console and sign in with the login it shows (`admin@dotcore.local` / `admin`).
* Open it from the console and sign in with the email and password in the deployment's sidebar. Set them when you deploy, or
leave the password empty to get a generated one.
* A ready-made `Dotcore Inference` credential connects n8n's OpenAI nodes to your models.
* In the OpenAI node's "Message a model", turn off the "Store" option. Dotcore doesn't store
responses, so the request fails with it on.
Expand All @@ -17,7 +18,6 @@

## Good to know

* The login is fixed and public, so keep the app on a trusted network.
* Workflows, credentials and settings live in the deployment's data. Losing it loses them.
* Telemetry, version notifications and the AI Assistant are off.

Expand Down
18 changes: 15 additions & 3 deletions apps/open-webui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
## How it is built

* [`docker-image.lock.json`](docker-image.lock.json) pins the upstream image; nothing is built here.
* `WEBUI_AUTH` is off. Configuration bindings set every Open WebUI environment value, persistent
configuration is off, and `OPENAI_API_BASE_URL` gets the site's inference endpoint. Data lives at
* Login is off by default, and sign-up is always off. The `require-login` parameter drives
`WEBUI_AUTH`, and only the admin email and password bindings depend on it: with login off they are
not set at all, because Open WebUI creates the admin from them even with login off and then
refuses visitors with an "existing users" error.
* With login on, Open WebUI creates the admin only when its data folder has no user, so login needs
a fresh data folder, which each deployment has. A data folder opened with login off holds a default
admin that stays valid and skips the parameters' admin. `WEBUI_ADMIN_NAME`, `WEBUI_SECRET_KEY` and
`DEFAULT_USER_ROLE` stay unbound.
* Configuration bindings set every Open WebUI environment value, persistent configuration is off,
and `OPENAI_API_BASE_URL` gets the site's inference endpoint. Data lives at
`/app/backend/data`.

## Update
Expand All @@ -15,4 +23,8 @@
## Validate

1. On a Docker apps site, deploy a model and Open WebUI, open the endpoint the console shows.
2. The model list shows the site's routes; one chat returns an answer.
2. With login off (the default), the app opens straight into the chat, and the container has no
admin email or password variable.
3. Deploy again with "Require login" on: sign in with the sidebar's email and password;
unauthenticated access is refused.
4. The model list shows the site's routes; one chat returns an answer.
9 changes: 7 additions & 2 deletions apps/open-webui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

## Using it

* Open it from the console. It lists the site's inference routes as models.
* Open it from the console. Login is off by default, so it opens straight into the chat. It lists
the site's inference routes as models.
* To require login, turn on "Require login" when you deploy, then sign in with the email and
password in the deployment's sidebar.

## Good to know

* It has no login. Anyone who can reach it can use it.
* The admin email and password apply only when login is required. Sign-up is closed.
* The password is the admin's initial one. If you change it inside Open WebUI, the sidebar still
shows the old one.
* Each start re-applies the settings Dotcore sets, so changes you make to them in the app don't
last.
* Chats and settings live in the deployment's data.
Expand Down
49 changes: 49 additions & 0 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading