Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
145 commits
Select commit Hold shift + click to select a range
c45d1f2
docs: AI-native machine-readable layer (llms.txt, raw markdown, copy-…
MagicLex Jul 31, 2026
f9f0f82
mcp: read-only docs MCP server (search / get_page / sections / list)
MagicLex Jul 31, 2026
2b6f293
docs: enable mermaid diagrams (pymdownx.superfences custom_fences)
MagicLex Jul 31, 2026
2d89bd3
docs: fix wrong config defaults for superset and trino
MagicLex Jul 31, 2026
26dfce2
docs: fix delivery guarantee, at-most-once should be exactly-once
MagicLex Jul 31, 2026
7debe60
docs: concepts keystone (FTI, AI systems, read/serve path) + home red…
MagicLex Jul 31, 2026
bff34e4
docs: generated reference pages for config variables and REST status …
MagicLex Jul 31, 2026
baa3108
docs: SaaS is run.hopsworks.ai, drop 'serverless' and app.hopsworks.ai
MagicLex Jul 31, 2026
e47af4a
docs: new platform architecture diagram, theme-adaptive inline SVG
MagicLex Jul 31, 2026
a66bee8
docs: make the architecture diagram a clickable navigation map
MagicLex Jul 31, 2026
efcd5a9
docs: shared clickable-SVG diagram kit; FTI diagram is now a clickabl…
MagicLex Jul 31, 2026
7212966
docs: feature store architecture as a clickable SVG diagram
MagicLex Jul 31, 2026
561d64d
docs: explanatory concept diagrams (drift, point-in-time join, versio…
MagicLex Jul 31, 2026
90ab0ff
docs: H1 on every concept page, demote orphan headings
MagicLex Jul 31, 2026
db36938
docs: reframe Prediction Services as AI Systems, add Deployment API
MagicLex Jul 31, 2026
1feb14e
docs: fix two book contradictions, skew and deployment versioning
MagicLex Jul 31, 2026
b9a034e
docs: standardise on 'vector index', not 'vector database'
MagicLex Jul 31, 2026
6cb9674
docs: merge duplicated concept pages (monitoring, versioning, connector)
MagicLex Jul 31, 2026
cbe31ef
docs: reorder Concepts nav into dependency order
MagicLex Jul 31, 2026
89db6ab
docs: Tier-2 book additions on the read/serve and model path
MagicLex Jul 31, 2026
8117092
docs: define MLOps, draw the lineage chain, name concept drift
MagicLex Jul 31, 2026
c6fa361
docs: new concept pages for streaming pipelines and agents/LLM
MagicLex Jul 31, 2026
7c104f0
docs: Tier-3 corrections (get_feature_vector order, TTL, validation, …
MagicLex Jul 31, 2026
585d9fd
docs: standardize all kit diagrams, add MIT/MDT/ODT taxonomy SVG
MagicLex Jul 31, 2026
911434e
docs: re-cut all data_transformations diagrams onto the kit
MagicLex Jul 31, 2026
04fcb67
docs: re-cut every remaining concept diagram onto the kit
MagicLex Jul 31, 2026
2beb03e
docs: visual refurbish aligned to the product design system
MagicLex Jul 31, 2026
dbe4d67
docs: flat header and legible search, per the flat design system
MagicLex Jul 31, 2026
f1cb5f8
docs: slim the top chrome (header + tabs)
MagicLex Jul 31, 2026
d4f3138
docs: left-sidebar navigation mimicking the app, drop top tabs
MagicLex Jul 31, 2026
42f351f
docs: clean sidebar, drop the floating grey box
MagicLex Jul 31, 2026
5994f6d
docs: remove dead CSS after the nav rework
MagicLex Jul 31, 2026
dad0ca3
docs: drill-in navigation, AI-agents page, and chrome fixes
MagicLex Aug 4, 2026
abb4e89
mcp-server: hosted streamable-HTTP transport
MagicLex Aug 4, 2026
08c1e83
docs: drop unused brewer_* config vars from the generated reference
MagicLex Aug 4, 2026
2dc421c
docs: home hero, quick cards and interactive first-feature-vector ste…
MagicLex Aug 5, 2026
5bcdc0d
docs: recapture auth screenshots on a live 5.x cluster, drop dead 2FA…
MagicLex Aug 5, 2026
6963c91
docs: home stepper heading speaks the product, not the API
MagicLex Aug 5, 2026
621af24
docs: recapture jobs and airflow screenshots on a live 5.x cluster
MagicLex Aug 5, 2026
0934cf4
docs: recapture alert configuration screenshots, fix typo
MagicLex Aug 5, 2026
a0aedb3
docs: hopsworks-version screenshot follows the version to the help menu
MagicLex Aug 5, 2026
f68ade1
docs: recapture jupyter and python environment screenshots
MagicLex Aug 5, 2026
5d7d7bf
docs: recapture admin screenshots on a live 5.x cluster
MagicLex Aug 5, 2026
d4742a3
docs: recapture feature store screenshots on a live 5.x cluster
MagicLex Aug 5, 2026
d40ec8b
docs: recapture model serving and registry screenshots on a live 5.x …
MagicLex Aug 5, 2026
56a5818
docs: serving guides follow the current deployment form
MagicLex Aug 5, 2026
2b82ff6
docs: capture group-to-project mapping screenshots
MagicLex Aug 5, 2026
551f18f
docs: recapture git and feature group screenshots on a live 5.x cluster
MagicLex Aug 5, 2026
fa82b59
docs: rebuild jobs GIFs as crisp frame-based animations
MagicLex Aug 5, 2026
360875a
docs: border every content image and extend diagram zoom to screenshots
MagicLex Aug 5, 2026
fef28db
docs: design-system notes cover image borders and zoom
MagicLex Aug 5, 2026
9d7e421
docs: recapture project, sharing, tags, secrets and api-key screenshots
MagicLex Aug 5, 2026
26e68fa
docs: recapture trino and superset screenshots on live services
MagicLex Aug 5, 2026
baa640d
docs: feature group creation is API-only, UI shows them in the Catalog
MagicLex Aug 5, 2026
50ffb99
docs: document the project terminal
MagicLex Aug 5, 2026
591e26f
docs: admin guides follow the cluster-settings sidebar and current forms
MagicLex Aug 5, 2026
b85be61
docs: drop the last em dashes in the admin tree
MagicLex Aug 5, 2026
c628f75
docs: guides follow the 5.x UI flows
MagicLex Aug 5, 2026
993e3ed
docs: finish the UI-flow alignment sweep
MagicLex Aug 5, 2026
dcecf62
docs: rebuild python and jupyter GIFs on the live 5.x UI
MagicLex Aug 5, 2026
6c30981
docs: clear pre-existing em dashes in the job scheduling guides
MagicLex Aug 5, 2026
9a726fa
docs: repo-wide em dash sweep, zero left in Markdown
MagicLex Aug 5, 2026
31b8b95
docs: scheduler screenshot and project GIFs from the live cluster
MagicLex Aug 5, 2026
0a82217
docs: fix table style lint in the mcp-server readme
MagicLex Aug 5, 2026
e9a8cda
docs: markdownlint ignores venvs and build output
MagicLex Aug 5, 2026
31585c5
docs: markdownlint-cli2 config ignores vendored envs; fix list indent
MagicLex Aug 5, 2026
fdb0c1c
docs: hops-viz animated diagram kit, streaming pipeline showcase
MagicLex Aug 19, 2026
f5c33cc
docs: hops-viz survives the zoom overlay
MagicLex Aug 19, 2026
3236d24
docs: diagrams become files; hops-viz gets a readability floor
MagicLex Aug 19, 2026
756b5ff
docs: diagram figures get the content-image border
MagicLex Aug 19, 2026
9b24bde
docs: extract all 43 inline kit figures to diagrams/
MagicLex Aug 19, 2026
2ff53cb
docs: caveat for zoom-overlay clone scoping
MagicLex Aug 19, 2026
d89be28
docs: write_apis diagrams to animated hops-viz scenes
MagicLex Aug 19, 2026
a28fdf1
docs: fg_overview storage diagram to an animated hops-viz scene
MagicLex Aug 19, 2026
9014a0a
docs: width is earned, not default
MagicLex Aug 19, 2026
234f451
docs: point-in-time join diagram becomes an animated scene
MagicLex Aug 19, 2026
fe81685
docs: feature vector assembly becomes an animated scene
MagicLex Aug 19, 2026
7550ce8
docs: offline-online skew as a two-act animated scene
MagicLex Aug 19, 2026
18efe60
docs: data versioning diagram becomes an animated scene
MagicLex Aug 19, 2026
cc9ffa7
docs: feature pipeline diagram becomes an animated scene
MagicLex Aug 19, 2026
5200826
docs: tick the three navigational charts, static by charter
MagicLex Aug 19, 2026
aa3220a
docs: on-demand feature diagram becomes an animated scene
MagicLex Aug 19, 2026
9d7a342
docs: tick dev capability maps, static by design
MagicLex Aug 20, 2026
d241a7e
docs: external feature group diagram becomes an animated scene
MagicLex Aug 20, 2026
e521c09
docs: validation and statistics diagram becomes an animated scene
MagicLex Aug 20, 2026
fc16a73
docs: tick fv_overview, structural figures stay static
MagicLex Aug 20, 2026
22f815a
docs: drift detection diagram becomes an animated scene
MagicLex Aug 20, 2026
1d0b7dc
docs: model serving diagram becomes an animated scene
MagicLex Aug 20, 2026
1185267
docs: tick structural concept figures, static by design
MagicLex Aug 20, 2026
5c1768c
docs: the MLOps flywheel actually turns
MagicLex Aug 20, 2026
de5003c
docs: vector index diagram becomes an animated scene
MagicLex Aug 20, 2026
141810b
docs: agent retrieval diagram becomes an animated scene
MagicLex Aug 20, 2026
3ec016d
docs: triage search page images, live UI screenshots kept
MagicLex Aug 20, 2026
b202cc1
docs: inventory complete, guides and setup are all UI captures
MagicLex Aug 20, 2026
eebe2bb
docs: inventory 148/148, home figure is the nav chart
MagicLex Aug 20, 2026
7956cf1
docs: consolidate home FTI diagram onto the hops-viz kit
MagicLex Aug 20, 2026
48f2be2
docs: nav cleanup, viz fit-width, platform chart portrait
MagicLex Aug 20, 2026
28b31ff
docs: convert 5 concept diagrams to the viz kit (portrait)
MagicLex Aug 20, 2026
2bd8470
docs: convert data_transformations diagrams to the viz kit (portrait)
MagicLex Aug 20, 2026
a0084e0
docs: convert feature view + pipeline diagrams to the viz kit (portrait)
MagicLex Aug 20, 2026
7807814
docs: convert prediction-service diagrams to the viz kit (portrait)
MagicLex Aug 20, 2026
e5f621f
docs: replace the provenance screenshot with a viz lineage diagram
MagicLex Aug 20, 2026
f9ce1ad
docs: convert projects-and-governance to the viz kit (portrait)
MagicLex Aug 20, 2026
7f4cf26
docs: rework governance, convert cicd diagrams, fit the zoom overlay
MagicLex Aug 20, 2026
836a2ac
docs: convert data-storage sharing, side-exit CI/CD arrows
MagicLex Aug 20, 2026
e773e9b
docs: update diagram-refresh worklist (18/25 converted, icon retrofit…
MagicLex Aug 20, 2026
f40094b
docs: drill nav shows two adjacent levels, not one
MagicLex Aug 25, 2026
6c6cf9b
docs: extend the diagram viz kit and wiring
MagicLex Aug 26, 2026
a5843ef
docs: add the viz overlap checker and update the diagram charter
MagicLex Aug 26, 2026
ed2c19e
docs: refresh diagrams to the viz kit
MagicLex Aug 26, 2026
2cdf8fe
docs: wire diagram includes into concept pages
MagicLex Aug 26, 2026
04de274
docs: update llm-copy button and mcp-server readme
MagicLex Aug 26, 2026
295c0bd
docs: content updates across guides, setup, and home
MagicLex Aug 26, 2026
356eaa5
Merge remote-tracking branch 'origin/main' into docs-ai-native-artifacts
MagicLex Aug 26, 2026
aeeae88
docs: drill nav shows your level plus the one above it
MagicLex Aug 26, 2026
0447629
docs: two-tier TOC hierarchy, fix off-by-one active heading
MagicLex Aug 26, 2026
5754c0b
docs: enforce diagram layout mechanics, re-grid diagrams, fix arrowheads
MagicLex Aug 26, 2026
f78ba08
docs: bake elbow edges statically, add stabilo labels, enforce collis…
MagicLex Sep 1, 2026
9b1185f
docs: stabilo-tag over-line labels across diagrams
MagicLex Sep 2, 2026
a8a7990
docs: fg_overview table anatomy figure, parity review ledger
MagicLex Sep 2, 2026
9c62a27
docs: stream API figure mirrors the original, HSFS out of all diagrams
MagicLex Sep 2, 2026
b6988e2
docs: feature pipeline figures redrawn, band titles and icons centred…
MagicLex Sep 2, 2026
6941a75
docs: schema versioning as code, feature vector as notebook cells, re…
MagicLex Sep 2, 2026
806f679
docs: refactor checkpoint: diagrams, nav, and refreshed UI captures
MagicLex Sep 7, 2026
93c4d03
Merge origin/main into docs-ai-native-artifacts
MagicLex Sep 7, 2026
9e3abb1
docs: quickstart as one hot path, code blocks as terminal windows
MagicLex Sep 8, 2026
313b4bf
docs: search scope switch, All or API only, and a code-aware search s…
MagicLex Sep 8, 2026
0dfd4bd
docs: search scope follows the navigation, no switch
MagicLex Sep 8, 2026
69b04e3
docs: search scope as a Docs | API prefix on the header search field
MagicLex Sep 8, 2026
ad93f7e
docs: search scope prefix above the input so it takes the click
MagicLex Sep 8, 2026
872501a
docs: search scope highlight radius matches the nav pill and tabs
MagicLex Sep 8, 2026
549dd47
docs: active search keeps the Quartz pill, results panel closes it wi…
MagicLex Sep 8, 2026
ce566ee
docs: on-demand figure code box restored, stepper rail numerals, exte…
MagicLex Sep 8, 2026
af38dd3
docs: create external feature group, UI captures redone on 5.0
MagicLex Sep 8, 2026
3bf2368
docs: dltHub ingestion guide, UI captures redone on 5.0 and a loading…
MagicLex Sep 8, 2026
6c469e6
agent docs: UI capture guide and helpers
MagicLex Sep 8, 2026
6d2d65f
docs: remove the ArrowFlight Server with DuckDB setup page
MagicLex Sep 8, 2026
13f90ea
docs: quickstart Python tab says where the Python lines run
MagicLex Sep 8, 2026
1d4a154
docs: quickstart Python path runs hops setup first, login picks the c…
MagicLex Sep 8, 2026
ed3f28d
docs: stepper tabs link in every direction, no text-transform on link…
MagicLex Sep 8, 2026
68ad447
docs: quickstart CLI steps pin --version 1 on insert and get
MagicLex Sep 8, 2026
62440cd
Merge origin/main into docs-ai-native-artifacts
MagicLex Sep 11, 2026
9f0f6e4
docs: api admonitions on the deployment schema and feature view deplo…
MagicLex Sep 11, 2026
2ac986f
docs: single space after the card list markers on the registry and da…
MagicLex Sep 11, 2026
a625dc2
docs: two blank lines after the import in the projects index snippet
MagicLex Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ uv tool install md-snakeoil && snakeoil --line-length 88 --rules "E,F,B,C4,ISC,P

- @docs/README.md — full command reference, content structure, and links to detail docs
- @docs/content.md — writing conventions, code blocks, linking, and assets
- @docs/design-system.md — visual language: tokens, logo, nav, search, diagrams; read before any CSS/nav/visual change
- @docs/captures.md — UI screenshots and GIFs: where the pixels come from, browser session, scoping rules, helpers
- @docs/caveats/README.md — known gotchas; add new ones as separate files in this folder
2 changes: 2 additions & 0 deletions .claude/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ Do not write prose in API reference pages in this repo — edit the docstrings i
## More

- @docs/content.md — writing conventions, Python code blocks, linking, assets
- @docs/design-system.md — visual language: tokens, logo, nav, search, diagrams
- @docs/captures.md — how UI screenshots and GIFs are taken: cluster, browser session, scoping, crop and GIF helpers
- @docs/caveats/README.md — known gotchas; add new ones as separate files
43 changes: 43 additions & 0 deletions .claude/docs/capture_crop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Crop a viewport screenshot to a rectangle measured in the page.

Usage:
capture_crop.py <viewport.png> <out.png> '<rect json>' [--margin F] [--top-min Y]

The rect is the JSON an `agent-browser eval` returns from getBoundingClientRect
plus the viewport width: {"x", "y", "w", "h", "iw"}. The device scale is
derived from the screenshot width divided by "iw", so any viewport works.
--margin is a fraction of the rectangle added on every side (0.03 for a card,
0.18 for a modal). --top-min clamps the crop's top edge in css pixels, used to
keep a sticky header out of the shot.
"""

import argparse
import json

from PIL import Image


def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("src")
ap.add_argument("out")
ap.add_argument("rect")
ap.add_argument("--margin", type=float, default=0.0)
ap.add_argument("--top-min", type=float, default=None)
a = ap.parse_args()
rect = json.loads(a.rect)
im = Image.open(a.src)
dpr = im.width / rect["iw"]
x, y, w, h = rect["x"], rect["y"], rect["w"], rect["h"]
mx, my = w * a.margin, h * a.margin
x0, y0, x1, y1 = x - mx, y - my, x + w + mx, y + h + my
if a.top_min is not None:
y0 = max(y0, a.top_min)
box = tuple(round(v * dpr) for v in (max(0, x0), max(0, y0), x1, y1))
box = (box[0], box[1], min(im.width, box[2]), min(im.height, box[3]))
im.crop(box).save(a.out)
print(a.out, Image.open(a.out).size)


if __name__ == "__main__":
main()
55 changes: 55 additions & 0 deletions .claude/docs/capture_gif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Assemble a GIF from viewport screenshots of successive UI states.

Usage:
capture_gif.py <frames dir> <out.gif> <margin fraction> [bottom margin fraction]

The directory holds pairs frame_NN.png (a viewport screenshot) and
rect_NN.json (the card's rectangle in that frame: x, y, w, h, iw, plus a
"state" label; a frame without a state is skipped). Every frame is cropped
around the largest rectangle seen, so the card can move between frames,
halved to 1x and quantised. The first frame holds longer, the last longest.
"""

import glob
import json
import os
import sys

from PIL import Image


def main() -> None:
d, out, margin = sys.argv[1], sys.argv[2], float(sys.argv[3])
bottom = float(sys.argv[4]) if len(sys.argv) > 4 else margin
frames = []
for rf in sorted(glob.glob(os.path.join(d, "rect_*.json"))):
with open(rf) as fh:
r = json.load(fh)
if not isinstance(r, dict) or r.get("state") is None:
continue
p = rf.replace("rect_", "frame_").replace(".json", ".png")
if os.path.exists(p):
frames.append((p, r))
if not frames:
raise SystemExit("no frame_NN.png / rect_NN.json pairs with a state")
first = Image.open(frames[0][0])
dpr = first.width / frames[0][1]["iw"]
w = max(r["w"] for _, r in frames)
h = max(r["h"] for _, r in frames)
mx, my, mb = w * margin, h * margin, h * bottom

def box(r: dict) -> tuple[int, ...]:
return tuple(round(v * dpr) for v in (r["x"] - mx, r["y"] - my, r["x"] + w + mx, r["y"] + h + mb))

imgs = []
for p, r in frames:
im = Image.open(p).convert("RGB").crop(box(r))
im = im.resize((im.width // 2, im.height // 2), Image.LANCZOS)
imgs.append(im.quantize(colors=128, method=Image.Quantize.MEDIANCUT))
durations = [1500] + [900] * max(0, len(imgs) - 2) + ([2500] if len(imgs) > 1 else [])
imgs[0].save(out, save_all=True, append_images=imgs[1:], duration=durations, loop=0, optimize=True)
print(len(imgs), "frames", imgs[0].size, os.path.getsize(out) // 1024, "KB")


if __name__ == "__main__":
main()
83 changes: 83 additions & 0 deletions .claude/docs/captures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# UI Captures

How screenshots and GIFs of the Hopsworks app are taken for the docs.
Diagrams are a different species, see the Diagrams section of `design-system.md`; this file is only about pixels of the real product.
Read it before replacing a screenshot, and follow `parity-review.md` for which pages still carry old-UI captures.

## Where the pixels come from

A dev cluster running the target release, never a mock-up and never an older release than the docs version.
The demo project should look like a real project (a `fraud_detection` style project with feature groups, a deployment, an app, a couple of jobs) so that lists are not empty and names read as real.
When the state a page describes does not exist, fake it on the cluster or in the browser rather than drawing it: create the object through the SDK or the REST API, stub a response with `agent-browser network route`, or write rows straight into the metadata database.
Leave harmless fixtures in place for the next agent and write them down in memory; revert anything that changes cluster behaviour (admin variables, auth toggles, Helm values).

## Browser session

Use `agent-browser` with a dedicated session and profile directory, headed, ignoring the self-signed certificate:

```bash
agent-browser --session hopsdocs --profile "$SCRATCH/chrome-profile" --headed --ignore-https-errors open https://<app>/
agent-browser --session hopsdocs set viewport 1440 900 2
```

Never capture from the user's personal Chrome profile: its active tab moves under you.
The viewport is 1440 css wide at device scale 2, so every capture is 2x; raise the height (1440 by 1500) when a card must fit in one shot.
A restart of the app (Helm, Payara) logs the session out; ask the user to log in again in the headed window rather than storing credentials.

Read the page with `eval`, click with native `click` on an element you gave an id to in a prior `eval`, and use `find role button click --name "..."` for primary buttons that ignore untrusted clicks (the wizard "Next" buttons do).
Radix radio groups switch on a click of their `label`, or with arrow keys after focusing a radio.
Custom dropdowns: click the combobox input, then click the `[role=option]`.

## What a capture shows

Scope the capture to the panel the prose talks about, with some UI around it so the reader sees it is inside the app: never a full app shell, never a bare widget on white.
Rules that have held on every page so far:

- A form or card: the card from its header to the last relevant block, plus about 3 percent margin on each side; clamp the top to the sticky header's bottom edge so the header never bleeds in.
- A row range inside a long form (a settings block): cut at the midpoint of the gap to the neighbouring rows so no neighbour is sliced.
- A modal: the dialog with an 18 percent margin so the blurred page behind it shows it is a modal.
- A list: the toolbar (primary button and filter) and the table, nothing else.
- Blur the focused control before shooting (`document.activeElement.blur()`), or the caret and focus ring end up in the docs.
- Fill placeholders with values that read as real (`transactions`, `fraud_source`, a cursor field, a job name), never `test` or `asdf`.

Measure the rectangle in the page, take a viewport screenshot, and crop:

```bash
R=$(agent-browser --session hopsdocs eval '(()=>{const e=document.querySelector("#the-card");e.scrollIntoView({block:"start"});window.scrollBy(0,-60);const r=e.getBoundingClientRect();return JSON.stringify({x:r.x,y:r.y,w:r.width,h:r.height,iw:innerWidth})})()' | tail -1)
R=${R#\"}; R=${R%\"}; R=${R//\\/}
agent-browser --session hopsdocs screenshot /tmp/vp.png
python3 .claude/docs/capture_crop.py /tmp/vp.png docs/assets/images/<section>/<name>.png "$R" --margin 0.03 --top-min 72
```

`capture_crop.py` derives the device scale from the rectangle's `iw`, so it works for any viewport.
The rectangle is measured after scrolling, because element screenshots lose their target when React re-renders.

## GIFs

A GIF is for a sequence the reader would otherwise have to imagine (a server starting, a job moving through states).
Record one viewport screenshot per state and, next to it, the rectangle of the card in that frame (the card moves when a sidebar collapses), then assemble:

```bash
python3 .claude/docs/capture_gif.py "$FRAMES_DIR" docs/assets/images/<section>/<name>.gif 0.05
```

Frames are cropped around the largest card rectangle, halved to 1x and quantised, so a five-frame GIF stays under a few hundred kilobytes.
The first frame holds longer, the last one longest.

## Naming and placement

Images live in `docs/assets/images/<section>/` mirroring the page (`guides/fs/feature_group/`, `guides/jobs/`, `admin/oauth2/`).
Keep the existing file name when replacing an old capture so no page reference changes; delete captures you cannot redo rather than leaving the old UI in, and drop their figure from the page.
Alt text says what the reader is looking at, one sentence, no "screenshot of".

## Faking states, worked examples

- A feature the cluster does not enable: stub the availability check in the browser, `agent-browser network route "**/isAvailable*" --body '{"enabled":true}'`, then create the objects through the API.
- Feature monitoring results: register synthetic statistics per commit window through the SDK so the chart has distinct points.
- A data source that browses tables: the built-in HopsFS and JDBC sources never enable "Next: Select Tables"; create a `SQL` source against the cluster's own MySQL (`mysqld.hopsworks.svc.cluster.local`) with a dedicated read-only user and a small database of realistic tables.
- Session-capacity badges, alerts, admin panels: the memory file for the dev cluster lists the switches; check it before searching.

## Before you are done

Open the page on the served site and look at the capture in the column: if the text is not readable at the docs width, the scope was too wide, not the resolution too low.
Tick the page in `parity-review.md` with a note on what was redone.
5 changes: 5 additions & 0 deletions .claude/docs/caveats/diagram-inside-content-tabs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Diagram fragments inside content tabs

A `--8<--` diagram include placed inside a `=== "Tab"` block is re-parsed as Markdown by the tabbed extension, unlike a top-level include which passes through as one raw HTML block. Two things break: a blank line inside the fragment ends the HTML block, so the SVG's inner tags render as paragraph text; and a `$` inside the scene JSON (`$label`, `$ms`) is picked up by the arithmatex math extension, which injects a `<span>` into the script and the scene fails to parse (no toggle, no step bar).

Write tabbed fragments with no blank lines, and spell the scene's dollar keys as JSON unicode escapes, `"\u0024label"` and `"\u0024ms"`, which decode to the same keys. The flywheel figures on the AI Systems page are the reference. Top-level includes need neither.
5 changes: 5 additions & 0 deletions .claude/docs/caveats/linked-tabs-text-transform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Linked tabs and CSS text-transform

Material links content tabs (`content.tabs.link`) by comparing label text with `innerText`. `innerText` carries CSS text transforms on rendered elements but not on hidden ones, so a label uppercased by CSS reads "PYTHON" where it is visible and "Python" in every hidden set, and a switch made on the visible set never reaches the others (only labels that are already uppercase, like "CLI", keep working). The home stepper hit this: switching on step 3 left steps 1 and 2 on the old tab.

Never put `text-transform` on a linked tab label. Write the label text as it should display and style the rest (font, weight, size).
5 changes: 5 additions & 0 deletions .claude/docs/caveats/tabs-inside-raw-html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Content tabs inside raw HTML blocks

A `=== "Tab"` set placed in a `<div markdown>` that sits inside an outer raw HTML block without its own `markdown` attribute renders as literal text: md_in_html only parses nested `markdown` divs when the outermost raw block carries the attribute too. Code fences still render there because superfences is a preprocessor, so the breakage is easy to miss (the home stepper looked fine until tabs went in).

Put `markdown` on the outermost wrapper as well (`<div class="hops-steps" markdown>`); raw children without the attribute, such as the stepper's button rail, pass through untouched.
7 changes: 7 additions & 0 deletions .claude/docs/caveats/zoom-overlay-clone-scoping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Zoom overlay clones escape .md-typeset scoping

The diagram zoom overlay (`diagram-zoom.js`) clones the whole figure into `document.body`, outside `.md-typeset`.
Any CSS scoped under `.md-typeset` (design tokens especially) stops matching the clone, and a failed `var()` in an SVG `fill` computes to black, so the zoomed diagram renders as black boxes while the inline one looks fine.

Scope diagram tokens and component rules to the figure class alone (`.hops-viz`, `.hops-diagram`), never through `.md-typeset`, and pin theme-dependent values inside `.hops-zoom-stage` because the overlay panel is always dark whatever the page scheme.
Animated figures get restarted on the clone by `hops-viz.js` listening for the `hops-zoom-open` event; keep that event dispatch when touching `diagram-zoom.js`.
21 changes: 21 additions & 0 deletions .claude/docs/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,24 @@ Avoid relative file paths as links (e.g. `../other.md`) — they break after mik
## Assets

Images go in `docs/assets/images/<section>/` matching the section of the content that uses them.

## API reference box

A guide ends its code walkthrough (or each walkthrough section, when a page has several) with an `api` admonition, never a bare `### API Reference` heading with loose links.
Rows are the mkdocstrings symbol badge plus the autoref, exactly what the reader lands on in the API section: entry-point methods first, then each class with the methods the guide called nested under it, then any external doc with a muted `docs` badge.
No prose per row.
The last line is the single CTA into the Python API, with the `../` depth matching the page URL.

```markdown
!!! api "API reference"

- <code class="doc-symbol doc-symbol-method"></code> [`Project.get_kafka_api`][hopsworks_common.project.Project.get_kafka_api]
- <code class="doc-symbol doc-symbol-class"></code> [`KafkaApi`][hopsworks_common.core.kafka_api.KafkaApi]
- <code class="doc-symbol doc-symbol-method"></code> [`create_topic`][hopsworks_common.core.kafka_api.KafkaApi.create_topic]
- <code class="doc-symbol doc-symbol-docs"></code> [Kafka docs](https://kafka.apache.org/documentation/)

<a class="hops-api-cta" href="../../../../python-api/hopsworks/">Browse the full Python API :material-arrow-right:</a>
```

Badges: `class`, `method`, `function`, `attribute`, `docs`.
The `python-api/` root is not a page; link to `python-api/hopsworks/`.
Loading
Loading