diff --git a/db/init/011_auth.sql b/db/init/011_auth.sql
new file mode 100644
index 0000000..bd9f518
--- /dev/null
+++ b/db/init/011_auth.sql
@@ -0,0 +1,8 @@
+-- Auth secrets for bearer token authentication
+CREATE TABLE IF NOT EXISTS auth_secrets (
+    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+    namespace_id UUID NOT NULL REFERENCES namespaces(id) ON DELETE CASCADE,
+    secret_hash TEXT NOT NULL,
+    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+    UNIQUE(namespace_id)
+);
diff --git a/docs/mcp-memory-api.md b/docs/mcp-memory-api.md
index 4a2c15f..af015aa 100644
--- a/docs/mcp-memory-api.md
+++ b/docs/mcp-memory-api.md
@@ -8,12 +8,12 @@
 ## Tools
 ### `save_context`
 Persist a context blob with metadata.
-- input: `{ namespace: string, key?: string, content: any, tags?: string[], ttl_seconds?: number }`
+- input: `{ key?: string, content: any, tags?: string[], ttl_seconds?: number }`
 - output: `{ id: string, created_at: string }`
 
 ### `recall_context`
 Fetch context by key/tags/time range.
-- input: `{ namespace: string, key?: string, tags?: string[], limit?: number, since?: string }`
+- input: `{ key?: string, tags?: string[], limit?: number, since?: string }`
 - output: `{ items: Array<{id:string, key?:string, content:any, tags?:string[], created_at:string}> }`
 
 ### `embed_text`
@@ -23,22 +23,22 @@ Return vector embedding for given text(s).
 
 ### `upsert_memory`
 Upsert text+metadata into vector store.
-- input: `{ namespace: string, items: Array<{id?:string, text:string, metadata?:object, embedding?:number[]}> }`
+- input: `{ items: Array<{id?:string, text:string, metadata?:object, embedding?:number[]}> }`
 - output: `{ upserted: number }`
 
 ### `search_memory`
 Vector + keyword hybrid search.
-- input: `{ namespace: string, query: { text?: string, embedding?: number[], k?: number, filter?: object } }`
+- input: `{ query: { text?: string, embedding?: number[], k?: number, filter?: object } }`
 - output: `{ matches: Array<{id:string, score:number, text?:string, metadata?:object}> }`
 
 ### `warm_cache`
 Precompute embeddings for recent items.
-- input: `{ namespace: string, since?: string }`
+- input: `{ since?: string }`
 - output: `{ queued: number }`
 
 ### `sync_semantic`
 Promote episodic rows into semantic (chunks + embeddings) storage.
-- input: `{ namespace: string, max_batch?: number }`
+- input: `{ max_batch?: number }`
 - output: `{ processed: number, pending: number }`
 - Notes: skips items with `sensitivity="secret"` or expired TTL; requires DAL job support.
 
diff --git a/docs/tool-calling-without-native-support.md b/docs/tool-calling-without-native-support.md
index 1272356..c3ed64f 100644
--- a/docs/tool-calling-without-native-support.md
+++ b/docs/tool-calling-without-native-support.md
@@ -34,7 +34,7 @@ If JSON parsing is brittle, accept a single line command and parse it:
 
 @tool <name> {json-args}
 
-Example: @tool kom.memory.v1.search_memory {"namespace":"project:metal", "query":{"text":"embedding model"}}
+Example: @tool kom.memory.v1.search_memory {"query":{"text":"embedding model"}}
 
 ## 3) Prompt Template (drop-in)
 Use this system message for happy-code/claude-code sessions:
@@ -69,7 +69,7 @@ while True:
 System: (template above + list of tools & schemas)
 User: Save this note: "Embedding model comparison takeaways" into project:metal
 Assistant:
-{"thought":"need to upsert note","action":{"tool":"kom.memory.v1.upsert_memory","args":{"namespace":"project:metal","items":[{"text":"Embedding model comparison takeaways"}]}}}
+{"thought":"need to upsert note","action":{"tool":"kom.memory.v1.upsert_memory","args":{"items":[{"text":"Embedding model comparison takeaways"}]}}}
 Tool (kom.memory.v1.upsert_memory): { "upserted": 1 }
 Assistant:
 {"final":{"content":{"status":"ok","upserted":1}}}
diff --git a/docs/using-memory-tools.md b/docs/using-memory-tools.md
index 12b3001..bd64252 100644
--- a/docs/using-memory-tools.md
+++ b/docs/using-memory-tools.md
@@ -13,7 +13,6 @@ The Kompanion MCP backend exposes `kom.memory.v1.save_context` and `kom.memory.v
   {
     "tool": "kom.memory.v1.save_context",
     "arguments": {
-      "namespace": "project:metal",
       "key": "codey/session",
       "content": {"summary": "Refactored PgDal for TTL support"},
       "tags": ["codey", "memory"]
@@ -26,7 +25,6 @@ The Kompanion MCP backend exposes `kom.memory.v1.save_context` and `kom.memory.v
   {
     "tool": "kom.memory.v1.recall_context",
     "arguments": {
-      "namespace": "thread:123",
       "limit": 5,
       "tags": ["task"]
     }
diff --git a/src/dal/PgDal.cpp b/src/dal/PgDal.cpp
index b33200e..ac7feff 100644
--- a/src/dal/PgDal.cpp
+++ b/src/dal/PgDal.cpp
@@ -281,21 +281,10 @@ std::optional<NamespaceRow> PgDal::ensureNamespace(const std::string& name) {
   if (!connected_) {
     return std::nullopt;
   }
-  if (!useInMemory_ && hasDatabase()) {
-    return sqlEnsureNamespace(name);
+  if (auto existing = findNamespace(name)) {
+    return existing;
   }
-
-  auto it = namespacesByName_.find(name);
-  if (it != namespacesByName_.end()) {
-    return it->second;
-  }
-
-  NamespaceRow row;
-  row.id = allocateId(nextNamespaceId_, "ns_");
-  row.name = name;
-  namespacesByName_[name] = row;
-  namespacesById_[row.id] = row;
-  return row;
+  return createNamespaceWithSecret(name).first;
 }
 
 std::optional<NamespaceRow> PgDal::findNamespace(const std::string& name) const {
@@ -310,22 +299,6 @@ std::optional<NamespaceRow> PgDal::findNamespace(const std::string& name) const
   return it->second;
 }
 
-NamespaceRow PgDal::sqlEnsureNamespace(const std::string& name) {
-  QSqlDatabase db = database();
-  QSqlQuery query(db);
-  query.prepare(QStringLiteral(
-      "INSERT INTO namespaces (name) VALUES (:name) "
-      "ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name "
-      "RETURNING id::text, name;"));
-  query.bindValue(QStringLiteral(":name"), QString::fromStdString(name));
-  if (!query.exec() || !query.next()) {
-    throw std::runtime_error(query.lastError().text().toStdString());
-  }
-  NamespaceRow row;
-  row.id = query.value(0).toString().toStdString();
-  row.name = query.value(1).toString().toStdString();
-  return row;
-}
 
 std::optional<NamespaceRow> PgDal::sqlFindNamespace(const std::string& name) const {
   QSqlDatabase db = database();
@@ -345,6 +318,103 @@ std::optional<NamespaceRow> PgDal::sqlFindNamespace(const std::string& name) con
   return row;
 }
 
+std::pair<NamespaceRow, std::string> PgDal::createNamespaceWithSecret(const std::string& name) {
+    if (!connected_) {
+        throw std::runtime_error("PgDal not connected");
+    }
+    if (!useInMemory_ && hasDatabase()) {
+        return sqlCreateNamespaceWithSecret(name);
+    }
+
+    // In-memory implementation
+    auto it = namespacesByName_.find(name);
+    if (it != namespacesByName_.end()) {
+        // For in-memory, we don't have secrets, so we can't return one.
+        // This path should ideally not be taken in production.
+        return {it->second, ""};
+    }
+
+    NamespaceRow row;
+    row.id = allocateId(nextNamespaceId_, "ns_");
+    row.name = name;
+    namespacesByName_[name] = row;
+    namespacesById_[row.id] = row;
+
+    // Secrets are not supported in-memory for now
+    return {row, ""};
+}
+
+std::optional<AuthSecret> PgDal::findSecretByNamespaceId(const std::string& namespaceId) const {
+    if (!useInMemory_ && hasDatabase()) {
+        return sqlFindSecretByNamespaceId(namespaceId);
+    }
+    // In-memory implementation does not support secrets
+    return std::nullopt;
+}
+
+std::pair<NamespaceRow, std::string> PgDal::sqlCreateNamespaceWithSecret(const std::string& name) {
+    QSqlDatabase db = database();
+    QSqlQuery query(db);
+
+    // 1. Create the namespace
+    query.prepare(QStringLiteral(
+        "INSERT INTO namespaces (name) VALUES (:name) "
+        "ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name "
+        "RETURNING id::text, name;"));
+    query.bindValue(QStringLiteral(":name"), QString::fromStdString(name));
+    if (!query.exec() || !query.next()) {
+        throw std::runtime_error(query.lastError().text().toStdString());
+    }
+    NamespaceRow row;
+    row.id = query.value(0).toString().toStdString();
+    row.name = query.value(1).toString().toStdString();
+
+    // 2. Generate and store the secret
+    QByteArray secretData(32, 0);
+    for (int i = 0; i < secretData.size(); ++i) {
+        secretData[i] = static_cast<char>(QRandomGenerator::system()->generate() % 256);
+    }
+    const std::string secret = secretData.toHex().toStdString();
+    const QByteArray secretHash = QCryptographicHash::hash(QByteArray::fromStdString(secret), QCryptographicHash::Sha256);
+    const std::string secretHashStr = secretHash.toHex().toStdString();
+
+    sqlInsertSecret(row.id, secretHashStr);
+
+    return {row, secret};
+}
+
+void PgDal::sqlInsertSecret(const std::string& namespaceId, const std::string& secretHash) {
+    QSqlDatabase db = database();
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral(
+        "INSERT INTO auth_secrets (namespace_id, secret_hash) "
+        "VALUES (:namespace_id::uuid, :secret_hash) "
+        "ON CONFLICT (namespace_id) DO UPDATE SET secret_hash = EXCLUDED.secret_hash;"));
+    query.bindValue(QStringLiteral(":namespace_id"), QString::fromStdString(namespaceId));
+    query.bindValue(QStringLiteral(":secret_hash"), QString::fromStdString(secretHash));
+    if (!query.exec()) {
+        throw std::runtime_error(query.lastError().text().toStdString());
+    }
+}
+
+std::optional<AuthSecret> PgDal::sqlFindSecretByNamespaceId(const std::string& namespaceId) const {
+    QSqlDatabase db = database();
+    QSqlQuery query(db);
+    query.prepare(QStringLiteral(
+        "SELECT secret_hash FROM auth_secrets WHERE namespace_id = :namespace_id::uuid"));
+    query.bindValue(QStringLiteral(":namespace_id"), QString::fromStdString(namespaceId));
+    if (!query.exec()) {
+        throw std::runtime_error(query.lastError().text().toStdString());
+    }
+    if (!query.next()) {
+        return std::nullopt;
+    }
+    AuthSecret secret;
+    secret.secret_hash = query.value(0).toString().toStdString();
+    return secret;
+}
+
+
 std::string PgDal::upsertItem(const ItemRow& row) {
   if (!connected_) {
     throw std::runtime_error("PgDal not connected");
diff --git a/src/dal/PgDal.hpp b/src/dal/PgDal.hpp
index 190313d..29fbf24 100644
--- a/src/dal/PgDal.hpp
+++ b/src/dal/PgDal.hpp
@@ -4,6 +4,8 @@
 
 #include <QSqlDatabase>
 #include <QString>
+#include <QCryptographicHash>
+#include <QRandomGenerator>
 
 #include <chrono>
 #include <optional>
@@ -47,6 +49,10 @@ struct EmbeddingRow {
   std::vector<float> vector;
 };
 
+struct AuthSecret {
+    std::string secret_hash;
+};
+
 class PgDal final : public IDatabase {
 public:
   PgDal();
@@ -57,8 +63,10 @@ public:
   void commit();
   void rollback();
 
+  std::pair<NamespaceRow, std::string> createNamespaceWithSecret(const std::string& name);
   std::optional<NamespaceRow> ensureNamespace(const std::string& name);
   std::optional<NamespaceRow> findNamespace(const std::string& name) const;
+  std::optional<AuthSecret> findSecretByNamespaceId(const std::string& namespaceId) const;
 
   std::string upsertItem(const ItemRow& row);
   std::vector<std::string> upsertChunks(const std::vector<ChunkRow>& chunks);
@@ -113,8 +121,11 @@ private:
   QSqlDatabase database() const;
   ConnectionConfig parseDsn(const std::string& dsn) const;
 
-  NamespaceRow sqlEnsureNamespace(const std::string& name);
+  std::pair<NamespaceRow, std::string> sqlCreateNamespaceWithSecret(const std::string& name);
+  std::optional<NamespaceRow> sqlEnsureNamespace(const std::string& name);
   std::optional<NamespaceRow> sqlFindNamespace(const std::string& name) const;
+  std::optional<AuthSecret> sqlFindSecretByNamespaceId(const std::string& namespaceId) const;
+  void sqlInsertSecret(const std::string& namespaceId, const std::string& secretHash);
   std::pair<std::string, int> sqlUpsertItem(const ItemRow& row);
   std::vector<std::string> sqlUpsertChunks(const std::vector<ChunkRow>& chunks);
   void sqlUpsertEmbeddings(const std::vector<EmbeddingRow>& embeddings);
diff --git a/src/main.cpp b/src/main.cpp
index 9e31cc3..de4f5fc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -26,6 +26,7 @@
 #include "mcp/KomMcpServer.hpp"
 #include "mcp/KompanionQtServer.hpp"
 #include "mcp/RegisterTools.hpp"
+#include "dal/PgDal.hpp"
 
 namespace {
 
@@ -199,6 +200,13 @@ int main(int argc, char **argv)
         std::cerr << "[kom_mcp] PG_DSN not set; DAL will fall back to stubbed mode. Configure Database/PgDsn to enable persistence.\n";
     }
 
+    kom::PgDal dal;
+    if (effectiveDsn) {
+        if (!dal.connect(*effectiveDsn)) {
+            std::cerr << "[kom_mcp] Failed to connect to database; DAL will fall back to stubbed mode.\n";
+        }
+    }
+
     if (parser.isSet(listOption)) {
         for (const auto &toolName : logic.listTools()) {
             std::cout << toolName << "\n";
@@ -237,7 +245,7 @@ int main(int argc, char **argv)
         return 1;
     }
 
-    KompanionQtServer server(backend, &logic);
+    KompanionQtServer server(backend, &logic, &dal);
     if (backend == QStringLiteral("stdio")) {
         server.start();
     } else {
diff --git a/src/mcp/HandlersMemory.hpp b/src/mcp/HandlersMemory.hpp
index ea45e9b..c0da754 100644
--- a/src/mcp/HandlersMemory.hpp
+++ b/src/mcp/HandlersMemory.hpp
@@ -634,4 +634,22 @@ inline std::string recall_context(const std::string& reqJson) {
     return os.str();
 }
 
+inline std::string embed_text(const std::string& reqJson) {
+    const std::string nsName = detail::extract_string_field(reqJson, "namespace");
+    if (nsName.empty()) {
+        return detail::error_response("bad_request", "namespace is required");
+    }
+    // For now, just return a dummy successful response
+    return "{\"model\":\"stub-model\",\"vectors\":[[0.1,0.2,0.3]]}";
+}
+
+inline std::string warm_cache(const std::string& reqJson) {
+    const std::string nsName = detail::extract_string_field(reqJson, "namespace");
+    if (nsName.empty()) {
+        return detail::error_response("bad_request", "namespace is required");
+    }
+    // For now, just return a dummy successful response
+    return "{\"queued\":0}";
+}
+
 } // namespace Handlers
diff --git a/src/mcp/KompanionQtServer.cpp b/src/mcp/KompanionQtServer.cpp
index d2d015e..88dde0d 100644
--- a/src/mcp/KompanionQtServer.cpp
+++ b/src/mcp/KompanionQtServer.cpp
@@ -17,6 +17,9 @@
 #include <QtCore/QLoggingCategory>
 #include <QtCore/QStandardPaths>
 #include <QtCore/QStringList>
+#include <QtCore/QJsonValue>
+#include <QStringView>
+#include <QCryptographicHash>
 
 #include <QDebug>
 using namespace Qt::Literals::StringLiterals;
@@ -34,9 +37,10 @@ QString normaliseToolName(const QString &defaultNamespace, const QString &rawNam
 }
 } // namespace
 
-KompanionQtServer::KompanionQtServer(const QString &backend, KomMcpServer *logic, QObject *parent)
+KompanionQtServer::KompanionQtServer(const QString &backend, KomMcpServer *logic, kom::PgDal* dal, QObject *parent)
     : QMcpServer(backend, parent)
     , m_logic(logic)
+    , m_dal(dal)
 {
     setProtocolVersion(QtMcp::ProtocolVersion::Latest);
     setSupportedProtocolVersions({QtMcp::ProtocolVersion::v2024_11_05,
@@ -80,6 +84,51 @@ KompanionQtServer::KompanionQtServer(const QString &backend, KomMcpServer *logic
         }
 
         const QJsonObject args = request.params().arguments();
+        const QJsonValue authTokenValue = args.value("auth_token");
+        const QString authToken = authTokenValue.toString();
+
+        if (m_dal) {
+            const QStringList parts = authToken.split(':');
+            if (parts.size() != 2) {
+                if (error) {
+                    error->setCode(401);
+                    error->setMessage("Unauthorized: Invalid auth token format");
+                }
+                return result;
+            }
+            const std::string namespaceName = parts[0].toStdString();
+            const std::string secret = parts[1].toStdString();
+
+            auto ns = m_dal->findNamespace(namespaceName);
+            if (!ns) {
+                if (error) {
+                    error->setCode(401);
+                    error->setMessage("Unauthorized: Namespace not found");
+                }
+                return result;
+            }
+
+            auto authSecret = m_dal->findSecretByNamespaceId(ns->id);
+            if (!authSecret) {
+                if (error) {
+                    error->setCode(401);
+                    error->setMessage("Unauthorized: No secret found for namespace");
+                }
+                return result;
+            }
+
+            const QByteArray providedSecretHash = QCryptographicHash::hash(QByteArray::fromStdString(secret), QCryptographicHash::Sha256).toHex();
+            const QByteArray storedSecretHash = QByteArray::fromStdString(authSecret->secret_hash).toHex();
+
+            if (providedSecretHash != storedSecretHash) {
+                if (error) {
+                    error->setCode(401);
+                    error->setMessage("Unauthorized: Invalid secret");
+                }
+                return result;
+            }
+        }
+
         const QByteArray payload = QJsonDocument(args).toJson(QJsonDocument::Compact);
         const std::string responseStr = m_logic->dispatch(toolKey, payload.toStdString());
         const QByteArray jsonBytes = QByteArray::fromStdString(responseStr);
diff --git a/src/mcp/KompanionQtServer.hpp b/src/mcp/KompanionQtServer.hpp
index 22101a0..6383817 100644
--- a/src/mcp/KompanionQtServer.hpp
+++ b/src/mcp/KompanionQtServer.hpp
@@ -2,6 +2,7 @@
 
 #include <QtMcpServer/QMcpServer>
 #include <QtMcpCommon/QMcpTool>
+#include "../dal/PgDal.hpp"
 
 #include "KomMcpServer.hpp"
 
@@ -11,11 +12,12 @@ class KompanionQtServer : public QMcpServer
 {
     Q_OBJECT
 public:
-    KompanionQtServer(const QString &backend, KomMcpServer *logic, QObject *parent = nullptr);
+    KompanionQtServer(const QString &backend, KomMcpServer *logic, kom::PgDal* dal, QObject *parent = nullptr);
 
 private:
     QList<QMcpTool> loadToolsFromSchema() const;
 
     KomMcpServer *m_logic = nullptr;
+    kom::PgDal* m_dal = nullptr;
     QList<QMcpTool> m_tools;
 };
diff --git a/src/mcp/RegisterTools.hpp b/src/mcp/RegisterTools.hpp
index 9f6a57a..d4284ce 100644
--- a/src/mcp/RegisterTools.hpp
+++ b/src/mcp/RegisterTools.hpp
@@ -7,8 +7,10 @@
 inline void register_default_tools(KomMcpServer& server) {
     server.registerTool("kom.memory.v1.save_context", Handlers::save_context);
     server.registerTool("kom.memory.v1.recall_context", Handlers::recall_context);
+    server.registerTool("kom.memory.v1.embed_text", Handlers::embed_text);
     server.registerTool("kom.memory.v1.upsert_memory", Handlers::upsert_memory);
     server.registerTool("kom.memory.v1.search_memory", Handlers::search_memory);
+    server.registerTool("kom.memory.v1.warm_cache", Handlers::warm_cache);
     server.registerTool("kom.local.v1.backup.export_encrypted", Handlers::backup_export_encrypted);
     server.registerTool("kom.local.v1.backup.import_encrypted", Handlers::backup_import_encrypted);
     server.registerTool("kom.meta.v1.project_snapshot", Handlers::project_snapshot);
diff --git a/src/mcp/Scope.hpp b/src/mcp/Scope.hpp
deleted file mode 100644
index 235d95b..0000000
--- a/src/mcp/Scope.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <string>
-
-struct Scope {
-    std::string namespace_id;
-    std::string user_id;
-    bool valid() const { return !namespace_id.empty(); }
-};
-
-// In a real qtmcp server, these would be derived from session/auth.
-inline Scope currentScope() {
-    // TODO: inject from session context / env. For now, return empty (invalid).
-    return Scope{};
-}
diff --git a/tests/contract/test_mcp_tools.cpp b/tests/contract/test_mcp_tools.cpp
index 0f3d1e2..aba00f4 100644
--- a/tests/contract/test_mcp_tools.cpp
+++ b/tests/contract/test_mcp_tools.cpp
@@ -32,15 +32,26 @@ if (!expect_contains(saveResp, "\"created_at\"", "save_context timestamp")) retu
 
     const std::string saveReqNoNamespace = R"({"key":"nogreeting","content":{"text":"remember this without namespace"},"tags":["context","demo"]})";
     std::string saveRespNoNamespace = server.dispatch("kom.memory.v1.save_context", saveReqNoNamespace);
-    if (!expect_contains(saveRespNoNamespace, "\"error\":{\"code\":\"bad_request\",\"message\":\"namespace is required\"}", "save_context without namespace should fail")) return 1;
+if (!expect_contains(saveRespNoNamespace, "\"error\":{\"code\":\"bad_request\",\"message\":\"namespace is required\"}", "save_context without namespace should fail")) return 1;
 
-const std::string recallReq = R"({"namespace":"tests","key":"greeting","limit":2})";
-std::string recallResp = server.dispatch("kom.memory.v1.recall_context", recallReq);
-if (!expect_contains(recallResp, "\"items\"", "recall_context items")) return 1;
-if (!expect_contains(recallResp, "\"confidence\":0.98", "recall_context returns payload")) return 1;
+    const std::string recallReq = R"({"namespace":"tests","key":"greeting","limit":2})";
+    std::string recallResp = server.dispatch("kom.memory.v1.recall_context", recallReq);
+    if (!expect_contains(recallResp, "\"items\"", "recall_context items")) return 1;
+    if (!expect_contains(recallResp, "\"confidence\":0.98", "recall_context returns payload")) return 1;
 
-std::string firstId;
-const std::string idsAnchor = "\"ids\":[\"";
+    const std::string recallMinReq = R"({"namespace":"tests"})";
+    std::string recallMinResp = server.dispatch("kom.memory.v1.recall_context", recallMinReq);
+    if (!expect_contains(recallMinResp, "\"items\"", "recall_context minimum parameters items")) return 1;
+    if (!expect_contains(recallMinResp, "\"id\"", "recall_context minimum parameters id")) return 1;
+
+    const std::string embedReq = R"({"namespace":"tests","texts":["hello world", "goodbye world"]})";
+    std::string embedResp = server.dispatch("kom.memory.v1.embed_text", embedReq);
+    if (!expect_contains(embedResp, "\"model\"", "embed_text model key")) return 1;
+    if (!expect_contains(embedResp, "\"vectors\"", "embed_text vectors key")) return 1;
+    if (!expect_contains(embedResp, "[[", "embed_text vectors content")) return 1;
+
+    std::string firstId;
+    const std::string idsAnchor = "\"ids\":[\"";
     auto idsPos = upsertResp.find(idsAnchor);
     if (idsPos != std::string::npos) {
         idsPos += idsAnchor.size();
@@ -63,6 +74,10 @@ const std::string idsAnchor = "\"ids\":[\"";
     std::string vectorResp = server.dispatch("kom.memory.v1.search_memory", vectorReq);
     if (!expect_contains(vectorResp, "\"id\":\""+firstId+"\"", "vector search returns stored id")) return 1;
 
+    const std::string warmCacheReq = R"({"namespace":"tests"})";
+    std::string warmCacheResp = server.dispatch("kom.memory.v1.warm_cache", warmCacheReq);
+    if (!expect_contains(warmCacheResp, "\"queued\"", "warm_cache queued key")) return 1;
+
     const std::string snapshotResp = server.dispatch("kom.meta.v1.project_snapshot", "{}");
     if (!expect_contains(snapshotResp, "\"sections\"", "snapshot sections key")) return 1;
 
