Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 13 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ only covers cloud-specific, non-obvious caveats.
- **Backend** (port 8080, base path `/api`): `bash scripts/start-backend.sh` (wraps
`./mvnw spring-boot:run`; it strips `SPRING_PROFILES_ACTIVE=prod` for local runs → dev mode).
- **Frontend** (port 3000): `npm run dev` (Vite proxies `/api` → 8080 and `/agent-api` → 8787).
- **Hermes Agent webui** (port 8787, optional): needed only for the sidebar **Agent** tab.
See caveats below for install + `HERMES_WEBUI_ALLOWED_ORIGINS`.
- **DeepSQL Agent API** (port 8787, optional): needed for the sidebar **Agent** tab.
Runtime is a customized Nous Hermes Agent; see caveats below for install +
`HERMES_WEBUI_ALLOWED_ORIGINS` (upstream env name).
- A demo target DB `demo_shop` (same Postgres server, sample `customers`/`products`/`orders`)
exists for exercising connection/schema features without an external database.

Expand Down Expand Up @@ -207,15 +208,19 @@ only covers cloud-specific, non-obvious caveats.
`DEEPSQL_CHAT_ENDPOINT=https://deepsql-selfhost-resource.cognitiveservices.azure.com/`,
`DEEPSQL_CHAT_MODEL=gpt-5.4` (deployment name), plus matching `DEEPSQL_EMBEDDING_*` with
`text-embedding-3-large`. Also set `AZURE_OPENAI_KEY` / `AZURE_OPENAI_ENDPOINT` aliases —
`hermes/install.sh` reads those. After changing LLM env, restart the backend
`agent/install.sh` reads those. After changing LLM env, restart the backend
(`scripts/start-backend.sh`); `/api/setup/status` should show `hasLlmConfig: true`.
- **Agent tab (Hermes) is optional but required for the in-app Agent chat UI.** Install via
- **Agent tab is optional but required for the in-app Agent chat UI.** The Agent tab
is DeepSQL’s own React (`AgentChatPanel`); it talks to the DeepSQL Agent HTTP API
on `:8787` (a heavily customized [Nous Hermes Agent](https://hermes-agent.nousresearch.com/)
runtime — see [`agent/README.md`](agent/README.md)). Install upstream via
`curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --non-interactive --skip-setup`,
symlink `~/.hermes/hermes-agent/.venv` → `venv` (DeepSQL's `hermes/install.sh` expects `.venv`),
then `bash hermes/install.sh`. Start the webui with
symlink `~/.hermes/hermes-agent/.venv` → `venv` (DeepSQLs `agent/install.sh` expects `.venv`),
then `bash agent/install.sh`. Start the agent API/webui with
`HERMES_WEBUI_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000`
(without this, Vite's Origin header makes Hermes return **403** "Cross-origin mismatch").
Webui listens on `:8787`; Vite proxies `/agent-api` → there.
(upstream env var; without it Vite’s Origin header yields **403** “Cross-origin mismatch”).
Listens on `:8787`; Vite proxies `/agent-api` → there. Profile cookie name
`hermes_profile` is an upstream contract — do not rename it in DeepSQL clients.
- **Before running backend tests that boot the Spring context** (e.g. `ApiSmokeTest`), stop
the running backend first — both use `ddl-auto=update` on the same `dba_agent` DB and can
deadlock on an `ALTER TABLE`. Test env vars are documented in `CLAUDE.md` (Testing).
Expand Down
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ src/ # Frontend (React)

docs/ # Documentation
mcp/ # DeepSQL Phase 1 MCP server (Node stdio wrapper around backend APIs)
agent/ # DeepSQL Agent customization (persona, skills, skins; customized Hermes runtime)
```

## MCP Server
Expand All @@ -103,10 +104,11 @@ mcp/ # DeepSQL Phase 1 MCP server (Node stdio wrapper around back

## Dashboard Generation (artifact model)

Dashboards are **generated by the embedded Hermes agent acting as a coding agent** — it writes the whole dashboard as a single self-contained HTML document, not a JSON spec. The earlier spec+renderer model (metrics/charts/tables + a `{{placeholder}}` substitution engine + `DashboardBuilder.js`) was thrown away: the rigid `col BETWEEN {{name}}` convention couldn't express real SQL (e.g. a Unix-epoch date filter → `near '{range.start}'` syntax errors) and boxed the agent in.
Dashboards are **generated by the embedded DeepSQL Agent acting as a coding agent**
(customized Hermes runtime — see [`agent/README.md`](agent/README.md)) — it writes the whole dashboard as a single self-contained HTML document, not a JSON spec. The earlier spec+renderer model (metrics/charts/tables + a `{{placeholder}}` substitution engine + `DashboardBuilder.js`) was thrown away: the rigid `col BETWEEN {{name}}` convention couldn't express real SQL (e.g. a Unix-epoch date filter → `near '{range.start}'` syntax errors) and boxed the agent in.

- `DashboardAgentService` is a thin broker: `ensureProfileForUser` → `ensureSession` (fresh session) → `sendAndAwait` with an **artifact contract**. The agent grounds on the brain/schema, verifies every query with `execute_sql`, then emits ONE HTML doc (in a ` ```html ` block). The broker extracts the HTML and returns `{version:3, renderMode:"artifact", title, html, trace}`, stored verbatim in `saved_dashboards.dashboardConfig`.
- The agent loads the **`dashboard-design` skill** (`hermes/skills/dashboard-design/SKILL.md`, v2 — artifact contract, the `deepsql.query` runtime, composition/UX rules, an **intent checklist**, and Unix-epoch date handling).
- The agent loads the **`dashboard-design` skill** (`agent/skills/dashboard-design/SKILL.md`, v2 — artifact contract, the `deepsql.query` runtime, composition/UX rules, an **intent checklist**, and Unix-epoch date handling).
- **Rendering + data access**: `DashboardArtifact.jsx` renders the HTML in a **sandboxed iframe** (`sandbox="allow-scripts"`, opaque origin + a strict CSP — no external network). The artifact fetches data only through an injected `deepsql.query(sql)` bridge that `postMessage`s to the parent; the parent calls **`POST /api/dashboards/query`** (`DashboardQueryController`), which is **read-only twice over** (`McpSqlGuardService.validateReadOnlySql` + `QueryExecutionContext.api` = `READ_ONLY_ONLY`) and access-scoped via `assertCanReadConnectionContent`. So the agent's code has full creative freedom while every query stays guarded and sandboxed. The bridge also auto-sizes the iframe and forwards runtime errors.
- Generation endpoints unchanged (`POST /api/dashboards/generate` + `/generate/stream`). `DashboardBuilder.js`/`DashboardInputs.js` remain only because `tabs/Core/PreviewTab.js` still uses them — the dashboard *creation* path no longer touches them.
- **Sharing**: both share types render a standalone read-only `DashboardViewer` (title + `DashboardArtifact` with an injected `queryFn`). Internal link `/dashboard-view/:id` (auth) uses the authed broker; public link `/share/dashboard/:token` (permitAll) uses `PublicDashboardController` (`GET /api/public/dashboards/{token}` + `/query`), which resolves only while `saved_dashboards.is_public` is true (revoke = flip it) and runs read-only + connection-scoped. `share_token`/`is_public` are set only via `POST|DELETE /api/saved-dashboards/{id}/share` (access-checked), never a general update. `ShareMenu.jsx` drives the UI. The public query path has its own nginx `dashq` limiter.
Expand Down
81 changes: 81 additions & 0 deletions agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# DeepSQL Agent

Source of truth for the **DeepSQL Agent** — DeepSQL’s DBA-specialized agent layer:
persona, skills, skins, and install overlays.

## Upstream disclosure

The runtime is a **heavily customized [Nous Hermes Agent](https://hermes-agent.nousresearch.com/)**
(plus its optional webui/TUI). DeepSQL does not ship a fork of that runtime in this
tree. Instead this directory is the product surface we own:

| DeepSQL customization | Purpose |
|-----------------------|---------|
| `SOUL.md` | DBA persona / always-on system prompt (grounding, RBAC, read-only defaults) |
| `skills/*/SKILL.md` | DBA procedures (BI query, schema, indexes, slow queries, workload, dashboards) |
| `skins/deepsql.yaml` | CLI/TUI skin |
| `webui/` | Optional overlay that rebrands a Hermes webui checkout to DeepSQL |
| `tui/` | Optional overlay that rebrands the Hermes TUI checkout to DeepSQL |
| `install.sh` / `distribution.yaml` | Idempotent install + enterprise profile distribution |

Upstream install paths and CLI names (`~/.hermes`, `hermes` binary, `HERMES_*` env
vars, `hermes_profile` cookie, skill frontmatter `metadata.hermes`) are **unchanged** —
those are contracts of the upstream engine. Product UI and docs refer to the
**DeepSQL Agent**, not Hermes.

The in-app Agent tab is DeepSQL’s own React (`AgentChatPanel`); it consumes the
agent HTTP API (`/agent-api/*`), not the Hermes webui skin.

## Contents

- `SOUL.md` — DBA persona. Encodes DeepSQL grounding discipline (`get_brain_context`
before SQL, table-qualified columns, business rules + anti-patterns, read-only by
default, two-step mutation confirm).
- `skills/<name>/SKILL.md` — procedural skills (agentskills.io format):
- `bi-query` — answer a data question with grounded, read-only SQL
- `schema-exploration` — map/describe a database
- `index-advisor` — recommend (and dry-run/apply) indexes via the workload-weighted advisor
- `slow-query-optimize` — diagnose + rewrite one slow query
- `workload-analysis` — hotspots, regressions, per-customer load, growth
- `dashboard-design` — HTML dashboard artifact contract for the coding-agent path
- `distribution.yaml` — profile distribution for `hermes profile install/update`
- `webui/`, `tui/`, `skins/` — optional branding overlays for upstream UIs

These mirror workflows the in-house `AgentOrchestrator` performed, re-expressed as
agent persona + skills over the DeepSQL MCP tools.

## Install (local / self-host)

1. Install the upstream agent runtime (see [AGENTS.md](../AGENTS.md) Cursor Cloud notes
or the [Hermes install docs](https://hermes-agent.nousresearch.com/)).
2. Apply DeepSQL customization (requires `AZURE_OPENAI_KEY` in the environment or
the repo `.env`):

```bash
bash agent/install.sh
```

It configures `~/.hermes/config.yaml` from this repo:

- **model** — Azure OpenAI via its OpenAI-compatible `…/openai/v1` endpoint (key from env/.env, never committed)
- **mcp_servers.deepsql** — this repo’s `mcp/deepsql-phase1-server.js`
- **skills.external_dirs** — this repo’s `agent/skills` (source of truth; must be a YAML list)
- **approvals.mode: smart**, **SOUL.md** persona, and disables host-affecting toolsets
(terminal/file/code/browser/computer_use) → a read-only `deepsql:*` + memory/todo/skills sandbox

Verify:

```bash
cd ~/.hermes/hermes-agent && uv run hermes mcp test deepsql # → Connected, DeepSQL tools
```

The DeepSQL MCP server and the Spring backend remain the DBA brain; the agent consumes them.
Optional upstream webui skin: see [`webui/`](webui/).

### Approval UX (operator note)

Because every exposed tool is read-only (`deepsql:*` reads; the one write tool,
`apply_index_recommendation`, is server-side `confirm`-gated; host toolsets disabled),
webui per-call approval prompts add friction without adding safety for this deployment.
Operators can enable session auto-approve (or per-tool “Always allow”) so DBA turns
flow without clicking. Left as a deliberate operator action, not a baked-in default.
5 changes: 3 additions & 2 deletions hermes/SOUL.md → agent/SOUL.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ before acting: `bi-query` (answer a data question), `schema-exploration`
## Voice

You are **DeepSQL**. Never refer to yourself, your skills, your memory, or your
runtime as "Hermes" — that is the underlying engine and is invisible to the
user. They are **DeepSQL skills**, the **DeepSQL agent**, the **DeepSQL brain**.
runtime as "Hermes" in user-facing replies — users see the **DeepSQL Agent**.
(Operators know the runtime is a customized Nous Hermes Agent; that detail stays
out of chat.) They are **DeepSQL skills**, the **DeepSQL agent**, the **DeepSQL brain**.
Don't surface internal filesystem paths (`~/.hermes/...`) or engine internals;
speak in DeepSQL product terms.

Expand Down
3 changes: 2 additions & 1 deletion hermes/distribution.yaml → agent/distribution.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# DeepSQL Agent profile distribution.
# DeepSQL Agent profile distribution (runs on the Nous Hermes Agent profile CLI).
# Enterprises install this per user: hermes profile install <git-url|dir> --name <profile>
# `hermes profile update <profile>` refreshes SOUL.md + skills/ WITHOUT touching
# the user's memory, sessions, .env, or config.yaml (their identity + history).
# `hermes_requires` is an upstream schema key — do not rename it.
name: deepsql-agent
version: 0.1.0
description: "DeepSQL DBA agent — grounded, read-only database assistant over the DeepSQL MCP tools (BI queries, schema exploration, index advice, slow-query optimization, workload analysis)."
Expand Down
15 changes: 9 additions & 6 deletions hermes/install.sh → agent/install.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
#!/usr/bin/env bash
# Reproducibly install the DBA customization into an agent home (~/.hermes).
# Idempotent: safe to re-run. Source of truth is this repo's hermes/ dir.
# Reproducibly install the DeepSQL Agent customization into an agent home (~/.hermes).
# Idempotent: safe to re-run. Source of truth is this repo's agent/ dir.
#
# Configures:
# - model: existing Azure OpenAI gpt-5.4 via its OpenAI-compatible v1 endpoint
# - mcp_servers.deepsql: the repo's DeepSQL MCP server (read-only DBA tools)
# - skills.external_dirs: this repo's hermes/skills (source of truth)
# - skills.external_dirs: this repo's agent/skills (source of truth)
# - approvals.mode: smart
# - SOUL.md: the DBA persona
# - disables host-affecting toolsets (terminal/file/code/browser/computer_use)
#
# Secrets are read from the environment (or the repo .env), never committed:
# AZURE_OPENAI_KEY, AZURE_OPENAI_ENDPOINT (endpoint defaults to the repo value)
#
# Upstream note: HERMES_HOME / hermes-agent / hermes CLI are contracts of the
# Nous Hermes Agent runtime this customization runs on — do not rename those.
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
Expand Down Expand Up @@ -50,14 +53,14 @@ cfg.setdefault("mcp_servers", {})["deepsql"] = {
"env": {"DEEPSQL_API_BASE_URL": "http://localhost:8080/api/",
"DEEPSQL_MCP_USER_ID": "deepsql-agent", "DEEPSQL_MCP_PROJECT_ID": "deepsql-agent"},
}
cfg.setdefault("skills", {})["external_dirs"] = [f"{repo}/hermes/skills"]
cfg.setdefault("skills", {})["external_dirs"] = [f"{repo}/agent/skills"]
cfg.setdefault("approvals", {})["mode"] = "smart"
cfg_path.write_text(yaml.safe_dump(cfg, sort_keys=False))
print(f" config.yaml updated ({cfg_path})")
PY

# Persona
cp "$REPO_ROOT/hermes/SOUL.md" "$HERMES_HOME/SOUL.md"
cp "$REPO_ROOT/agent/SOUL.md" "$HERMES_HOME/SOUL.md"
echo " SOUL.md installed"

# Scope to a read-only sandbox: disable host-affecting toolsets.
Expand All @@ -66,4 +69,4 @@ echo " SOUL.md installed"
>/dev/null 2>&1 ) || echo " (toolset disable skipped — disable manually with 'hermes tools disable ...')"
echo " host toolsets disabled (read-only deepsql + memory/todo/skills remain)"

echo "✓ DBA customization installed. Verify: (cd $AGENT_DIR && uv run hermes mcp test deepsql)"
echo "✓ DeepSQL Agent customization installed. Verify: (cd $AGENT_DIR && uv run hermes mcp test deepsql)"
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions hermes/tui/README.md → agent/tui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

The TUI's logo, hero art, and tagline live in the TUI **source**
(`ui-tui/src/banner.ts`, `ui-tui/src/components/branding.tsx`) and its default
skin in `hermes_cli/skin_engine.py` — not in a skin YAML. So rebranding to
"DeepSQL Agent" means editing those files in the agent checkout and rebuilding
the Node/Ink dist (like `hermes/webui/apply-overlay.sh` for the webui).
skin in `hermes_cli/skin_engine.py` (upstream module path) — not in a skin YAML.
So rebranding to "DeepSQL Agent" means editing those files in the agent checkout
and rebuilding the Node/Ink dist (like `agent/webui/apply-overlay.sh` for the webui).

Changing the *defaults* (not just our `deepsql` skin) also removes the brief
flash of default branding at startup — there's no default left to render before
Expand Down Expand Up @@ -61,7 +61,7 @@ const CADUCEUS_ART = [
## Colors

The wordmark color comes from the active skin's banner palette
([hermes/skins/deepsql.yaml](../skins/deepsql.yaml)) — kept in a tight grey
([agent/skins/deepsql.yaml](../skins/deepsql.yaml)) — kept in a tight grey
range so it reads as a subtle, understated grey rather than bright white.

## Productization note
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Rebrand the TUI to "DeepSQL Agent" in an agent checkout, then rebuild the
# Node/Ink dist. Idempotent. The TUI logo/tagline live in the TUI *source*
# (not the skin), so this overlay edits them and rebuilds — vendored
# customization, applied like hermes/webui/apply-overlay.sh.
# customization, applied like agent/webui/apply-overlay.sh.
#
# Handles the clean string edits (tagline, default-skin branding) + rebuild.
# The ASCII logo/hero blocks are in README.md (multi-line art doesn't sed
Expand Down Expand Up @@ -40,7 +40,7 @@ fi
if grep -q '\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x95\x97 \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x95\x97\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x95\x97' "$BANNER"; then
echo "= logo already DeepSQL wordmark"
else
echo "! logo not yet replaced — paste the DeepSQL LOGO_ART + CADUCEUS_ART from hermes/tui/README.md into ui-tui/src/banner.ts"
echo "! logo not yet replaced — paste the DeepSQL LOGO_ART + CADUCEUS_ART from agent/tui/README.md into ui-tui/src/banner.ts"
fi

# 4. Rebuild the TUI dist.
Expand Down
14 changes: 9 additions & 5 deletions hermes/webui/README.md → agent/webui/README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
# DeepSQL Agent WebUI — DBA skin (Phase 2)
# DeepSQL Agent WebUI — DBA skin (optional overlay)

Source of truth for branding the agent webui (the web chat surface that replaces the React `AgentView`) to the DBA Agent design.
Source of truth for branding an upstream agent webui checkout to the DeepSQL DBA
look. The in-app Agent tab uses DeepSQL’s own React UI; this overlay is only for
operators who run the upstream webui directly.

- `dba-skin.css` — a `data-skin="dba"` skin: minimal black/white/grey, Inter-first, flat surfaces, light + dark variants. Modeled on the built-in `graphite` skin.

## Install into a webui checkout

The webui is a separate cloned repo (default `~/.hermes/hermes-webui`). Apply the skin with the idempotent overlay script (safe to re-run, e.g. after re-pulling):
The webui is a separate cloned repo (default `~/.hermes/hermes-webui`, upstream
Nous Hermes Agent webui). Apply the skin with the idempotent overlay script
(safe to re-run, e.g. after re-pulling):

```bash
hermes/webui/apply-overlay.sh [path-to-webui] # default: ~/.hermes/hermes-webui
agent/webui/apply-overlay.sh [path-to-webui] # default: ~/.hermes/hermes-webui
```

It appends `dba-skin.css` to `static/style.css` and registers the skin in `static/boot.js` `_SKINS`, each guarded so re-runs are no-ops. Then reload the UI and select it: `/theme dba` then `/theme light` (or Settings → Appearance).

## Notes / follow-ups (Phase 2/3)
## Notes / follow-ups

- **Vendoring:** these are edits to a cloned repo and will be lost on re-pull. Productization should maintain this as a patch/overlay applied at deploy (or fork the webui) so the repo stays source of truth. Pin matching webui ↔ agent release trains (the webui couples to the agent by direct import).
- **Inter font:** the skin prefers `Inter` then falls back to system sans. For guaranteed Inter, bundle the webfont locally (don't depend on Google Fonts in a self-hosted deploy).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# so the clone's files can be regenerated after a re-pull.
#
# Usage: ./apply-overlay.sh [path-to-webui] (default: ~/.hermes/hermes-webui)
# Default path is the upstream Hermes webui install location (HERMES_HOME contract).
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand Down
2 changes: 1 addition & 1 deletion hermes/webui/dba-skin.css → agent/webui/dba-skin.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Minimal black/white/grey, Inter-first, flat surfaces (no shadows).
* Matches the DBA Agent design language. Light + dark variants.
* Install: append this file to the webui's static/style.css and register
* the skin in static/boot.js `_SKINS` (see hermes/webui/README.md).
* the skin in static/boot.js `_SKINS` (see agent/webui/README.md).
*/

:root[data-skin="dba"]{
Expand Down
Loading
Loading