Skip to content

docs: replace open-source self-hosting pages with Fish Audio Enterprise guides - #113

Open
leng-yue wants to merge 1 commit into
mainfrom
docs/enterprise-self-hosting
Open

docs: replace open-source self-hosting pages with Fish Audio Enterprise guides#113
leng-yue wants to merge 1 commit into
mainfrom
docs/enterprise-self-hosting

Conversation

@leng-yue

@leng-yue leng-yue commented Aug 3, 2026

Copy link
Copy Markdown
Member

Rewrites the Resources → Self-Hosting group so it documents self-hosted Fish Audio Enterprise instead of the open-source fish-speech local model setup.

Why

The old pages documented the open-source project, which is documented in its own repo. Keeping it here made the enterprise offering ambiguous.

Removed

Page Was
developer-guide/self-hosting/local-setup Conda/UV install of the open-source model
developer-guide/self-hosting/docker-deployment fishaudio/fish-speech container images
developer-guide/self-hosting/running-inference Local CLI/WebUI inference

All three now redirect to the new introduction, so existing inbound links keep working. No other page in the repo linked to them.

Added

Page Covers
introduction What self-hosted Fish Audio Enterprise is, why self-host, the three delivery forms (Online Helm / Offline Helm / Offline All-in-One) as a comparison table, what is and is not included, and how to get access
requirements GPU/CPU/RAM/disk baselines, cluster topology, shared storage, platform and GPU stack, network, All-in-One host requirements, preflight commands
registry-access Dashboard → deploy token → docker login / helm registry login / Kubernetes pull secret, plus token rotation and revocation
kubernetes Preflight, secrets, values, install, readiness, smoke test, upgrade, rollback, uninstall; online vs offline profile
all-in-one Single docker run, first-start compile, requests, reference voices, persistence, capacity, troubleshooting
air-gapped Mirroring images and charts across the gap, offline model assets, the signed local usage ledger and how it is verified and reconciled, and how to prove zero egress
operations Ownership, monitoring signals, scaling, backups, upgrade policy, troubleshooting, escalation

Connection values live in the dashboard, not the docs

This is a deliberate product decision. The registry host, Helm charts base, login username, team ID, deploy tokens, and the artifact list are rendered per team in the fish.audio dashboard under Developer → Self Host. The documentation never prints any of them. Every command uses an obvious placeholder (<registry-host>, <your-email>, <deploy-token>, <chart-ref>, <all-in-one-image>) and each page points the reader back to that dashboard page to copy the real value. Image tags are likewise taken from the Granted Artifacts card rather than hard-coded.

A /self-host redirect is added because the dashboard's Documentation button links there.

Source material was the enterprise deployment package. It has been sanitized: no customer name, no credentials, no internal hostnames or IPs, no customer-specific benchmark numbers, no build-specific image tags or digests.

Verification

  • npx mint dev — all seven pages return 200, render their content, and the nav group is correct. The three removed paths return 307.
  • npx mint broken-links — 22 broken links found, all pre-existing in .mintlify/skills/ and temp/; none in the changed files. (mint validate is not a command in the pinned CLI version, 1.0.0.)
  • prettier --check on the touched files passes. The rest of the repo is unformatted on main and was left alone.

Please do not merge yet — this needs review first. Auto-merge has not been enabled.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added comprehensive self-hosting guides for requirements, registry access, Kubernetes, All-in-One, air-gapped deployments, and ongoing operations.
    • Documented deployment setup, offline workflows, authentication, monitoring, scaling, backups, troubleshooting, and validation.
    • Reorganized self-hosting navigation and added redirects from legacy documentation paths.
    • Removed outdated standalone Docker, local model setup, and inference guides.

The Self-Hosting section documented the open-source fish-speech local model
setup, which is documented in its own project and made the enterprise offering
ambiguous. Replace it with documentation for self-hosted Fish Audio Enterprise.

Removed: local-setup, docker-deployment, running-inference (all three redirect
to the new introduction so existing links keep working).

Added: introduction, requirements, registry-access, kubernetes, all-in-one,
air-gapped, operations.

Connection values (registry host, chart base, login username, team ID) and
deploy tokens are rendered per team in the dashboard under Developer -> Self
Host, so the docs never print them and use placeholders instead. Also adds a
/self-host redirect for the dashboard's documentation link.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
hanabiaiinc 🟢 Ready View Preview Aug 3, 2026, 9:17 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Added a new self-hosting documentation set for Fish Audio Enterprise. It covers requirements, registry access, Kubernetes, All-in-One, air-gapped deployment, operations, navigation, and redirects. Legacy self-hosting guides were removed.

Changes

Self-hosting documentation

Layer / File(s) Summary
Self-hosting orientation and access
developer-guide/self-hosting/introduction.mdx, developer-guide/self-hosting/requirements.mdx, developer-guide/self-hosting/registry-access.mdx, docs.json, developer-guide/self-hosting/docker-deployment.mdx, developer-guide/self-hosting/local-setup.mdx, developer-guide/self-hosting/running-inference.mdx
Added deployment overviews, infrastructure requirements, registry authentication, navigation entries, and redirects. Removed the legacy Docker, local model, and inference guides.
Kubernetes deployment and operations
developer-guide/self-hosting/kubernetes.mdx, developer-guide/self-hosting/operations.mdx
Added installation, reference-voice staging, readiness checks, smoke tests, upgrades, rollbacks, monitoring, backups, troubleshooting, and escalation procedures.
All-in-One deployment flow
developer-guide/self-hosting/all-in-one.mdx
Added image loading, container startup, inference requests, reference voices, authentication, persistence, concurrency, operational commands, and troubleshooting guidance.
Air-gapped deployment and ledger validation
developer-guide/self-hosting/air-gapped.mdx
Added disconnected artifact transfer, offline model serving, signed usage ledger handling, retention, verification, and no-egress validation procedures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • fishaudio/docs#68: Updates related self-hosting documentation pages and transcript components.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes replacing open-source self-hosting documentation with Fish Audio Enterprise guides.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/enterprise-self-hosting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
developer-guide/self-hosting/all-in-one.mdx (1)

192-194: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Replace the ellipsis with a copy-ready command.

The snippet ends in ..., so a reader cannot run it. Show the flag inside the full run command, or state that you add the flag to the run command in the Run section.

Proposed fix
-docker run -e LIMIT_MODEL_CONCURRENCY=64 ...
+docker run -d --name fish-tts \
+  --gpus all \
+  --shm-size 16g --ulimit memlock=-1 --ulimit stack=67108864 \
+  -p 8088:8088 \
+  -v fish-tts-shared:/mnt/shared \
+  -e JWT_SECRET="$FISH_JWT_SECRET" \
+  -e LIMIT_MODEL_CONCURRENCY=64 \
+  --restart unless-stopped \
+  "$AIO_IMAGE"

As per coding guidelines: "Do not include untested code examples".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@developer-guide/self-hosting/all-in-one.mdx` around lines 192 - 194, Replace
the `docker run -e LIMIT_MODEL_CONCURRENCY=64 ...` snippet with a complete,
copy-ready command using only the documented image, options, and arguments from
the surrounding Run section; if those details are unavailable, remove the
command snippet and explicitly direct readers to add the environment flag to the
existing Run command without inventing untested syntax.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@developer-guide/self-hosting/air-gapped.mdx`:
- Around line 199-205: Update the air-gapped verification instructions to define
record_hash as covering the stored signed JSON serialization with deterministic
key ordering. Preserve that canonical serialization when storing the signed
record, and revise the recomputation command to remove jq’s trailing newline (or
pipe through printf '%s') so the hashed bytes exactly match the signed value.
- Around line 187-197: The verification command in the air-gapped ledger example
must write only the record_hash bytes, without a trailing newline; update the jq
extraction in the message-generation step accordingly. Also review the
rsa_pss_saltlen setting for supported customer OpenSSL versions, either choosing
a compatible value or documenting the required OpenSSL version for this command.

In `@developer-guide/self-hosting/kubernetes.mdx`:
- Around line 168-193: Update the verification command near the archive example
to use the same in-container mounted path that includes the namespace and
release segments as the documented archive location, or revise the
archive-location documentation to match the mounted root. Keep the reference
archive filename and edge API verification behavior unchanged.

In `@developer-guide/self-hosting/registry-access.mdx`:
- Around line 106-117: Update the “Create the Kubernetes pull secret” snippet to
create or apply the fish-audio namespace before creating the registry secret,
using an idempotent kubectl command and preserving the existing secret command
afterward.

---

Nitpick comments:
In `@developer-guide/self-hosting/all-in-one.mdx`:
- Around line 192-194: Replace the `docker run -e LIMIT_MODEL_CONCURRENCY=64
...` snippet with a complete, copy-ready command using only the documented
image, options, and arguments from the surrounding Run section; if those details
are unavailable, remove the command snippet and explicitly direct readers to add
the environment flag to the existing Run command without inventing untested
syntax.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: acf26baa-4cb0-4df9-a572-63a97f015b51

📥 Commits

Reviewing files that changed from the base of the PR and between 22780b1 and cfe12f0.

📒 Files selected for processing (11)
  • developer-guide/self-hosting/air-gapped.mdx
  • developer-guide/self-hosting/all-in-one.mdx
  • developer-guide/self-hosting/docker-deployment.mdx
  • developer-guide/self-hosting/introduction.mdx
  • developer-guide/self-hosting/kubernetes.mdx
  • developer-guide/self-hosting/local-setup.mdx
  • developer-guide/self-hosting/operations.mdx
  • developer-guide/self-hosting/registry-access.mdx
  • developer-guide/self-hosting/requirements.mdx
  • developer-guide/self-hosting/running-inference.mdx
  • docs.json
💤 Files with no reviewable changes (3)
  • developer-guide/self-hosting/running-inference.mdx
  • developer-guide/self-hosting/docker-deployment.mdx
  • developer-guide/self-hosting/local-setup.mdx

Comment on lines +187 to +197
```bash
PUB=offline-ledger-signing-key.pub.pem
LINE=$(head -n 1 '<ledger-file>.event.jsonl')

printf '%s' "$LINE" | jq -r .record_hash > /tmp/msg
printf '%s' "$LINE" | jq -r .signature | openssl base64 -d -A > /tmp/sig

openssl dgst -sha256 -verify "$PUB" \
-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-3 \
-signature /tmp/sig /tmp/msg
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

openssl pkeyutl rsa_pss_saltlen -3 auto-digestmax supported version

💡 Result:

The auto-digestmax option for rsa_pss_saltlen in OpenSSL is a setting introduced to align with FIPS 186-4 compliance [1][2]. It functions by automatically detecting the salt length during signature verification and, when signing, maximizes the salt length up to the size of the digest [3]. This option was introduced in OpenSSL 3.1 [2]. Key details regarding this option include: - Behavior: It provides a balance between compatibility and FIPS compliance [1][2]. During verification, it auto-detects the salt length to ensure maximum compatibility [1]. When signing, it clamps the salt length to the digest length, ensuring it does not violate the FIPS 186-4 requirement that the salt length must be less than or equal to the hash function output length [1][2]. - Purpose: It was created to address issues where older salt length settings (like digest or auto) might either fail with certain digest/key combinations or potentially violate FIPS requirements depending on the default behavior [1][2]. - Availability: As of August 2026, this feature is available in OpenSSL 3.1 and later versions [3][2]. It is documented under the OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX parameter [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate air-gapped.mdx"
fd -a 'air-gapped.mdx' . || true

echo
echo "Relevant lines"
if [ -f developer-guide/self-hosting/air-gapped.mdx ]; then
  nl -ba developer-guide/self-hosting/air-gapped.mdx | sed -n '140,210p'
fi

echo
echo "Search for record_hash/signature/rsa_pss_saltlen references"
rg -n "record_hash|signature|rsa_pss_saltlen" developer-guide/self-hosting/air-gapped.mdx || true

echo
echo "Probe jq newline behavior"
printf '%s\n' '{"record_hash":"abc","signature":"def"}' | jq -r .record_hash > /tmp/jq_r_msg
printf '%s\n' '{"record_hash":"abc","signature":"def"}' | jq -j .record_hash > /tmp/jq_j_msg
printf "jq -r output (hex):\n"
xxd /tmp/jq_r_msg
printf "jq -j output (hex):\n"
xxd /tmp/jq_j_msg

Repository: fishaudio/docs

Length of output: 294


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant lines"
awk '{printf "%6d\t%s\n", NR, $0}' developer-guide/self-hosting/air-gapped.mdx | sed -n '140,210p'

echo
echo "Search for RSA-SHA256-PSS / saltlen options"
grep -nEi "rsa|pss|saltlen|record_hash|signature|openssl dgst|openssl pkeyutl" developer-guide/self-hosting/air-gapped.mdx || true

echo
echo "Probe jq newline behavior"
python3 - <<'PY'
import subprocess
cmd = ['printf', '%s\n', '{"record_hash":"abc","signature":"def"}']
for opt in ['-r', '-j']:
    p = subprocess.run(['python3','-c', 'import sys;print(sys.stdin.read())'] + ['jq', opt, '.record_hash'], input=b'{"record_hash":"abc","signature":"def"}\n', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    print(f"jq {opt}: bytes={p.stdout!r}, contains_trailing_newline={p.stdout.endswith(b\"\\n\")}")
PY

Repository: fishaudio/docs

Length of output: 5923


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "jq newline behavior"
printf '%s\n' '{"record_hash":"abc","signature":"def"}' | jq -r .record_hash > /tmp/jq_r_msg
printf '%s\n' '{"record_hash":"abc","signature":"def"}' | jq -j .record_hash > /tmp/jq_j_msg
python3 - <<'PY'
for path in ("/tmp/jq_r_msg", "/tmp/jq_j_msg"):
    data = open(path, "rb").read()
    marker = "r" if "jq_r" in path else "j"
    print("jq", marker, "bytes=", repr(data), "trailing_newline=", data.endswith(b"\n"))
PY

echo
echo "Search signature constants/sources"
rg -n "rsa_pss_saltlen|RSA-PSS|open_ssl|openssl|record_hash|RSA_PSS|openSSL|OpenSSL" --glob '!vendor/**' --glob '!build/**' --glob '!dist/**' . | sed -n '1,200p'

Repository: fishaudio/docs

Length of output: 1628


🌐 Web query:

OpenSSL pkeyutl -rawin -verify -sigopt rsa_pss_saltlen:16 default digest length

💡 Result:

In OpenSSL's pkeyutl utility, when using the rsa_pss_saltlen option, the default salt length behavior depends on the context of the underlying EVP_PKEY_CTX. For PSS padding, if the salt length is not explicitly set, the default is -2 [1]. In the context of the EVP_PKEY_CTX_set_rsa_pss_saltlen function: - A value of -1 sets the salt length to the digest length [1]. - A value of -2 sets the salt length to the maximum permissible value when signing, or causes the salt length to be automatically determined based on the PSS block structure when verifying [1]. While the pkeyutl documentation for command-line options describes the "digest" value as setting the salt length to the digest length [2][3], it refers to the same underlying control mechanisms. When you do not specify a salt length, the system defaults to the value represented by -2 (the maximum permissible salt length) [1].

Citations:


🌐 Web query:

OpenSSL pkeyutl -rawin -verify -sigopt rsa_pss_saltlen:-3 invalid old version

💡 Result:

In OpenSSL, the value -3 for rsa_pss_saltlen represents a request to set the salt length to the maximum permissible value [1][2][3]. If you encounter an "invalid" error when using rsa_pss_saltlen:-3, it is typically because the specific operation (such as signing) or the key constraints prevent the use of that salt length, or because the version of OpenSSL you are using has introduced stricter validation for FIPS compliance [1][4][5]. Key technical points regarding this behavior: 1. Definition of -3: Internally, OpenSSL defines RSA_PSS_SALTLEN_MAX as -3 [2][3]. This is intended to maximize the salt length based on the RSA key size and digest length. 2. FIPS Compliance Changes: Recent versions of OpenSSL have moved toward stricter adherence to FIPS 186-4, which limits the salt length (sLen) to be less than or equal to the digest length (hLen) [1][4][5]. As part of this, a new default option, auto-digestmax (which effectively caps the salt length at the digest length), was introduced [4][5]. Attempting to use a "maximum" salt length that violates these FIPS-based constraints can result in an error, as the library now performs stricter checks [1][4]. 3. Version Differences: - In older versions, -3 was a standard way to request the maximum salt length [2][3]. - In newer versions (especially since OpenSSL 3.0), the library may reject certain configurations that were previously allowed if they conflict with modern security standards or the new default "auto-digestmax" logic, particularly if you are in a FIPS-enabled environment [4][5]. 4. Troubleshooting: If you are getting an invalid error, verify if the salt length you are requesting exceeds the digest length of your chosen hash function. You may need to use the digest length (value -1) or the new auto or auto-digestmax options instead of forcing a maximum length [6][4][5]. Top results: [1], [4], [5], [2]

Citations:


Write the hash without a trailing newline before verification.

jq -r .record_hash > /tmp/msg appends a newline. The signature covers the record_hash value only, but verification applies the digest to a longer message, so authentic ledger records fail. Use jq -j .record_hash or another newline-free write method.

Also check the OpenSSL versions customers support: set rsa_pss_saltlen to a value supported by those builds, or document the required OpenSSL version for this command.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@developer-guide/self-hosting/air-gapped.mdx` around lines 187 - 197, The
verification command in the air-gapped ledger example must write only the
record_hash bytes, without a trailing newline; update the jq extraction in the
message-generation step accordingly. Also review the rsa_pss_saltlen setting for
supported customer OpenSSL versions, either choosing a compatible value or
documenting the required OpenSSL version for this command.

Comment on lines +199 to +205
`Verified OK` confirms the record is authentic. Recompute the hash itself from the
record body and compare it to the `record_hash` field:

```bash
printf '%s' "$LINE" | jq -c 'del(.record_hash,.signature)' | openssl dgst -sha256
printf '%s' "$LINE" | jq -r .record_hash
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)air-gapped\.mdx$|air-gap|air_gapped|air-gapped' || true

echo "== target excerpt =="
if [ -f developer-guide/self-hosting/air-gapped.mdx ]; then
  nl -ba developer-guide/self-hosting/air-gapped.mdx | sed -n '160,225p'
fi

echo "== record_hash references =="
rg -n "record_hash|all fields above|Verified OK|openssl dgst|json|jq" developer-guide/self-hosting/air-gapped.mdx || true

Repository: fishaudio/docs

Length of output: 269


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target excerpt =="
awk '{printf "%6d\t%s\n", NR, $0}' developer-guide/self-hosting/air-gapped.mdx | sed -n '160,225p'

echo "== record_hash references =="
grep -n "record_hash\|all fields above\|Verified OK\|openssl dgst\|json\|jq" developer-guide/self-hosting/air-gapped.mdx || true

echo "== jq newline and key-order probe =="
python3 - <<'PY'
from subprocess import run, PIPE
samples = [
  '{"record_hash":"abc","signature":"sig","payload":"x"}',
  '{"signature":"sig","payload":"x","record_hash":"abc"}',
]
for s in samples:
    p = run(["jq", "-c", '.'], input=s, text=True, stdout=PIPE, stderr=PIPE)
    print(f"input={s!r}")
    print(f"jq -c bytes={p.stdout!r} len={len(p.stdout)} endswith_newline={p.stdout.endswith('\\n)}")
PY

Repository: fishaudio/docs

Length of output: 5229


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== jq newline and key-order probe =="
python3 - <<'PY'
from subprocess import run, PIPE
samples = [
  '{"record_hash":"abc","signature":"sig","payload":"x"}',
  '{"signature":"sig","payload":"x","record_hash":"abc"}',
]
for s in samples:
    p = run(["jq", "-c", '.'], input=s, text=True, stdout=PIPE, stderr=PIPE)
    print("input={}".format(repr(s)))
    print("jq -c bytes={}".format(repr(p.stdout)))
    print("jq -c len={}".format(len(p.stdout)))
    print("jq -c endswith_newline={}".format(p.stdout.endswith("\n")))
PY

echo "== jq del behavior using line above =="
python3 - <<'PY'
from subprocess import.run, PIPE
samples = [
  '{"record_hash":"abc","signature":"sig","payload":"x"}',
  '{"signature":"sig","payload":"x","record_hash":"abc"}',
]
for s in samples:
    p = run(["jq", "-c", "del(.record_hash,.signature)"], input=s, text=True, stdout=PIPE, stderr=PIPE)
    print("input={}".format(repr(s)))
    print("jq result={}".format(repr(p.stdout)))
PY

echo "== check whether jq/openssl/jq installed =="
(command -v jq && jq --version) || true
(command -v openssl && openssl version) || true

Repository: fishaudio/docs

Length of output: 692


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== jq del behavior using line above =="
python3 - <<'PY'
from subprocess import run, PIPE
samples = [
  '{"record_hash":"abc","signature":"sig","payload":"x"}',
  '{"signature":"sig","payload":"x","record_hash":"abc"}',
]
for s in samples:
    p = run(["jq", "-c", "del(.record_hash,.signature)"], input=s, text=True, stdout=PIPE, stderr=PIPE)
    print("input={}".format(repr(s)))
    print("jq result={}".format(repr(p.stdout)))
    print("returncode={}".format(p.returncode))
PY

echo "== jq installed =="
(command -v jq && jq --version) || true

Repository: fishaudio/docs

Length of output: 441


Specify the canonical bytes that record_hash covers.

jq -c adds a trailing newline, and jq object-key ordering is not deterministic across deployments, so the hash input may not match the manifest's signed bytes. Store the signed JSON serialization, update record_hash to describe that serialization, and trim the jq newline or use printf '%s' so the command under Recompute the hash matches the signed value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@developer-guide/self-hosting/air-gapped.mdx` around lines 199 - 205, Update
the air-gapped verification instructions to define record_hash as covering the
stored signed JSON serialization with deterministic key ordering. Preserve that
canonical serialization when storing the signed record, and revise the
recomputation command to remove jq’s trailing newline (or pipe through printf
'%s') so the hashed bytes exactly match the signed value.

Comment on lines +168 to +193
```text
<sharedStorageHostPath>/<namespace>/<release>/reference-archives/<reference_id>.zip
```

Each archive holds one or more audio files at the zip root, each paired with a
UTF-8 `.txt` transcript of the same basename:

```text
voice-alice-001.zip
|-- sample-01.wav
|-- sample-01.txt
|-- sample-02.mp3
`-- sample-02.txt
```

Supported audio extensions are `.wav`, `.mp3`, and `.opus`. Do not nest
directories inside the archive, and do not add prefixes to the filename — the
file name must match the reference id exactly.

If you have no node shell, stage archives through a helper pod that mounts the
share, then confirm the edge API can see the file:

```bash
kubectl -n "$NAMESPACE" exec deploy/edge-api-production -- \
ls -lh /mnt/share/reference-archives/voice-alice-001.zip
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare documented reference-archive paths across the docs set.
rg -n 'reference-archives' --glob '*.mdx' -C 2

Repository: fishaudio/docs

Length of output: 152


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate kubernetes files =="
fd -a 'kubernetes\.mdx$' . || true

echo "== repository files with reference archive terms =="
rg -n 'reference.?archive|reference-archives|sharedStorageHostPath|reference.*id|REFERENCE|RELEASE|NAMESPACE' . -S --glob '!node_modules' --glob '!dist' --glob '!build' | head -200

echo "== exact target file excerpt if present =="
FILE="$(fd -a 'kubernetes\.mdx$' . | head -1 || true)"
if [ -n "$FILE" ]; then
  wc -l "$FILE"
  sed -n '130,215p' "$FILE" | cat -n
fi

Repository: fishaudio/docs

Length of output: 35886


Fix the reference-archive verify path.

kubernetes.mdx:169 documents the shared archive file at <sharedStorageHostPath>/<namespace>/<release>/reference-archives/<reference_id>.zip, but kubernetes.mdx:192 checks /mnt/share/reference-archives/... without the namespace/release segments. Use the in-container mounted path, or document the archive root without those segments.

🧰 Tools
🪛 GitHub Check: Mintlify Validation (hanabiaiinc) - vale-spellcheck

[warning] 173-173: developer-guide/self-hosting/kubernetes.mdx#L173
Did you really mean 'basename'?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@developer-guide/self-hosting/kubernetes.mdx` around lines 168 - 193, Update
the verification command near the archive example to use the same in-container
mounted path that includes the namespace and release segments as the documented
archive location, or revise the archive-location documentation to match the
mounted root. Keep the reference archive filename and edge API verification
behavior unchanged.

Comment on lines +106 to +117
## Create the Kubernetes pull secret

The cluster pulls images with the same credentials. Create the pull secret the
chart expects in the release namespace:

```bash
kubectl -n fish-audio create secret docker-registry fish-audio-registry \
--docker-server="$REGISTRY_HOST" \
--docker-username="$LOGIN_USER" \
--docker-password="$DEPLOY_TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Create the namespace before the pull secret.

Readers reach this page before the namespace step in Kubernetes deployment. If the fish-audio namespace does not exist, kubectl apply fails with a "namespaces not found" error. Add the namespace creation to this snippet.

Proposed fix
+```bash
+kubectl create namespace fish-audio --dry-run=client -o yaml | kubectl apply -f -
+```
+
 ```bash
 kubectl -n fish-audio create secret docker-registry fish-audio-registry \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Create the Kubernetes pull secret
The cluster pulls images with the same credentials. Create the pull secret the
chart expects in the release namespace:
```bash
kubectl -n fish-audio create secret docker-registry fish-audio-registry \
--docker-server="$REGISTRY_HOST" \
--docker-username="$LOGIN_USER" \
--docker-password="$DEPLOY_TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
```
## Create the Kubernetes pull secret
The cluster pulls images with the same credentials. Create the pull secret the
chart expects in the release namespace:
🧰 Tools
🪛 GitHub Check: Mintlify Validation (hanabiaiinc) - vale-spellcheck

[warning] 109-109: developer-guide/self-hosting/registry-access.mdx#L109
Did you really mean 'namespace'?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@developer-guide/self-hosting/registry-access.mdx` around lines 106 - 117,
Update the “Create the Kubernetes pull secret” snippet to create or apply the
fish-audio namespace before creating the registry secret, using an idempotent
kubectl command and preserving the existing secret command afterward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant