📘 Lesson 6 — Multi-Folder Workspaces (Switch Between Knowledge Bases)
How to let your Apps Script + Gemini assistant dynamically switch between multiple folders (each with its own RAG index).

🔥 What Lesson 6 Adds
Until now, your assistant worked with exactly one folder, and one RAG index sheet.
Lesson 6 adds the ability to manage multiple “workspaces”, each with:
– A Drive Folder
– Its own RAG Index (a tab in the same spreadsheet OR multiple spreadsheets)
– A name (e.g. “Policies”, “Project X”, “Onboarding Docs”)
– A selectable workspace dropdown in the web UI
This means your AI assistant can answer questions like:
“Switch to the Onboarding Docs workspace.”
“Now answer using the Policies workspace.”
“Use the Research Notes workspace.”
Each workspace becomes a separate knowledge brain.
🎯 Learning Objectives
By the end of Lesson 6, you will be able to:
✔ Allow your AI to switch between multiple Drive folders
✔ Maintain a RAG index per workspace
✔ Add a workspace selector UI
✔ Load the correct embeddings for each workspace
✔ Keep chat history separate per workspace
✔ Enable “Reset per workspace”
🧱 Lesson 6 Architecture Overview

+—————————+
| Workspace Registry | <– A JSON list saved in Script Properties
+—————————+
| |
| |
v v
Workspace A Workspace B Workspace C
———— ———— ————
– Folder ID – Folder ID – Folder ID
– Index Sheet – Index Sheet – Index Sheet
– Chat History – Chat History – Chat History
Each workspace has:
{
name: “Policies”,
folderId: “1xxxx”,
sheetId: “1xxxx (Spreadsheet for RAG index)”
}
Your assistant receives:
– Selected workspace
– Retrieves RAG index for that workspace
– Uses its Drive folder, embeddings, and chat history
– Answers
🧩 Part 1 — Store Workspaces in Script Properties
Add this new property:
WORKSPACES
Containing JSON:
[
{
“name”: “Policies”,
“folderId”: “xxxxx”,
“sheetId”: “xxxxx”
},
{
“name”: “Onboarding”,
“folderId”: “yyyyy”,
“sheetId”: “yyyyy”
}
]
Add helper functions into a new file named:
Lesson6_Workspaces.gs
✅ 1. Workspace Registry Helpers
const WORKSPACE_KEY = ‘WORKSPACES’;
/**
* Returns array of workspaces:
* [{name, folderId, sheetId}, …]
*/
function getWorkspaces_() {
const s = PropertiesService.getScriptProperties().getProperty(WORKSPACE_KEY);
if (!s) return [];
try { return JSON.parse(s); }
catch(e) { return []; }
}
/**
* Saves workspace list.
*/
function saveWorkspaces_(arr) {
PropertiesService.getScriptProperties()
.setProperty(WORKSPACE_KEY, JSON.stringify(arr));
}
/**
* Add a new workspace.
*/
function addWorkspace(name, folderId, sheetId) {
const ws = getWorkspaces_();
ws.push({ name, folderId, sheetId });
saveWorkspaces_(ws);
return ws;
}
🧩 Part 2 — Selecting a Workspace
We store the user’s active workspace in the User Cache:
const ACTIVE_WORKSPACE_KEY = ‘ACTIVE_WORKSPACE’;
function setActiveWorkspace(name) {
const ws = getWorkspaces_();
const found = ws.find(w => w.name === name);
if (!found) throw new Error(“Workspace not found: ” + name);
CacheService.getUserCache().put(
ACTIVE_WORKSPACE_KEY,
JSON.stringify(found),
3600
);
return found;
}
function getActiveWorkspace_() {
const cache = CacheService.getUserCache();
const raw = cache.get(ACTIVE_WORKSPACE_KEY);
if (!raw) return null;
try { return JSON.parse(raw); }
catch(e) { return null; }
}
🧩 Part 3 — Updating Lesson 4C to Use Workspaces
Modify answerWithChatRag to load:
– workspace RAG index
– workspace chat history
function answerWithChatRagMulti(question) {
const q = question.trim();
if (!q) throw new Error(“Question empty”);
const ws = getActiveWorkspace_();
if (!ws) throw new Error(“No active workspace selected.”);
// load index for THIS workspace
const index = loadRagIndexForSheet_(ws.sheetId);
// history is unique per workspace
const historyKey = CHAT_HISTORY_KEY + “_” + ws.name;
const history = getChatHistoryForKey_(historyKey);
// everything else is the same as Lesson 4C
// … similarity search, Gemini call …
// save history under workspace-specific key
saveChatHistoryForKey_(historyKey, updatedHistory);
return {
answer,
sources,
workspace: ws.name
};
}
Add helper functions:
function getChatHistoryForKey_(key) {
const cache = CacheService.getUserCache();
const json = cache.get(key);
if (!json) return [];
try { return JSON.parse(json); }
catch(e) { return []; }
}
function saveChatHistoryForKey_(key, history) {
CacheService.getUserCache().put(key, JSON.stringify(history), 21600);
}
🧩 Part 4 — Updating the Web App (UI)
Add a workspace dropdown:
<select id=”workspaceSelect” onchange=”onWorkspaceChange()”>
</select>
Populate it when the page loads:
function init() {
google.script.run
.withSuccessHandler(function (ws) {
const sel = document.getElementById(“workspaceSelect”);
sel.innerHTML = “”;
ws.forEach(w => {
const opt = document.createElement(“option”);
opt.value = w.name;
opt.textContent = w.name;
sel.appendChild(opt);
});
})
.getWorkspacesPublic(); // wrapper for getWorkspaces_()
}
Implement workspace switching:
function onWorkspaceChange() {
const name = document.getElementById(“workspaceSelect”).value;
google.script.run
.withSuccessHandler(function () {
addSystemMessage(“Workspace switched to: ” + name);
document.getElementById(“messages”).innerHTML = “”;
})
.setActiveWorkspacePublic(name);
}
Add these two public functions in Apps Script:
function getWorkspacesPublic() {
return getWorkspaces_();
}
function setActiveWorkspacePublic(name) {
return setActiveWorkspace(name);
}
🧩 Part 5 — RAG in the New Workspace
Your original buildRagIndex() now becomes:
function buildRagIndexForWorkspace(name) {
const ws = getWorkspaces_().find(w => w.name === name);
if (!ws) throw new Error(“Workspace not found: ” + name);
return buildRagIndex_(ws.folderId, ws.sheetId);
}
This allows:
buildRagIndexForWorkspace(“Policies”);
buildRagIndexForWorkspace(“Onboarding”);
buildRagIndexForWorkspace(“Project A”);
🧪 What Users Can Do Now
Try:
✔ “Switch workspace to Project A.”
✔ “Where is the onboarding checklist stored?”
✔ “Reset workspace chat.”
✔ “Build RAG index for Policies.”
✔ “Now answer using Policies.”
You now have a multi-brain AI system, each workspace isolated with:
– Its own documents
– Its own embeddings
– Its own chat memory
This is extremely close to a lightweight Notion AI, ChatGPT Files, or Mini RAG Assistant.