diff --git a/.changeset/custom-embeddings-endpoint.md b/.changeset/custom-embeddings-endpoint.md
new file mode 100644
index 00000000..2ae779d7
--- /dev/null
+++ b/.changeset/custom-embeddings-endpoint.md
@@ -0,0 +1,5 @@
+---
+"@inkeep/open-knowledge": patch
+---
+
+Configure a custom OpenAI-compatible embeddings endpoint from Settings → This project → Search instead of editing config files by hand. The semantic-search settings now expose the embeddings base URL directly, and the account copy plus `ok embeddings set-key` messaging now describe the key as belonging to the configured embeddings provider rather than only to OpenAI.
diff --git a/packages/app/src/components/settings/EmbeddingsKeySection.tsx b/packages/app/src/components/settings/EmbeddingsKeySection.tsx
index 3465833a..613c6710 100644
--- a/packages/app/src/components/settings/EmbeddingsKeySection.tsx
+++ b/packages/app/src/components/settings/EmbeddingsKeySection.tsx
@@ -57,13 +57,13 @@ export function EmbeddingsKeySection({ transport }: { transport?: EmbeddingsKeyT
- Your OpenAI API key, used only to create embeddings of your content for semantic search.
- Stored once for this machine in{' '}
+ Your embeddings provider API key, used only to create embeddings of your content for
+ semantic search. Stored once for this machine in{' '}
~/.ok/secrets.yml
{' '}
(readable only by your user account) and shared across all projects. Turn the feature on
- per project in This project → Search.
+ per project in This project → Search, where you can also override the endpoint.
+ Clear the field to reset back to the default OpenAI endpoint.
+
+
+
~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
- ],
"FRYB1Q": ["/api/config returned a malformed body"],
"FRqZ9v": ["Couldn't update skill: ", ["0"]],
"FTUGgh": ["Enter a repository URL or owner/repo"],
@@ -770,6 +767,7 @@
"KujtjC": ["Find"],
"L-rMC9": ["Reset to default"],
"L1ZE3M": ["Document statistics"],
+ "L1rRuU": ["Embeddings API endpoint"],
"L3CEC1": ["this item"],
"L4Cdd9": ["or create a new file <0/>"],
"L6Hhh6": ["(root)"],
@@ -1403,6 +1401,7 @@
"eG8Jsg": ["Toggle source tab focus mode"],
"eJitUk": ["Upload from computer"],
"eKThTQ": ["Failed to reorder"],
+ "eLl1VX": ["Failed to update the embeddings endpoint — ", ["detail"]],
"eNQGRb": ["Inline LaTeX math rendered with KaTeX."],
"ePK91l": ["Edit"],
"eQkgKV": ["Installed"],
@@ -1618,6 +1617,7 @@
"l8G3S9": ["Auto-sync is off — you don't have permission to push to this repo"],
"lAiyU_": ["Only the current document uses <0>#", ["tag"], "0>."],
"lGs_bQ": ["Page <0>*0>"],
+ "lHCR4I": ["Clear the field to reset back to the default OpenAI endpoint."],
"lHwYMr": ["Server error: ", ["status"], " ", ["statusText"]],
"lI0Td2": ["Use letters, digits, <0>_0> and <1>-1> only."],
"lIn9L9": ["Disable sync"],
@@ -1785,6 +1785,9 @@
"pha01Y": ["Project-level pages with no incoming graph edges."],
"pkAft1": ["Search failed."],
"pmKdif": ["Failed: ", ["loadError"]],
+ "pmOGtg": [
+ "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+ ],
"pmUArF": ["Workspace"],
"ppDgFi": ["Restart with this app's version"],
"pzutoc": ["Italic"],
@@ -2002,6 +2005,9 @@
"wXO4Tg": [["hrs"], "h ago"],
"wbv9xO": ["Create new project"],
"wbwHYD": ["Enable sync"],
+ "wccmX0": [
+ "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+ ],
"weP6me": ["Couldn't load docs — type @ again to retry"],
"wlwXUk": [
"You picked ~/Downloads. Files there are usually transient — consider a stable folder instead."
diff --git a/packages/app/src/locales/en/messages.po b/packages/app/src/locales/en/messages.po
index f0a213a0..9025b572 100644
--- a/packages/app/src/locales/en/messages.po
+++ b/packages/app/src/locales/en/messages.po
@@ -1067,6 +1067,10 @@ msgstr "Clear"
msgid "Clear {keyName}"
msgstr "Clear {keyName}"
+#: src/components/settings/SearchSection.tsx
+msgid "Clear the field to reset back to the default OpenAI endpoint."
+msgstr "Clear the field to reset back to the default OpenAI endpoint."
+
#: src/components/FolderTimelineCard.tsx
msgid "cleared folder properties"
msgstr "cleared folder properties"
@@ -2325,6 +2329,10 @@ msgstr "Embed an external page in an inline iframe (docs, demos, Figma, CodeSand
msgid "Embed an image with optional alt text."
msgstr "Embed an image with optional alt text."
+#: src/components/settings/SearchSection.tsx
+msgid "Embeddings API endpoint"
+msgstr "Embeddings API endpoint"
+
#: src/components/settings/SearchSection.tsx
msgid "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
msgstr "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
@@ -2657,6 +2665,10 @@ msgstr "Failed to reorder"
msgid "Failed to update property"
msgstr "Failed to update property"
+#: src/components/settings/SearchSection.tsx
+msgid "Failed to update the embeddings endpoint — {detail}"
+msgstr "Failed to update the embeddings endpoint — {detail}"
+
#: src/components/settings/SettingsDialogBody.tsx
msgid "Failed to update the project sync default — {detail}"
msgstr "Failed to update the project sync default — {detail}"
@@ -6686,6 +6698,10 @@ msgstr "Use lowercase letters, digits, and <0>-0> only."
msgid "Use lowercase letters, digits, and hyphens only."
msgstr "Use lowercase letters, digits, and hyphens only."
+#: src/components/settings/SearchSection.tsx
+msgid "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+msgstr "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+
#: src/components/settings/SettingsDialogShell.tsx
msgid "User"
msgstr "User"
@@ -6914,6 +6930,10 @@ msgstr "You picked the filesystem root (/). Scaffolding here will scan every fil
msgid "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
msgstr "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
+#: src/components/settings/EmbeddingsKeySection.tsx
+msgid "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+msgstr "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+
#: src/components/settings/SettingsDialogBody.tsx
#: src/components/SyncStatusBadge.tsx
msgid "Your GitHub session expired — sign in again to verify push access."
@@ -6927,10 +6947,6 @@ msgstr "Your GitHub token is missing required scopes. Try signing in again."
msgid "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
msgstr "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
-#: src/components/settings/EmbeddingsKeySection.tsx
-msgid "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-msgstr "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-
#: src/components/CloneDialog.tsx
msgid "Your repositories"
msgstr "Your repositories"
diff --git a/packages/app/src/locales/pseudo/messages.json b/packages/app/src/locales/pseudo/messages.json
index f3e59392..717e55fc 100644
--- a/packages/app/src/locales/pseudo/messages.json
+++ b/packages/app/src/locales/pseudo/messages.json
@@ -594,9 +594,6 @@
"FEr96N": ["Ţĥēḿē"],
"FNTx6u": ["Śēàŕćĥ \"", ["semanticSubmitQuery"], "\" ƀŷ ḿēàńĩńĝ"],
"FOGD7m": ["Ćŕēàţē śōḿēţĥĩńĝ ĝŕēàţ."],
- "FOyCTr": [
- "Ŷōũŕ ŌƥēńÀĨ ÀƤĨ ķēŷ, ũśēď ōńĺŷ ţō ćŕēàţē ēḿƀēďďĩńĝś ōƒ ŷōũŕ ćōńţēńţ ƒōŕ śēḿàńţĩć śēàŕćĥ. Śţōŕēď ōńćē ƒōŕ ţĥĩś ḿàćĥĩńē ĩń <0>~/.ōķ/śēćŕēţś.ŷḿĺ0> (ŕēàďàƀĺē ōńĺŷ ƀŷ ŷōũŕ ũśēŕ àććōũńţ) àńď śĥàŕēď àćŕōśś àĺĺ ƥŕōĴēćţś. Ţũŕń ţĥē ƒēàţũŕē ōń ƥēŕ ƥŕōĴēćţ ĩń Ţĥĩś ƥŕōĴēćţ → Śēàŕćĥ."
- ],
"FRYB1Q": ["/àƥĩ/ćōńƒĩĝ ŕēţũŕńēď à ḿàĺƒōŕḿēď ƀōďŷ"],
"FRqZ9v": ["Ćōũĺďń'ţ ũƥďàţē śķĩĺĺ: ", ["0"]],
"FTUGgh": ["Ēńţēŕ à ŕēƥōśĩţōŕŷ ŨŔĹ ōŕ ōŵńēŕ/ŕēƥō"],
@@ -770,6 +767,7 @@
"KujtjC": ["Ƒĩńď"],
"L-rMC9": ["Ŕēśēţ ţō ďēƒàũĺţ"],
"L1ZE3M": ["Ďōćũḿēńţ śţàţĩśţĩćś"],
+ "L1rRuU": ["Ēḿƀēďďĩńĝś ÀƤĨ ēńďƥōĩńţ"],
"L3CEC1": ["ţĥĩś ĩţēḿ"],
"L4Cdd9": ["ōŕ ćŕēàţē à ńēŵ ƒĩĺē <0/>"],
"L6Hhh6": ["(ŕōōţ)"],
@@ -1403,6 +1401,7 @@
"eG8Jsg": ["Ţōĝĝĺē śōũŕćē ţàƀ ƒōćũś ḿōďē"],
"eJitUk": ["Ũƥĺōàď ƒŕōḿ ćōḿƥũţēŕ"],
"eKThTQ": ["Ƒàĩĺēď ţō ŕēōŕďēŕ"],
+ "eLl1VX": ["Ƒàĩĺēď ţō ũƥďàţē ţĥē ēḿƀēďďĩńĝś ēńďƥōĩńţ — ", ["detail"]],
"eNQGRb": ["Ĩńĺĩńē ĹàŢēX ḿàţĥ ŕēńďēŕēď ŵĩţĥ ĶàŢēX."],
"ePK91l": ["Ēďĩţ"],
"eQkgKV": ["Ĩńśţàĺĺēď"],
@@ -1618,6 +1617,7 @@
"l8G3S9": ["Àũţō-śŷńć ĩś ōƒƒ — ŷōũ ďōń'ţ ĥàvē ƥēŕḿĩśśĩōń ţō ƥũśĥ ţō ţĥĩś ŕēƥō"],
"lAiyU_": ["Ōńĺŷ ţĥē ćũŕŕēńţ ďōćũḿēńţ ũśēś <0>#", ["tag"], "0>."],
"lGs_bQ": ["Ƥàĝē <0>*0>"],
+ "lHCR4I": ["Ćĺēàŕ ţĥē ƒĩēĺď ţō ŕēśēţ ƀàćķ ţō ţĥē ďēƒàũĺţ ŌƥēńÀĨ ēńďƥōĩńţ."],
"lHwYMr": ["Śēŕvēŕ ēŕŕōŕ: ", ["status"], " ", ["statusText"]],
"lI0Td2": ["Ũśē ĺēţţēŕś, ďĩĝĩţś, <0>_0> àńď <1>-1> ōńĺŷ."],
"lIn9L9": ["Ďĩśàƀĺē śŷńć"],
@@ -1785,6 +1785,9 @@
"pha01Y": ["ƤŕōĴēćţ-ĺēvēĺ ƥàĝēś ŵĩţĥ ńō ĩńćōḿĩńĝ ĝŕàƥĥ ēďĝēś."],
"pkAft1": ["Śēàŕćĥ ƒàĩĺēď."],
"pmKdif": ["Ƒàĩĺēď: ", ["loadError"]],
+ "pmOGtg": [
+ "Ũśē ţĥē ďēƒàũĺţ ŌƥēńÀĨ ēńďƥōĩńţ ōŕ ōvēŕŕĩďē ĩţ ŵĩţĥ àń ŌƥēńÀĨ-ćōḿƥàţĩƀĺē ƀàśē ŨŔĹ ƒōŕ Àźũŕē ōŕ à śēĺƒ-ĥōśţēď ƥŕōvĩďēŕ."
+ ],
"pmUArF": ["Ŵōŕķśƥàćē"],
"ppDgFi": ["Ŕēśţàŕţ ŵĩţĥ ţĥĩś àƥƥ'ś vēŕśĩōń"],
"pzutoc": ["Ĩţàĺĩć"],
@@ -2002,6 +2005,9 @@
"wXO4Tg": [["hrs"], "ĥ àĝō"],
"wbv9xO": ["Ćŕēàţē ńēŵ ƥŕōĴēćţ"],
"wbwHYD": ["Ēńàƀĺē śŷńć"],
+ "wccmX0": [
+ "Ŷōũŕ ēḿƀēďďĩńĝś ƥŕōvĩďēŕ ÀƤĨ ķēŷ, ũśēď ōńĺŷ ţō ćŕēàţē ēḿƀēďďĩńĝś ōƒ ŷōũŕ ćōńţēńţ ƒōŕ śēḿàńţĩć śēàŕćĥ. Śţōŕēď ōńćē ƒōŕ ţĥĩś ḿàćĥĩńē ĩń <0>~/.ōķ/śēćŕēţś.ŷḿĺ0> (ŕēàďàƀĺē ōńĺŷ ƀŷ ŷōũŕ ũśēŕ àććōũńţ) àńď śĥàŕēď àćŕōśś àĺĺ ƥŕōĴēćţś. Ţũŕń ţĥē ƒēàţũŕē ōń ƥēŕ ƥŕōĴēćţ ĩń Ţĥĩś ƥŕōĴēćţ → Śēàŕćĥ, ŵĥēŕē ŷōũ ćàń àĺśō ōvēŕŕĩďē ţĥē ēńďƥōĩńţ."
+ ],
"weP6me": ["Ćōũĺďń'ţ ĺōàď ďōćś — ţŷƥē @ àĝàĩń ţō ŕēţŕŷ"],
"wlwXUk": [
"Ŷōũ ƥĩćķēď ~/Ďōŵńĺōàďś. Ƒĩĺēś ţĥēŕē àŕē ũśũàĺĺŷ ţŕàńśĩēńţ — ćōńśĩďēŕ à śţàƀĺē ƒōĺďēŕ ĩńśţēàď."
diff --git a/packages/app/src/locales/pseudo/messages.po b/packages/app/src/locales/pseudo/messages.po
index 2a401405..84d83e31 100644
--- a/packages/app/src/locales/pseudo/messages.po
+++ b/packages/app/src/locales/pseudo/messages.po
@@ -1062,6 +1062,10 @@ msgstr ""
msgid "Clear {keyName}"
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Clear the field to reset back to the default OpenAI endpoint."
+msgstr ""
+
#: src/components/FolderTimelineCard.tsx
msgid "cleared folder properties"
msgstr ""
@@ -2320,6 +2324,10 @@ msgstr ""
msgid "Embed an image with optional alt text."
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Embeddings API endpoint"
+msgstr ""
+
#: src/components/settings/SearchSection.tsx
msgid "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
msgstr ""
@@ -2652,6 +2660,10 @@ msgstr ""
msgid "Failed to update property"
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Failed to update the embeddings endpoint — {detail}"
+msgstr ""
+
#: src/components/settings/SettingsDialogBody.tsx
msgid "Failed to update the project sync default — {detail}"
msgstr ""
@@ -6681,6 +6693,10 @@ msgstr ""
msgid "Use lowercase letters, digits, and hyphens only."
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+msgstr ""
+
#: src/components/settings/SettingsDialogShell.tsx
msgid "User"
msgstr ""
@@ -6909,6 +6925,10 @@ msgstr ""
msgid "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
msgstr ""
+#: src/components/settings/EmbeddingsKeySection.tsx
+msgid "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+msgstr ""
+
#: src/components/settings/SettingsDialogBody.tsx
#: src/components/SyncStatusBadge.tsx
msgid "Your GitHub session expired — sign in again to verify push access."
@@ -6922,10 +6942,6 @@ msgstr ""
msgid "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
msgstr ""
-#: src/components/settings/EmbeddingsKeySection.tsx
-msgid "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-msgstr ""
-
#: src/components/CloneDialog.tsx
msgid "Your repositories"
msgstr ""
diff --git a/packages/cli/src/commands/embeddings/index.ts b/packages/cli/src/commands/embeddings/index.ts
index 4f99133d..f106e1d0 100644
--- a/packages/cli/src/commands/embeddings/index.ts
+++ b/packages/cli/src/commands/embeddings/index.ts
@@ -23,7 +23,7 @@ async function readKey(): Promise {
for await (const chunk of process.stdin) chunks.push(chunk as Buffer);
return Buffer.concat(chunks).toString('utf-8').trim();
}
- return (await password({ message: 'Enter OpenAI embeddings API key:' })).trim();
+ return (await password({ message: 'Enter embeddings provider API key:' })).trim();
}
function readSemanticConfig(projectDir: string) {
@@ -57,7 +57,7 @@ async function fetchLiveCoverage(
function setKeyCommand(): Command {
return new Command('set-key')
- .description('Store your OpenAI embeddings API key in ~/.ok/secrets.yml')
+ .description('Store your embeddings provider API key in ~/.ok/secrets.yml')
.action(async () => {
const key = await readKey();
if (!key) {
@@ -67,9 +67,9 @@ function setKeyCommand(): Command {
}
await createEmbeddingsSecretStore().set(key);
process.stderr.write(
- '✓ OpenAI embeddings API key stored in ~/.ok/secrets.yml (0600, this machine only).\n' +
+ '✓ Embeddings provider API key stored in ~/.ok/secrets.yml (0600, this machine only).\n' +
'Now enable it per project — the easiest path is OK Desktop → Settings → This\n' +
- 'project → Search (a toggle with an egress-confirmation prompt), or run\n' +
+ 'project → Search (toggle + endpoint settings), or run\n' +
'`ok embeddings enable` in the project folder.\n',
);
});
@@ -77,14 +77,14 @@ function setKeyCommand(): Command {
function clearKeyCommand(): Command {
return new Command('clear-key')
- .description('Remove your stored OpenAI embeddings API key')
+ .description('Remove your stored embeddings provider API key')
.action(async () => {
const { touched } = await clearEmbeddingsKeyFromAllBackends();
if (touched.length === 0) {
- process.stderr.write('No stored OpenAI embeddings key found.\n');
+ process.stderr.write('No stored embeddings provider key found.\n');
return;
}
- process.stderr.write(`✓ OpenAI embeddings API key cleared (${touched.join(', ')}).\n`);
+ process.stderr.write(`✓ Embeddings provider API key cleared (${touched.join(', ')}).\n`);
});
}