32 KiB
PrivateGPT Workbench PRD
Project Context
PrivateGPT is an open-source local AI API project. Its value proposition is not local inference itself, but the higher-level application layer built on top of any OpenAI-compatible local inference backend.
PrivateGPT aims to provide a local implementation of the capabilities developers and users expect from modern Claude-style APIs and applications, including:
- Chat/messages API
- File ingestion
- Retrieval with citations
- Text-to-SQL / database querying
- CSV and tabular analysis through sandboxed Python execution
- Web search and web extraction
- MCP support
- Skills
- Custom tools
- Embeddings and lower-level primitives
The demonstrator UI, tentatively called PrivateGPT Workbench, exists to make these API capabilities tangible.
For non-technical users, it should show PrivateGPT as:
A free, local AI assistant I can use to query documents, knowledge bases, websites, CSVs, and databases without relying on a cloud API key.
For developers, it should show PrivateGPT as:
A local Claude-compatible API layer I can build applications on top of.
This UI should remain a lightweight demonstrator, not the main product. It now lives inside the PrivateGPT repository under ./ui and must not become a heavy frontend application or a maintenance burden.
OpenAPI Source Of Truth
The API contract is defined by the Fern-generated repository-root relative OpenAPI file:
./fern/openapi/openapi.json
From the ./ui directory, the same file resolves as:
../fern/openapi/openapi.json
The Fern-generated OpenAPI file is the primary source of truth for:
- Available endpoints
- Request body shapes
- Response body shapes
- Schema names
- Supported tool/context structures
- Message block formats
- Artifact formats
- MCP/tool fields
- Future API changes
The implementation must inspect and follow the Fern-generated OpenAPI schema rather than relying only on this PRD's examples. Examples in this PRD are illustrative and should be corrected wherever the API contract differs.
Important current endpoints include:
POST /v1/messages
POST /v1/messages/count_tokens
POST /v1/messages/validate
GET /v1/models
POST /v1/artifacts/ingest
GET /v1/artifacts/list?collection=<collection>
POST /v1/artifacts/delete
POST /v1/artifacts/content
POST /v1/artifacts/chunked-content
POST /v1/primitives/search
POST /v1/tools/semantic-search
POST /v1/tools/tabular-data-analysis
POST /v1/tools/database-query
POST /v1/tools/web-fetch
POST /v1/tools/web-search
The implementation should treat POST /v1/messages as the central endpoint. Most of the product experience should flow through chat, with Context providing the inputs and Debugger explaining the underlying API interactions.
Before implementing request builders, parse or manually inspect ../fern/openapi/openapi.json and align all payloads with the current schemas, especially:
ChatBodyMessageInputToolSpecBodyContextFilterFileArtifactSqlDatabaseArtifactMcpServerConfig- Tool response block schemas
Visual And UX Source Of Truth
The product and implementation requirements in this PRD should be paired with the visual direction in this repository-root relative file:
./ui/docs/STYLE_GUIDE.md
From the ./ui directory, that file resolves as:
./docs/STYLE_GUIDE.md
That style guide includes repo-local reference images copied from the current brand/UI explorations:
./ui/references/primary-chat-layout.png
./ui/references/search-overlay.png
./ui/references/chat-tools-composer.png
./ui/references/context-knowledge-base.png
From ./ui, those files resolve as:
../references/primary-chat-layout.png
../references/search-overlay.png
../references/chat-tools-composer.png
../references/context-knowledge-base.png
Use the style guide as the source of truth for layout, glass surfaces, background treatment, sidebar behavior, chat composer treatment, Context rows, and Debugger visual density.
Purpose
PrivateGPT Workbench is a lightweight demonstrator UI for the PrivateGPT API. It should prove PrivateGPT's value as a local Claude-compatible AI application backend while staying simple enough to live inside the PrivateGPT repo as a non-core demo.
The app is not intended to become a full product, admin console, or design-system-heavy frontend. It is a practical local UI for trying the API, showing non-technical users what PrivateGPT can do, and helping developers understand how to build on top of it.
Primary Goals
- Let non-technical users experience PrivateGPT as a local AI assistant.
- Let users configure the local context available to the assistant: documents, databases, web search, MCP, skills, and custom tools.
- Let developers observe how the UI talks to the API through a lightweight session-level API Debugger.
- Keep implementation simple: ideally a single static HTML file with vanilla JS/CSS and browser
localStorage.
Non-Goals
- No user accounts.
- No server-side UI database.
- No projects, folders, organizations, or workspace hierarchy.
- No complex design system.
- No cloud sync.
- No heavy frontend framework unless absolutely necessary.
- No attempt to replace browser DevTools.
- No permanent debugger storage.
Architecture
Recommended initial implementation:
ui/
index.html
Single-file static app containing:
- HTML
- CSS
- JavaScript
Browser storage:
localStoragefor persistent app state.- In-memory state for debugger events.
Default PrivateGPT API base URL:
http://127.0.0.1:8001
Allow user override from inside the web application. Users must not need to edit config files to point the demonstrator at a different PrivateGPT deployment.
Connection settings should include:
- PrivateGPT API base URL
- Optional PrivateGPT API key / bearer token
If auth is configured, requests should include:
Authorization: Basic <base64(username:password)>
PrivateGPT API vs LLM Gateway
There are two separate connection concepts:
-
PrivateGPT API URL and auth
- This is what Workbench calls directly.
- This must be configurable in the Workbench UI.
- Default URL:
http://127.0.0.1:8001. - Supported auth in the Workbench UI: optional HTTP Basic auth only, entered as username and password fields.
-
LLM Gateway URL and auth
- This points PrivateGPT to the underlying inference provider, such as a local Ollama server.
- This is configured in PrivateGPT's own configuration files.
- Workbench must not expose LLM gateway configuration in the UI for v1.
- A common local LLM gateway default may be Ollama at
http://127.0.0.1:11434, but that belongs to PrivateGPT backend configuration, not Workbench.
All Workbench API calls should target the configured PrivateGPT API base URL. Do not call the LLM gateway directly from the browser UI.
For development and automated testing, a working PrivateGPT deployment may be available through local environment variables:
PGPT_BASE_URL
PGPT_TOKEN
The implementation may read these at runtime in local test scripts or dev-server setup, but must never store, print, commit, or hardcode the actual values.
Browser/CORS behavior should prioritize the local case first. The app should work when served locally against a local PrivateGPT API. If deployed elsewhere, it should still allow the user to configure API URL and token, but any required cross-origin server policy must be handled by the PrivateGPT deployment.
High-Level UI
The app has a persistent left sidebar and a main content area.
Sidebar
Context
New Chat
Chats
Contract review
CSV analysis
Database demo
Custom tool test
API Debugger
Settings
GitHub
Not for Production
Main
If first launch or onboarding restarted:
Guided onboarding overlay
Step 1: URL + collection + live checks
Step 2: Optional look-and-feel customization
If Context selected:
Context configuration screen
If Settings selected:
PrivateGPT API connection settings and assistant behavior
If API Debugger selected:
Session-level API request/response trace
If Chat selected:
Chat interface
Persistent State
Store in localStorage:
{
privateGptBaseUrl: string,
privateGptUsername: string,
privateGptPassword: string,
systemPrompt: string,
useCitations: boolean,
selectedModel: string | null,
uiAppearance: {
brief: string,
brandName: string,
welcomeTitle: string,
welcomeSubtitle: string,
customInstructions: string,
palette: {
accent: string,
secondary: string,
surface: string,
background: string
},
features: {
databases: boolean,
web: boolean,
mcp: boolean,
skills: boolean,
customTools: boolean,
apiDebugger: boolean,
github: boolean,
productionNotice: boolean
}
},
onboarding: {
completed: boolean,
step: 1 | 2,
appearanceSkipped: boolean,
lastCheck: {
ok: boolean,
testedAt: string,
summary: string,
steps: Array<{ label: string, detail: string, ok: boolean | null }>
} | null
},
context: {
documents: {
defaultCollection: string
},
databases: DatabaseConfig[],
mcpServers: McpServerConfig[],
skills: SkillConfig[],
customTools: CustomToolConfig[]
},
chats: ChatSession[],
activeChatId: string | null
}
Chat session:
type ChatSession = {
id: string;
title: string;
createdAt: string;
updatedAt: string;
messages: ChatMessage[];
settings: {
enabledDocuments: boolean;
enabledDatabases: string[];
enabledWeb: boolean;
enabledMcpServers: string[];
enabledSkills: string[];
enabledCustomTools: string[];
model: string | null;
};
};
Do not store debugger data.
On reload:
- Onboarding stays dismissed after successful completion.
- Context comes back.
- Chat list comes back.
- Chat messages come back.
- Chat-specific tool toggles come back.
- Appearance overrides and optional feature visibility come back.
- Debugger is empty.
Sidebar Behavior
Sidebar items:
-
Context
- Opens global Context screen.
-
New Chat
- Creates new chat session.
- Sets default title like
New chat. - Copies default context settings from global defaults.
- Opens the new chat.
-
Chat List
- Shows persisted chats sorted by
updatedAt DESC. - Selecting a chat opens it.
- Current chat is highlighted.
- Allow rename/delete through small inline menu or simple buttons.
- Long chat titles must truncate with ellipsis.
- The sidebar and chat list must never show a horizontal scrollbar.
- Shows persisted chats sorted by
-
API Debugger
- Opens the session-level request/response trace.
- Place this in the bottom sidebar group above Settings.
-
Settings
- Opens PrivateGPT API connection settings.
- Place this in the bottom sidebar group below API Debugger.
-
GitHub
- Links to the PrivateGPT repository.
- Shows live repository stars when GitHub is reachable.
- Place this below Settings.
-
Not for Production
- Opens a modal explaining that this UI is a local demonstrator, not a production-ready application.
- Place this below the GitHub widget.
No projects or grouping.
Settings Screen
The Settings screen owns Workbench-level configuration that is not part of assistant context.
Settings include:
- PrivateGPT API base URL.
- Optional HTTP Basic auth (username and password).
- Optional system prompt.
- Optional workspace instructions prepended ahead of the system prompt.
- Use citations toggle, enabled by default.
- Collection — the active document collection name used for document ingestion, listing, deletion, search, and chat requests. This field belongs in Settings because it is a global Workbench-level pointer, not a per-context source configuration.
- Look-and-feel overrides for brand copy, welcome copy, palette, and optional visible sections.
- Run onboarding again.
- Test API connection.
- Save settings.
- Clear local browser data.
The PrivateGPT API settings should not live in the Context screen. Context is for sources/tools the assistant can use; Settings is for how Workbench connects to PrivateGPT.
The system prompt also belongs in Settings because it controls global assistant behavior. Send it through the top-level system field in ChatBody, not as a system role message. If the user leaves it empty, do not send system prompt text. A system object may still be sent without text when needed for request-level options such as citations.enabled.
The Use citations toggle controls whether document-enabled chats request citation-annotated answers. It should be enabled by default.
The Clear local data action removes this Workbench's saved chats, settings, token, context, and preferences from browser localStorage. It must not imply deletion of data stored in PrivateGPT itself, such as ingested documents or backend configuration.
Onboarding
On first launch, Workbench should open an onboarding overlay before normal use.
Step 1 requirements:
- Collect PrivateGPT base URL.
- Collect optional HTTP Basic auth.
- Collect the active collection ID.
- Save those values into the same persistent state used by Settings.
- Run live checks against:
GET /v1/modelsGET /v1/artifacts/list?collection=<collection>GET /v1/skills?collection=<collection>
- Show a simple pass/fail checklist and block progression until the checks pass.
Step 2 requirements:
- Must be skippable.
- Must accept a natural-language theme brief and use the configured LLM through
POST /v1/messagesto generate a starting appearance proposal. - Must show the generated result before the user finishes onboarding.
- Must allow customizing brand name, welcome text, workspace instructions, colors, and optional visible sections after generation.
- GitHub/Zylon references must remain visible and must not be removable through generated or manual appearance settings.
- Must write into persistent appearance variables that override the runtime UI state and CSS custom properties.
- Must remain editable later from Settings or by rerunning onboarding.
Not For Production Disclosure
The sidebar should include a persistent Not for Production disclosure below the GitHub widget.
Clicking it opens a closable glass-style modal titled:
This demonstrator is not intended for Production use
The modal should explain that Workbench is useful for trying API capabilities, debugging requests, and exploring local AI workflows, but should not be published as a production application.
The disclosure should cover four concise risks:
- Browser storage is not secure secret storage. The bearer token, chats, context configuration, and settings are saved in
localStorage. - There is no application-level access control. Anyone with access to the page can use the configured API endpoint, token, tools, documents, and model access.
- Debugging data is intentionally visible. API Debugger can show prompts, document excerpts, headers, metadata, requests, and responses.
- Custom tools run browser JavaScript. Only trusted code should be used, and the UI should not be exposed without a reviewed deployment model.
End the modal with a commercial Zylon CTA:
- Link
Zylontohttps://zylon.ai. - Link
book a demo with our teamtohttps://cal.com/zylon/demo?source=privategptui. - Use this text:
Zylon is an enterprise AI platform delivering on-premise generative AI infrastructure for regulated industries, enabling secure deployment without external cloud dependencies.
Context Screen
The Context screen defines what the assistant can use.
Sections:
Documents
Databases
Web
MCP
Skills
Custom Tools
A compact tab or accordion layout is acceptable.
Documents
Purpose: manage ingested local knowledge.
Capabilities:
- Set collection name.
- Upload local files.
- Ingest files through
POST /v1/artifacts/ingest. - List ingested artifacts through
GET /v1/artifacts/list?collection=<collection>. - Delete artifacts through
POST /v1/artifacts/delete. - Optional diagnostic search box using
POST /v1/tools/semantic-search. - Optional content preview using
POST /v1/artifacts/content.
The collection field is important and must be user-configurable. Some PrivateGPT deployments create collections on the fly, while others sit behind a gateway that restricts each bearer token to one or more allowed collections. If a deployment enforces allowed collections, ingest/list/search calls must use one of those allowed collection ids or the API may reject the request.
The Collection field lives in Settings, not in the Documents panel. It applies globally and is used for:
- Document ingestion.
- Document listing.
- Document deletion.
- Document search.
- Document-enabled chat requests.
There is one active collection for the Workbench. Do not expose a separate chat-level collection selector in v1.
Upload behavior:
- Convert file to base64.
- Use an artifact id derived from filename plus timestamp or UUID.
- Include metadata with
file_name.
Example ingest body:
{
"artifact": "contract-2026-05-14",
"collection": "default",
"input": {
"type": "file",
"value": "<base64>"
},
"metadata": {
"file_name": "contract.pdf"
}
}
Documents In Chat
When a chat has Documents enabled, the /v1/messages call should enable the semantic search tool and scope it to the configured Documents collection.
Use this request pattern:
{
"model": "default",
"messages": [
{
"role": "user",
"content": "Find the property address in the documents. Answer just with the address, no extra text."
}
],
"tools": [
{
"name": "semantic_search",
"type": "semantic_search_v1"
}
],
"tool_context": [
{
"type": "ingested_artifact",
"context_filter": {
"collection": "<configured-collection>",
"artifacts": []
}
}
]
}
An empty artifacts array means search all documents within the configured collection.
Databases
Purpose: define SQL database artifacts available to chat.
Stored locally only.
Fields:
idnameconnection_stringdescriptionschemas, optional comma-separated listsslenable_tablesenable_viewsenable_functionsenable_procedures
When selected in chat, convert database configs into tool_context artifacts:
{
"type": "sql_database",
"connection_string": "...",
"schemas": null,
"ssl": false,
"enable_tables": true,
"enable_views": true,
"enable_functions": true,
"enable_procedures": true,
"description": "Local sales database"
}
Web
Purpose: explain web capabilities and let chat-level Tools decide whether to use them.
Do not collect web provider names, API keys, or extra web configuration in Workbench.
The current OpenAPI exposes:
POST /v1/tools/web-searchPOST /v1/tools/web-fetch
The web search provider and its credentials belong in PrivateGPT backend config. In Workbench, show static explanatory text in Context > Web and let the chat Tools menu decide whether web_search and web_extract are included in a chat request. The direct diagnostic endpoint may still be named /v1/tools/web-fetch; for /v1/messages, use the chat tool spec { "name": "web_extract", "type": "web_extract_v1" }.
MCP
Purpose: configure MCP connectors.
Fields:
idnameserver_config_jsonallowed_tools, optional list
The OpenAPI supports mcp_servers on ChatBody. The UI should allow raw JSON editing initially to avoid over-designing unknown MCP variants.
Example UI:
- Name input
- JSON textarea
- Validate JSON button
Skills
Purpose: configure available skills.
Use the backend skills API scoped to the single active Workbench collection.
Fields:
iddisplay_titlecollectionlatest_versionsourceloadingreadonly
Operations:
GET /v1/skills?collection=<collection>to list skills for the active collection.POST /v1/skillsmultipart create for new skills.POST /v1/skills/{skill_id}/versionsmultipart create for new versions.DELETE /v1/skills/{skill_id}?collection=<collection>for non-readonly skills.
When chat requests are built, selected skills should be represented as a tool_context artifact:
{
"type": "skill",
"skill_filter": {
"collection": "<configured-collection>",
"skill_or_version_ids": ["<selected-skill-id>"]
}
}
Custom Tools
Purpose: let users define Claude-style custom tools and browser-executed JavaScript handlers.
Fields:
idnamedescriptioninput_schema_jsonjavascript_handlertest_input_jsonlast_test_result
Tool definition shape:
{
"name": "currency_converter",
"description": "Convert USD to EUR using a locally configured exchange rate.",
"inputSchema": {
"type": "object",
"properties": {
"amount": {
"type": "number"
}
},
"required": ["amount"]
}
}
Handler shape:
async function handle(input, context) {
const rate = Number(context.localStorage.getItem("usd_eur_rate") || "0.92");
return {
type: "text",
text: `${input.amount} USD is approximately ${input.amount * rate} EUR.`
};
}
Handler execution context:
{
fetch: window.fetch.bind(window),
localStorage: window.localStorage,
privateGptBaseUrl: string,
currentChatId: string,
currentCollection: string,
log: (message: string, data?: unknown) => void
}
Use browser execution directly. No extra sandbox is required for v1, because the user is explicitly authoring local browser code.
Custom tool test:
- Parse test input JSON.
- Execute handler.
- Show result or error.
- Add debugger event if currently inside a chat context, otherwise just show local result.
Chat Screen
Main non-technical experience.
Header controls (in the composer toolbar below the textarea):
- Model selector — a custom glass dropdown populated from
GET /v1/models, showing the current model name with an animated chevron. Selecting a model updatesstate.selectedModel. - Refresh models icon button next to the model selector.
- Extended Thinking toggle — a
ghost-buttonchip showing a zap icon and the labelThinking. Activating it enables extended thinking mode for the active chat. Active state uses a purple tint and glow. - Tools button — opens the Tools menu popup with per-category toggles:
- Documents
- Web
- Databases
- MCP
- Skills
- Custom Tools
For databases, MCP, skills, and custom tools:
- Show configured items as selectable chips/dropdowns.
- Store selections per chat.
Message composer:
- Text input.
- Send button.
- Pressing
Enterwhile focused in the composer sends the message. - Pressing
Shift+Enterinserts a line break.
Message rendering:
- User messages.
- Assistant messages.
- Text blocks rendered as Markdown.
- Tool use blocks rendered as collapsed details blocks.
- Tool result blocks rendered as collapsed details blocks.
- Inline
<citation ...></citation>tags must never be rendered as text. - Inline citation tags must be replaced with small circular clickable citation markers, labelled only with the citation index. If the raw citation tag uses a zero-based
indexattribute, displayindex + 1. - Multiple inline citations may display the same number when they reference the same citation index.
- Do not render a separate citation list at the bottom of the message.
- Clicking a citation marker opens a closable glass-style popup with citation metadata and the source excerpt text from the original document when available.
- For semantic-search tool results, extract the source excerpt from the
tool_resultpayload by parsing the JSON text, matching the inline citation id againstnodes[].id, and using the matched node'scontentfield as the excerpt. The matcher should tolerate bracket differences such as4C40vs[4C40]. - Errors clearly shown.
- Do not show a raw response block in Chat; raw request/response details belong in Debugger.
- While waiting for PrivateGPT, show an in-chat pending response indicator using the PrivateGPT circular avatar with a subtle breathing animation.
Request behavior:
- Use
POST /v1/messages. - Build
ChatBodyfrom chat messages plus chat-selected context/tools. - Use the selected model id from the
/v1/modelsresponse. If models have not been loaded yet, fall back todefault. - Prefer the user-configured Settings system prompt when present.
- If no system prompt or skill instructions are present, omit system prompt text.
- When Documents are enabled and Settings > Use citations is on, send
system.citations.enabled: trueso semantic-search answers can include citation tags. This may require a top-levelsystemobject even when no prompt text is configured. - Always send system instructions through the top-level
systemfield so they are applied consistently across the whole request.
Basic request body:
{
"model": "default",
"messages": [
{
"role": "user",
"content": "Summarize my documents and cite sources."
}
],
"system": {
"text": "You are a support agent. Reply with only a short ticket title.",
"use_default_prompt": false,
"citations": {
"enabled": true
}
},
"tools": [],
"tool_context": [],
"mcp_servers": [],
"stream": false,
"max_tokens": 4096
}
Tool/context building:
- If Documents are enabled, add the semantic search tool and an
ingested_artifacttool context scoped to the global Context Documents collection. Useartifacts: []to search all documents in that collection. - If Databases are selected, add selected SQL database artifacts to
tool_context. - If MCP connectors are selected, add selected MCP server configs to
mcp_servers. - If Custom Tools are selected, add selected custom tool definitions to
tools. - If Skills are selected, add skill prompt/config support according to current backend conventions.
Custom Tool Loop
If assistant response contains a tool_use block for a custom browser tool:
- Find matching custom tool by name.
- Execute the JavaScript handler with
toolUse.input. - Append the tool result to the same visible assistant message bubble (not as a separate message).
- Send a follow-up
POST /v1/messageswith the tool result in the API history. - Stream the final assistant answer into the same bubble.
- API calls made during the loop appear in API Debugger.
The entire tool execution cycle — initial response, tool result, and follow-up answer — appears as a single consolidated assistant message bubble in chat. Hidden messages carrying tool roles exist in the API history only and are never rendered in the chat UI.
Follow-up messages should preserve the prior conversation and include the tool result using the API's expected content block shape.
If the handler fails:
- Show the error inline in the chat bubble.
- Log request/response errors in Debugger.
- Send a tool result with
is_error: trueif appropriate.
URL Hash Navigation
The app uses hash-based navigation so that reloading the page restores the current view and context tab.
Hash format:
#context/{tab}— Context screen with a specific tab (documents,databases,web,mcp,skills,customTools).#settings— Settings screen.#apiDebugger— API Debugger screen.#chat/{chatId}— Specific chat session by ID.
syncHash() is called at the end of every render() and after context tab changes. restoreFromHash() runs once at startup before the first render and on hashchange for browser back/forward support.
API Debugger Screen
API Debugger is session-level, live-only, and ephemeral.
Do not persist debugger events.
Show a small non-intrusive callout near the top of API Debugger explaining that it is a live trace for the current session and clears on page refresh.
Purpose:
- Teach developers how chat interactions map to API calls.
- Show request/response payloads and errors.
- Show redacted request headers when useful.
Debugger layout:
Timeline list | Event detail panel
Event model:
- One timeline entry per API call.
- The entry may start as pending, then update in place with the response or error.
- Do not show separate request and response entries for the same API call.
Each API event should include:
- timestamp
- method
- URL
- redacted request headers
- status
- duration
- request JSON
- response JSON or error
Secrets must never be displayed in Debugger. Redact Authorization, token-like headers, API keys, and cookies.
API Debugger should show API events from the current page lifetime, including calls made from Chat, Context, and Settings.
On reload, debugger is empty.
API Client
Implement a tiny client wrapper:
async function apiFetch(path, options, debugMeta)
Responsibilities:
- Prefix with
privateGptBaseUrl. - Set JSON headers.
- Build
Authorization: Basic <base64(username:password)>from the configured username and password when provided. - Measure duration.
- Parse JSON/text response.
- Log request/response/error to the session-level API Debugger buffer.
- Throw useful errors.
Endpoints used from OpenAPI:
GET /v1/modelsPOST /v1/messagesPOST /v1/messages/count_tokens, optionalPOST /v1/messages/validate, optionalPOST /v1/artifacts/ingestGET /v1/artifacts/list?collection=<collection>POST /v1/artifacts/deletePOST /v1/artifacts/content, optionalPOST /v1/tools/semantic-searchPOST /v1/tools/tabular-data-analysis, optional direct diagnosticPOST /v1/tools/database-query, optional direct diagnosticPOST /v1/tools/web-search, optional direct diagnosticPOST /v1/tools/web-fetch, optional direct diagnostic
Streaming/async endpoints can be deferred:
/v1/messages/async/v1/messages/async/{message_id}/stream
UX Principles
- The app should feel like a practical local assistant, not a marketing page.
- Chat is the primary surface.
- Context explains what the assistant can access.
- Debugger explains what happened under the hood.
- Keep controls dense but readable.
- Avoid large decorative cards or landing-page hero sections.
- Use plain, utilitarian UI.
- Prefer native controls and simple CSS.
- All errors should be visible and actionable.
MVP Acceptance Criteria
- User can configure API base URL.
- User can configure an optional API key / bearer token from the UI.
- User can load models from
GET /v1/modelsand select one for each chat. - User can create, rename, delete, and switch local chat sessions.
- Chat sessions persist across reload.
- Chat-specific tool toggles persist across reload.
- User can send a basic chat message to
/v1/messages. - User can upload and ingest documents.
- User can list ingested documents.
- User can enable document context for chat.
- Document-enabled chat requests add the
semantic_searchtool and aningested_artifacttool context scoped to the configured Documents collection. - User can configure database artifacts locally.
- User can configure MCP, skills, and custom tools locally, and can see that web provider credentials are configured in the PrivateGPT backend rather than in Workbench.
- User can define a custom tool with name, description, JSON schema, and JavaScript handler.
- Chat can pass selected custom tools to the API.
- Chat can execute a browser JavaScript handler when the assistant emits a matching tool call.
- API Debugger shows live API request/response/error events for the current browser session, with sensitive headers redacted.
- API Debugger events disappear after browser reload.
- No backend storage is introduced for the UI.
- App works as a static file.
- The implementation references the repository's relative OpenAPI file as the API contract and does not hardcode payload assumptions that contradict the schema.
- Sidebar includes a GitHub repository widget and a Not for Production disclosure.
- Settings includes a Clear local data action for this Workbench's browser state.
Suggested Build Order
- Static layout: sidebar, Context screen, Chat screen, API Debugger screen.
localStoragestate model.- API base URL and model loading.
- Chat sessions.
- Basic
/v1/messageschat. - Debugger event recorder.
- Documents ingestion/list/delete.
- Chat tool/context toggles.
- Database/Web/MCP/Skills config forms.
- Custom tool definition UI.
- Browser JavaScript handler execution loop.
- Polish errors, empty states, and reload behavior.