Client Applications & UX¶
Precis¶
This document is the canonical reference for everything Thinklio presents to its users. It covers the plain-language user guide that explains what the product does and how to work with it; the detailed UI specification for the Thinklio app at app.thinklio.ai (pages, layout, components, states, role-based visibility); the documentation and developer portal that powers /docs and /developer on the marketing site; and the internationalisation architecture that governs how every surface adapts to language, locale, and formatting conventions.
It absorbs four pre-consolidation documents that each described one facet of the same surface area: old doc 12 (user guide), old doc 18 (internationalisation discussion paper), old doc 23 (app UI specification), and old doc 29 (docs and developer UI).
The document is organised into four parts. Part A is the end-user guide, written for individuals, team members, and administrators. It introduces agents, composition and delegation, Agent Studio, knowledge, channels, tools, jobs, and governance in the order a new user encounters them. Part B is the full UI specification for the Thinklio app: technology stack, brand and theme system, layout and navigation, every page and tab, the agent lifecycle the app surfaces, the Predictive Planner controls, responsive behaviour, state management, role-based visibility, the client and admin data models, the component library, the file structure, and the backend integration contract. Part C covers the documentation and developer portal: the unified schema that powers both /docs and /developer, the shared layout components, the developer-only code panel and endpoint cards, the route structure, and the content organisation. Part D is the internationalisation architecture: nine target languages at launch, the two translation surfaces (deterministic platform strings versus generative agent responses), locale resolution rules, the resource bundle layout, agent response localisation via system prompt injection, data model additions, CJK considerations, phasing, and the open questions ADR-017 defers to formal specification.
Several editorial updates in this consolidation reflect the Convex + Clerk architecture adopted since these source documents were written. Authentication throughout the app is handled by Clerk (not Supabase Auth); REST-style API calls are replaced by Convex queries, mutations, and actions (not handwritten HTTP endpoints); platform string formatting is handled in TypeScript using the Intl API and a catalogue library (not golang.org/x/text). Every such change is noted in-place, and the original API contracts are preserved in the archive. The functional behaviour described (role-gated UI, briefing structure, i18n resolution order) is unchanged.
Part A is the place to start if you are new to Thinklio. Part B is the place to start if you are building or reviewing the app UI. Part C is the place to start if you are working on public documentation or the developer portal. Part D governs every surface and should be consulted whenever a string, date, number, currency, or agent-generated response crosses a locale boundary.
Table of contents¶
- Part A: End-user guide
- 1. Welcome to Thinklio
- 2. Getting started
- 3. Core concepts
- 4. Using your agent
- 5. Privacy and data
- 6. Troubleshooting
- 7. Getting help
- Part B: Thinklio app UI specification
- 1. Overview
- 2. Technology stack
- 3. Brand and theme system
- 4. Layout and navigation
- 5. Authentication and welcome
- 6. Pages
- 7. Agent lifecycle
- 8. Predictive Planner
- 9. Responsive behaviour
- 10. State management
- 11. Data model summary
- 12. Component library
- 13. File structure
- 14. Backend integration
- Part C: Documentation and developer portal UI
- 1. Overview
- 2. Data model
- 3. UI components
- 4. Route structure
- 5. User docs content structure
- 6. Developer docs content structure
- 7. Backend migration plan
- 8. Design decisions
- Part D: Internationalisation
- 1. Target languages
- 2. Two translation surfaces
- 3. Locale resolution
- 4. Platform string architecture
- 5. Agent response localisation
- 6. Data model additions
- 7. API response pattern
- 8. CJK considerations
- 9. Phasing
- 10. Open questions
- 11. ADR-017
- References
- Revision history
Part A: End-user guide¶
Part A is written for the people who actually use Thinklio: individuals running a personal agent, team members sharing agents with colleagues, and administrators configuring agents for their organisation. It describes the concepts in the order a new user encounters them and uses language suitable for product help content. Sections 2 onwards correspond to the pages that render in the /docs portal described in Part C.
1. Welcome to Thinklio¶
Thinklio gives you AI agents that think, act, and learn on your behalf. Whether you're using a personal assistant agent or your organisation has deployed agents for your team, this guide helps you get the most from Thinklio.
2. Getting started¶
2.1 For individual users¶
- Sign up. Create your account at thinklio.ai.
- Create your agent. Choose a template or start from scratch. Give your agent a name and tell it what you'd like help with.
- Connect a channel. Link your Telegram account (more channels coming) so you can chat with your agent wherever you already communicate.
- Start talking. Send your agent a message. It will respond based on its knowledge and the tools available to it.
2.2 For team members¶
- Accept your invitation. Your team admin will send you an invite to join the team on Thinklio.
- Access your team's agent. Once you've joined, you can interact with the agents assigned to your team.
- Contribute to team knowledge. As you work with the agent, it learns from your conversations. Information relevant to the team is shared; personal details stay private.
2.3 For administrators¶
- Set up your account. Create your account and configure billing.
- Create agents. Build agents for specific purposes (customer support, research, project management) or use templates.
- Compose agents. Use Agent Studio to build sophisticated agents that delegate to specialist agents.
- Assign agents to teams. Give your teams access to the agents they need, with appropriate permission restrictions per team.
- Configure policies. Set rules about what agents can do, how much they can spend, how deep delegation chains can go, and what requires approval.
3. Core concepts¶
3.1 Agents¶
An agent is your AI assistant. Each agent has its own personality, knowledge, and capabilities. Some agents are generalists, good at many things. Others are specialists, deeply knowledgeable about a specific domain.
Agents can:
- Answer questions using their knowledge
- Use tools (search the web, manage tasks, call APIs)
- Delegate to other specialist agents for specific tasks
- Dispatch long-running work and deliver results when ready
- Remember context from your conversations
- Learn and improve over time
3.2 Agent composition and delegation¶
Agents can work together. A personal assistant agent can delegate to specialist agents: a scheduler agent for calendar management, a research agent for information gathering, a domain expert for specialised questions.
From your perspective, you interact with one agent. Behind the scenes, it coordinates with its delegates to get you the best result. All of this is tracked, governed, and cost-attributed the same as direct interactions.
Your administrator configures which agents can delegate to which, and what each delegate is allowed to do. The same scheduler agent might have full calendar access when serving one team and read-only access for another.
3.3 Agent Studio¶
Agent Studio is the visual tool for composing agents. Team leads and administrators use it to:
- Define an agent's personality and instructions
- Attach specialist agents as delegates
- Configure what each delegate can do
- Upload knowledge documents
- View the delegation structure as a visual graph
- Use templates for common compositions (for example, "Personal Assistant with Scheduler and Research")
3.4 Knowledge¶
Your agent builds knowledge from every interaction. This knowledge is organised in layers:
- What the agent knows: its built-in domain expertise.
- What your organisation has shared: policies, procedures, reference material.
- What your team has discussed: shared project context, client details, decisions.
- What it knows about you: your preferences, your context, your history.
Your personal knowledge is private. Your teammates cannot see what the agent knows about you specifically, even when you're sharing the same agent.
When your agent delegates to another agent, each agent maintains its own knowledge. The scheduler agent's knowledge about your meeting preferences stays with the scheduler. Your personal assistant benefits from this indirectly: next time it delegates to the scheduler, the scheduler already knows your preferences.
3.5 Channels¶
You can talk to your agent through different communication tools:
- Telegram: chat with your agent in Telegram.
- Web chat: interact through a browser.
- API: connect your own applications.
Your conversation continues seamlessly across channels. Start a conversation in Telegram and pick it up on the web: your agent remembers the context.
3.6 Tools¶
Agents can use tools to take actions beyond just conversation:
- Search the web for current information
- Create and manage tasks
- Call external APIs and services
- Execute workflows
- Delegate to other specialist agents
Tool access is controlled by your administrator. Some tools are read-only (searching, looking things up), others can make changes (creating tasks, sending messages), and some require your explicit approval before the agent proceeds. The same agent may have different tool permissions depending on which team it is serving.
3.7 Jobs and deferred work¶
Some tasks take longer than a quick response. When you ask your agent to do something that will take a while (a comprehensive research task, a document generation workflow, or something that needs human review) the agent will:
- Acknowledge your request
- Start the work in the background
- Let you know when results are ready (or when useful partial results are available)
You can continue chatting with your agent while the work is in progress. The results will be delivered in the same conversation when they are ready.
If you change your mind, you can ask your agent to cancel a pending task.
3.8 Governance¶
If you're part of an account, your administrator sets policies that govern what agents can do. This might include:
- Which tools agents can access
- How much agents can spend per interaction
- What topics are off-limits
- What actions require human approval
- How many levels of agent-to-agent delegation are allowed
These policies exist to make agents trustworthy in professional settings. You'll see clear messages when a policy affects an agent's response.
4. Using your agent¶
4.1 Conversations¶
When you send a message to your agent, it:
- Gathers relevant context (your history, team knowledge, your preferences)
- Thinks about what you need
- Takes action if needed (uses tools, delegates to specialists, starts background work)
- Responds with its answer or result
Each conversation is tracked as a session. Within a session, the agent remembers what you've discussed. You can start a new session when you want a fresh context.
4.2 Commands¶
Command details will be added as features are implemented.
4.3 Tips for better interactions¶
- Be specific. "Summarise the key points from our project discussion last week" works better than "What happened?"
- Provide context. If you're asking about something new, give the agent enough background to help effectively.
- Correct mistakes. If the agent gets something wrong, tell it. It will learn from corrections.
- Use tools explicitly. "Search for the latest research on X" tells the agent you want it to use its search capability.
- Ask about progress. If you've asked the agent to do something that takes a while, you can ask how it's going.
5. Privacy and data¶
5.1 What your agent remembers¶
Your agent extracts and stores facts from your conversations to serve you better over time. These facts include things like your preferences, project details, and contextual information.
5.2 What's private¶
Your personal knowledge (facts about you, your preferences, your private context) is visible only to you. No one else on your team can see it, even if you share the same agent.
When your agent delegates to another agent, the delegate works from its own knowledge. Your full conversation history is not forwarded to the delegate.
5.3 Your data rights¶
- Export. You can export all your data at any time.
- Delete. You can request deletion of your personal data.
- Portability. If you leave a team, your personal knowledge goes with you.
6. Troubleshooting¶
Agent not responding?
- Check that the agent is active (not paused)
- Check your channel connection
- Try sending a simple test message
Agent giving irrelevant answers?
- Start a new session for a fresh context
- Be more specific in your request
- Check if relevant knowledge has been captured
Budget exceeded?
- Contact your team or account administrator
- Your agent will inform you when budget limits are reached
Long-running task not completing?
- Ask your agent about the status of the task
- Tasks have timeout limits: if a task exceeds its deadline, you will be notified
- You can ask your agent to cancel a pending task
7. Getting help¶
Support channels will be documented as they're established. The up-to-date set of support surfaces always lives under the /docs portal described in Part C.
Part B: Thinklio app UI specification¶
Part B is the UI specification for the Thinklio app at app.thinklio.ai. It is a unified Next.js application combining end-user agent interaction and organisational administration, using role-based progressive disclosure: all authenticated users see the client pages (briefing, agents, activity, knowledge, settings), users with admin or owner roles also see an Administration section in the sidebar, and users with the is_app_admin flag see the platform-level App Admin controls. The specification below is the contract between product, design, and engineering for the production app.
1. Overview¶
Thinklio App is a unified platform combining end-user agent interaction and organisational administration in a single Next.js application. The app uses role-based progressive disclosure: all users see the client-facing pages (briefing, agents, activity, knowledge, settings), while users with admin or owner roles also see an "Administration" section in the sidebar with access to platform management pages. A separate app admin flag grants platform-level controls.
The specification describes the UI contract: what each page presents, what roles see which controls, how state is managed, and how the app integrates with the backend. In the Convex + Clerk architecture, the backend integration section (14) supersedes the earlier Supabase-oriented contract.
2. Technology stack¶
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router, Turbopack) |
| Language | TypeScript 5 (strict mode) |
| Rendering | React 19 with experimental React Compiler |
| Styling | Tailwind CSS 4 with CSS custom properties |
| Icons | @phosphor-icons/react |
| UI Primitives | Radix UI (avatar, collapsible, dialog, dropdown, select, separator, switch, tabs, tooltip) |
| State | Zustand 5 (three stores) |
| Data Fetching | Convex React client (reactive queries, mutations, actions) |
| Auth | Clerk (@clerk/nextjs) |
| Charts | Recharts 2 |
| Markdown | react-markdown 10 |
| Animations | Motion (Framer Motion) 12 |
| Toasts | Sonner 2 |
| Build Output | Standalone (self-contained server for container deployment) |
The pre-consolidation spec used TanStack React Query and a separate Supabase client. Both are replaced by the Convex React client, which provides reactive queries directly against the Convex deployment. See 11-convex-reference.md Part A section 1 (reactivity) and 12-developer-guide.md (Convex + Clerk setup) for the wiring.
3. Brand and theme system¶
3.1 Colour palette¶
The default theme ("Calm") follows a 60/30/10 ratio:
- Warm neutrals (60%). Page backgrounds, cards, text. Shades: warm-50 through warm-950.
- Teal (30%). Navigation, authority, technical confidence. Shades: teal-50 through teal-950.
- Terracotta (10%). CTAs, accent moments, energy. Shades: terra-50 through terra-950.
3.2 Colour schemes¶
Five colour schemes are available, selectable per user in Settings > Profile > Appearance:
| Scheme | Description | Nav/accent tones |
|---|---|---|
| Calm (default) | Teal + terracotta + warm neutrals | Teal nav, terracotta CTAs |
| Warm | Amber and earthy tones | Dark brown nav, amber CTAs |
| Bold | Deep purple and magenta | Purple nav, magenta CTAs |
| Modern | Cool slate and blue | Slate nav, blue CTAs |
| Pride | Rainbow gradient accents | Dark indigo nav, pink CTAs |
Each scheme overrides the semantic CSS variables (nav, CTA, ring, border) for both light and dark modes via the data-scheme attribute on the root element. The Calm scheme applies no overrides (it uses the base CSS variables).
Scheme selection is persisted in localStorage (thinklio-colour-scheme) and applied before first paint via an inline script to prevent flash.
3.3 Typography¶
- Display: Fraunces (serif) for page headings and logo.
- Sans: Plus Jakarta Sans for body text and UI elements.
- Mono: JetBrains Mono for code, dollar amounts, and technical values.
3.4 Theme modes¶
Light, dark, and system modes are supported via CSS custom properties on :root and .dark. Users select mode via a segmented control in Settings > Profile > Appearance. A localStorage-based script in the root layout prevents flash of wrong mode on load.
3.5 CSS custom properties¶
All UI components reference semantic variables rather than palette colours directly:
--page-bg, --card-bg, --elevated-bg
--nav-bg, --nav-fg, --nav-active, --nav-hover, --fg-on-nav
--fg-primary, --fg-secondary, --fg-placeholder
--border, --ring
--cta, --cta-hover, --cta-fg
--success-fg/bg, --warning-fg/bg, --error-fg/bg, --info-fg/bg
3.6 Animations¶
Four keyframe animations are defined in global.css:
slide-in: sidebar drawer entrance (left to right).slide-in-right: notification panel entrance (right to left).slide-up: bottom nav and mobile elements.pulse-dot: processing status indicator.
3.7 Currency display¶
All monetary values are displayed in real USD (for example, "$24.37") rather than abstract credit units. Prominent balance displays (sidebar, briefing card, billing tab) include a small "USD" suffix after the amount via the CurrencyLabel component. Conversation-level micro-costs (agent message costs, delegation costs) show dollar amounts without the suffix to avoid visual noise.
4. Layout and navigation¶
4.1 Desktop layout¶
The desktop layout consists of:
- Sidebar (left, 240px expanded / 64px collapsed) with a dark-toned background (colour varies by scheme), navigation links, notification bell, USD balance display, user avatar, and collapse toggle.
- Main content area (scrollable) containing page content and footer.
The sidebar is always visible on screens >= 1024px. It can be collapsed via a toggle at the bottom, which reduces it to icon-only mode.
4.2 Mobile layout¶
On screens < 1024px:
- TopBar (top, 56px): hamburger menu, logo, page title, notification bell, user avatar.
- Main content area (scrollable) with bottom padding to accommodate the bottom nav.
- BottomNav (bottom, 64px, fixed) with four primary destinations: Briefing, Agents, Activity, Knowledge.
The hamburger menu opens a drawer overlay with the full sidebar content.
4.3 Sidebar navigation structure¶
Client navigation (scheme-toned):
- Briefing (
/briefing) - Agents (
/agents) - Activity (
/activity) - Knowledge (
/knowledge)
Active items use filled icon weight and bg-white/10 background.
Administration section (terracotta-toned, role-gated):
Visible only to users with admin or owner account roles. Separated from client nav by a terracotta-tinted divider. Uses a collapsible section header ("Administration") that defaults to open when viewing an admin page.
When the sidebar is collapsed, admin items show as icon-only links with tooltips, separated by a divider.
- Dashboard (
/admin/dashboard) - Agents (
/admin/agents) - Teams & Users (
/admin/teams) - Usage & Costs (
/admin/usage) - Audit Log (
/admin/audit) - Policies (
/admin/policies) - Integrations (
/admin/integrations)
Bottom section:
- Balance display (currency icon + remaining USD balance with "USD" suffix)
- Notifications button (bell icon + unread badge)
- User avatar (links to
/settings) - Collapse/expand toggle (desktop only)
4.4 Footer¶
A footer with copyright and links to Terms, Privacy, and Security pages appears at the bottom of all pages except the agents conversation view. It is always positioned at the bottom of the viewport, regardless of content height.
4.5 Notification panel¶
A slide-in panel from the right edge, triggered by the notification bell. Shows a list of notifications with:
- Agent avatar (or generic icon for system notifications)
- Agent name, description, relative timestamp
- Unread indicator (terracotta dot)
- "Mark all read" action
- Click-through to relevant page
5. Authentication and welcome¶
5.1 Welcome page (/login)¶
A clean, modern welcome page outside the authenticated layout. Structure:
Nav bar: Logo + "Thinklio" wordmark left, sign in / create account toggle right.
Main area (responsive):
- Mobile: centred column layout.
- Desktop: hero section left, auth card right.
Hero section:
- Heading: "Your team's AI workforce" (with CTA-coloured accent).
- Subtext: one-line tagline describing agent capabilities.
Auth card (frosted glass effect, max-width 384px):
- Sign up mode: name + email fields, Continue button, link to sign in.
- Sign in mode: email field, Continue button, link to create account.
- Both forms are powered by Clerk's sign-in and sign-up components, styled to inherit the active colour scheme. Successful sign-in navigates to
/briefing.
Footer: Links to Privacy, Terms, and the thinklio.ai website.
The page uses CSS custom properties so it inherits the active colour scheme and light/dark mode.
5.2 Sign out¶
A sign out button appears at the bottom of the Settings > Profile tab, separated by a border. Ghost styling, turns red on hover. Signs the user out via Clerk and navigates to /login.
6. Pages¶
6.1 Briefing (/briefing)¶
The default landing page. A personalised daily dashboard with a greeting header (time-aware: "Good morning / afternoon / evening" + user name + date).
Cards displayed in a single column (max-width 720px):
- Urgent Items: pending approvals and failed jobs requiring attention, with links.
- Calendar: today's events with time, title, duration, attendees.
- Mail Summary: unread count and summary of emails needing response.
- Tasks: due today (with checkboxes) and overdue items.
- Active Jobs: currently running agent jobs with progress.
- Knowledge Snapshot: new facts this week with source agent.
- Balance: remaining USD balance with progress bar and "View usage" link.
6.2 Agents (/agents)¶
A split-view conversational interface.
Desktop (three-column layout):
- Left (320px): Agent roster grouped by context (Personal, Team, Account) with collapsible sections.
- Centre (flex): Conversation view with message stream and input.
- Right (optional): Context panels for artefacts or knowledge.
Mobile: Single-column with navigation between roster and conversation via back button.
Agent roster items display:
- Agent avatar (initials on coloured circle)
- Name, description, catch-up line
- Status dot (green = idle, blue pulsing = processing, terracotta = pending approval, yellow = setup required)
Agents requiring setup show "Setup required" with a wrench icon instead of the catch-up line. Clicking opens the AgentConfigDialog (see Agent Onboarding below).
Conversation view contains a message stream with the following message types:
- User messages: right-aligned with teal background.
- Agent messages: left-aligned with avatar, markdown-rendered content, timestamp, USD cost, and thumbs up/down feedback (on hover).
- System messages: centred, muted text.
- Delegation indicators: compact chip showing which agent was delegated to, action taken, USD cost.
- Job progress cards: expandable card with progress bar, subjob list, status badge, thumbs up/down on completion.
- Approval requests: card with description, reason, detail, estimated USD cost, approve/decline buttons.
- Artefact deliveries: card with file type icon, title, description, USD cost, view/download buttons, thumbs up/down feedback.
- Governance notices: info banner for policy-related messages.
Message input is a text area with send button at the bottom of the conversation.
6.3 Agents direct (/agents/[agentId])¶
Full-screen conversation view for a specific agent, accessed by slug or ID. Redirects to /agents if agent not found.
6.4 Activity (/activity)¶
Job monitoring with three tabs:
- Active: jobs currently in progress (with live progress bars and subjob lists).
- Completed: resolved, failed, cancelled, or timed-out jobs with USD cost.
- All: full list with search filter.
Each job is displayed as a card showing agent name, job type badge, description, subjob progress, completion time, and USD cost.
6.5 Knowledge (/knowledge)¶
Knowledge base browser with search and three tabs:
- Personal: user-scoped facts (editable).
- Teams: team-scoped facts grouped by team name heading, then by category (preference, contact, project, procedure). Read-only. Scales to any number of teams.
- Account: account-scoped facts grouped by category. Read-only.
Each tab shows aggregate stats (total facts, by category, average confidence, total access count).
Knowledge fact cards display: subject, value, source agent avatar, confidence score, access count, category badge, and creation date. Personal facts have edit/delete actions.
6.6 Settings (/settings)¶
Tabbed layout with role-gated tab visibility:
| Tab | Visibility |
|---|---|
| Profile | All roles |
| Account | All roles (some cards gated by role) |
| Subscription & Billing | admin and owner only |
| App Admin | app_admin flag only |
Profile tab:
- Profile card: avatar, name, email, account, team, role, timezone, plan.
- Appearance: segmented mode control (Light / Dark / System with icons and labels) + colour scheme picker (five swatch circles: Calm, Warm, Bold, Modern, Pride).
- Connected Channels: web (connected), telegram, API keys (status).
- Data & Privacy: export data, delete account buttons.
- Sign out: ghost button at bottom, separated by border.
Account tab:
- Account: name, plan, billing email, data region, timezone.
- LLM Models (visible to
editorand above): three-tier model display (Deep / General / Mini) showing current model, provider, cost per million tokens, context window. Default badge per tier. - Services & Keys (visible to
adminand above): list of platform services grouped by category. Each shows name, category, and key status: "Platform key" (blue), "Your key" (green), or "Not configured" (grey). Actions: Add Key, Remove Key. Services include: OpenRouter, Voyage AI, Postmark, Tavily, Tavus, Anthropic Direct, OpenAI Direct, Twilio, HubSpot. - Notification Preferences: checkbox list (audit alerts, budget warnings, etc.).
- Predictive Planner: opt-in/out toggle with explanatory text (see section 8).
- Data Management: export all data, export audit log, data retention setting.
Subscription & Billing tab (admin and owner only):
- Subscription: current plan, payment method, billing email, change / update actions.
- Credits: USD balance with progress bar. Auto top-up toggle with selectable amount ($10, $20, $50, $100, $500, $1,000 USD). One-time top-up buttons (same amounts, always available even when auto top-up is enabled).
- Recent Transactions: debit/credit history with USD amounts (with "USD" suffix), service attribution, running balance.
App Admin tab (app_admin flag only):
- Platform Status: current status indicator (online / maintenance / offline), "Enable Maintenance Mode" button, platform margin percentage.
- Service Registry: full list of platform services with slug, category badge, platform key status, edit actions, add service button.
- LLM Model Registry: curated model list with tier default badges, provider, cost per million tokens, edit actions, add model button.
6.7 Admin: Dashboard (/admin/dashboard)¶
Platform overview with:
- Stat cards (4-column grid): Interactions (24h), Total Cost (24h), Active Agents, Active Users, each with trend indicator.
- Interactions chart: 30-day area chart (Recharts) showing daily interaction volume.
- Active agents panel: top agents by 24h interactions with budget utilisation bars.
- Recent activity feed: last 10 events with decision badges (allowed, denied, warning, require_approval).
6.8 Admin: Agents (/admin/agents)¶
Agent management gallery with four tabs:
- Active: deployed agents showing metrics (interactions, USD cost, budget %) with deactivate action.
- Available: agents ready for activation with activate button. May show configuration requirements count.
- Studio: custom agents in development or testing. Cards show deployment status badge and edit / promote actions.
- Installed: externally installed agents showing source (for example, "Thinklio Marketplace", "Novansa Internal") with uninstall action.
"New Agent" button links to the Agent Studio.
Search filters across all tabs by agent name and description. Tab labels include counts.
Agent cards adapt based on origin and deploymentStatus:
- Built-in agents: no origin badge, cannot be deleted.
- Custom agents: "Custom" badge, can be edited and deleted.
- Installed agents: source badge, can be uninstalled.
6.9 Admin: Agent Studio (/admin/agents/new, /admin/agents/[id]/edit)¶
Form-based pages for creating and editing custom agents. Max-width 720px, single column.
Sections (each in a Card):
- Identity: name (text input), description (textarea), accent colour (preset swatch picker with seven colours from the brand palette).
- Base Template: dropdown to select an existing built-in agent as a starting point (optional).
- System Prompt: large monospace textarea for the agent's system prompt.
- LLM Tier: three-card selector (Deep / General / Mini) with model name, cost / capability description, and current default model. Default: General.
- Channels: toggle buttons for web, email, telegram, API.
- Tools: pill-style multi-select from available platform capabilities (13 tools: Knowledge Retrieval, Document Generator, Web Search, Calendar API, and so on).
- User Configuration: dynamic field builder where admins define fields that end users must complete. Each field has: label (text input), type (text / textarea / select dropdown), required (checkbox). Fields can be added and removed.
The edit page adds a Deployment Status card at the top showing current status with promote / demote actions.
6.10 Admin: Teams & Users (/admin/teams)¶
- Team summary cards showing: team name, function, member count, active agents, 30d cost, 30d interactions.
- User table with search, showing: name, email, team, role badge, last active, 30d interactions, 30d cost.
6.11 Admin: Usage & Costs (/admin/usage)¶
Comprehensive analytics page:
- Monthly summary cards (total cost, platform cost, LLM cost, budget remaining, policy events).
- Cost by team bar breakdown.
- Cost by agent bar breakdown.
- Execution type pie chart.
- Daily cost trend area chart.
- Cost per interaction trend line chart.
6.12 Admin: Audit Log (/admin/audit)¶
Filterable audit trail with:
- Filters: date range, agent, decision type, event type.
- Desktop: table view with timestamp, agent, user, action, type badge, decision badge, cost, detail.
- Mobile: card view with the same information.
- Export button.
6.13 Admin: Policies (/admin/policies)¶
Expandable policy list. Each policy shows: name, scope, type, status badge, last modified. Expanding reveals: description, applies to, rules list, parameters table.
6.14 Admin: Integrations (/admin/integrations)¶
Grid of integration cards showing: icon, name, description, connection status badge, last sync time. Categories: productivity, CRM, communication, development, storage.
6.15 Public pages¶
Three static pages outside the authenticated layout:
/terms: Terms & Conditions/privacy: Privacy Policy/security: Security Policy
7. Agent lifecycle¶
7.1 Deployment states¶
Agents progress through four states:
- In Development: being built in Agent Studio, not visible to users.
- Testing: being validated, can be promoted to available.
- Available: ready for activation by admins.
- Active: deployed and accessible to users.
7.2 Origin types¶
- Built-in: part of the core platform, cannot be deleted.
- Custom: created via Agent Studio, can be edited and deleted.
- Installed: added from external sources (marketplace or internal), can be uninstalled.
7.3 Agent onboarding (end user)¶
When an admin activates an agent that defines a configurationSchema, the agent appears in the user's roster with a "Setup required" state. The roster item shows:
- Yellow status dot (instead of green).
- "Setup required" text with wrench icon (instead of catch-up line).
Clicking opens the AgentConfigDialog, a modal with:
- Agent avatar and name.
- Configuration fields as defined by the schema (text inputs, textareas, select dropdowns).
- Required field validation.
- Save button (marks agent as configured, transitions to normal state).
- Cancel button.
Once configured, the agent functions normally in the conversation UI.
8. Predictive Planner¶
8.1 Account setting¶
A toggle in the Account tab of Settings controls participation in the Predictive Planner. The card includes:
- Switch toggle: opt in or out.
- Explanation text: describes what is collected (de-identified agent plan structures, tool sequences, execution timing, and user quality ratings). Explicitly states that conversation content, knowledge facts, and identifiable information are never included.
- Contextual status:
- Opted in (green): "Your account is contributing to the Predictive Planner. Agents in your account benefit from improved planning strategies learned across the platform."
- Opted out (yellow): "Your account has opted out. Your agents will not benefit from Predictive Planner improvements, and the quality rating controls will be hidden from your users. You can opt back in at any time."
8.2 Outcome feedback¶
Thumbs up/down buttons appear on three conversation surfaces:
- Agent messages: in the hover-revealed metadata row (alongside timestamp and USD cost).
- Artefact cards: inline, right-aligned next to View/Download buttons.
- Completed job progress cards: replaces the Cancel button when job state is
resolved.
The feedback component toggles between three states: no rating, thumbs up (green highlight), thumbs down (red highlight). Clicking a selected rating deselects it.
9. Responsive behaviour¶
| Breakpoint | Layout |
|---|---|
| < 1024px (mobile/tablet) | TopBar + scrollable content + BottomNav. Sidebar accessed via hamburger drawer. |
| >= 1024px (desktop) | Sidebar (collapsible) + scrollable content. No TopBar or BottomNav. |
The agents page has additional responsive behaviour:
- Desktop: three-column split (roster + conversation + optional panel).
- Mobile: roster or conversation (toggled by agent selection, with back button).
Admin pages are wrapped in a max-width: 7xl container with horizontal padding. Client pages manage their own max-width (typically 720 to 800px).
10. State management¶
10.1 Zustand stores¶
Agent store (agent-store.ts):
selectedAgentId: currently active agent in conversation view.configuredAgents: set of agent IDs that have completed onboarding.
UI store (ui-store.ts):
sidebarCollapsed: desktop sidebar collapse state.activePanel: right panel selection (artefacts, knowledge, or none).notificationPanelOpen: notification drawer visibility.mobileMenuOpen: mobile sidebar drawer visibility.
Notification store (notification-store.ts):
readIds: set of notification IDs marked as read in the current session.
Server state (agents, messages, jobs, knowledge, notifications) lives in Convex and is consumed via useQuery / useMutation / useAction hooks. Zustand is reserved for purely client-side UI state.
10.2 Permissions¶
The usePermissions() hook backed by a Zustand store (hydrated from the Clerk session and Convex account membership) provides:
| Property | Type | Description |
|---|---|---|
role |
AccountRole |
Current account role: viewer, editor, admin, or owner |
isAppAdmin |
boolean |
Platform-level admin flag (independent of account role) |
isOwner |
boolean |
True for owner |
isAdmin |
boolean |
True for admin or owner |
isEditor |
boolean |
True for editor, admin, or owner |
isViewer |
boolean |
Always true (all roles can view) |
10.3 Role visibility matrix¶
| Feature | viewer | editor | admin | owner | app_admin |
|---|---|---|---|---|---|
| Client pages (briefing, agents, etc.) | read | full | full | full | full |
| Administration sidebar section | visible | visible | visible | ||
| Settings > LLM Models card | visible | visible | visible | visible | |
| Settings > Services & Keys card | visible | visible | visible | ||
| Settings > Subscription & Billing tab | visible | visible | visible | ||
| Settings > App Admin tab | visible | ||||
| Account management (admin pages) | visible | visible |
11. Data model summary¶
11.1 Client types (user-facing)¶
- User: id, email, displayName, timezone, accountId, team, teamRole, plan, balanceRemaining (USD), balanceTotal (USD), settings.
- Agent: id, name, slug, description, capabilityLevel, status, processingStatus, accentColour, context, tools, delegates, setupRequired, configurationSchema.
- ConversationMessage: union type of UserMessage, AgentMessage, DelegationIndicator, JobProgressCard, ApprovalRequest, ArtefactDelivery, GovernanceNotice, SystemMessage.
- Job: id, agentId, type, description, state, subjobs, cost (USD), timestamps.
- KnowledgeFact: id, scope, agentId, subject, value, category, confidence, accessCount.
- Notification: id, agentId, category, title, description, read status, timestamp, link.
- BriefingData: calendar, mail, tasks, activeJobs, knowledgeSnapshot, urgentItems.
- Artefact: id, agentId, title, description, fileType, fileSize, createdAt.
11.2 Admin types (management)¶
- Agent: extends client fields with: assignedTo, assignedTeamId, metrics (interactions, cost, budget), model, origin, deploymentStatus, configurationSchema, parentTemplateId, channels, systemPrompt, installedFrom.
- ConfigField: id, label, type (text / textarea / select), placeholder, options, required.
- Team: id, name, function, memberCount, activeAgents, cost, interactions.
- StaffMember: id, name, email, team, role, lastActive, interactions, cost.
- AuditEntry: id, timestamp, agent, user, action, type, decision, cost, detail.
- Policy / PolicyDetail: id, name, scope, type, status, rules, parameters.
- Integration: id, name, description, category, status, lastSync, icon.
- AccountSettings, ApiKey, LlmProvider, NotificationPref: account configuration.
The canonical schema for these types lives in 04-data-model.md; the TypeScript types used by the app are generated from Convex's schema (convex/schema.ts) via npx convex codegen. See 11-convex-reference.md section 2 (schemas) for schema patterns.
12. Component library¶
12.1 Base UI components¶
| Component | Source | Purpose |
|---|---|---|
avatar |
Radix | User/agent avatar with fallback initials |
badge |
Custom (CVA) | Status/category labels (six variants) |
button |
Custom (CVA) | Actions (four variants, four sizes) |
card |
Custom | Container with header / title / description / content |
confirm-dialog |
Radix Dialog | Confirmation modal with cancel / confirm |
currency-label |
Custom | USD amount with small currency code suffix |
progress-bar |
Custom | Linear progress (four colour variants) |
search-input |
Custom | Search field with magnifying glass icon |
separator |
Radix | Horizontal/vertical divider line |
tabs |
Radix | Tab navigation with styled triggers and content |
theme-toggle |
Custom | Cycles light → dark → system |
13. File structure¶
src/
├── app/
│ ├── layout.tsx Root layout (metadata, fonts, theme + scheme script)
│ ├── global.css Theme variables, colour schemes, animations, scrollbar
│ ├── (auth)/ Authentication route group
│ │ ├── layout.tsx Pass-through layout
│ │ └── login/page.tsx Welcome/login page (Clerk components)
│ ├── (app)/ Authenticated route group
│ │ ├── layout.tsx Providers + MainLayout wrapper
│ │ ├── template.tsx Page transition animation
│ │ ├── page.tsx Redirect → /briefing
│ │ ├── briefing/page.tsx
│ │ ├── agents/page.tsx
│ │ ├── agents/[agentId]/page.tsx
│ │ ├── activity/page.tsx
│ │ ├── knowledge/page.tsx
│ │ ├── settings/page.tsx
│ │ └── admin/
│ │ ├── dashboard/page.tsx
│ │ ├── agents/page.tsx
│ │ ├── agents/new/page.tsx
│ │ ├── agents/[id]/edit/page.tsx
│ │ ├── audit/page.tsx
│ │ ├── teams/page.tsx
│ │ ├── usage/page.tsx
│ │ ├── integrations/page.tsx
│ │ └── policies/page.tsx
│ ├── privacy/page.tsx
│ ├── security/page.tsx
│ └── terms/page.tsx
├── components/
│ ├── ui/ Base components
│ ├── layout/ Layout components
│ ├── briefing/ Briefing card components
│ ├── agents/ Agent roster components
│ ├── conversation/ Message type components
│ ├── activity/ Job display components
│ ├── knowledge/ Knowledge components
│ ├── panels/ Context panel components
│ └── admin/agents/ Admin agent components
├── convex/ Convex client bindings (generated)
├── stores/ Zustand stores
├── hooks/ Client hooks (usePermissions, etc.)
├── providers/ Context providers (ClerkProvider, ConvexProviderWithClerk)
└── lib/
└── utils.ts cn, formatNumber, formatCurrency,
formatRelativeTime, formatDate, formatTime, getGreeting
14. Backend integration¶
This section documents how the app connects to the backend. The pre-consolidation spec (old doc 23, Addendum dated 20 March 2026) described a REST-style contract against a Go + Supabase backend. In the current architecture, the backend is Convex with Clerk for identity. The functional surface (what the app does at each route, what each role can see) is unchanged; the wire format and call semantics change.
14.1 Role model¶
The backend uses a four-tier role model for account-level membership, plus a platform-level admin flag. The app has adopted these roles.
| Role | Permissions |
|---|---|
owner |
Full access: billing, delete account, transfer ownership, manage API keys, subscription |
admin |
Manage teams, members, agents, settings (not billing / delete) |
editor |
Create/edit agents, knowledge, use all features, choose LLM models |
viewer |
Read-only access, can interact with assigned agents |
| Flag | Permissions |
|---|---|
is_app_admin |
Platform-level controls: kill switch, service registry, model registry, margin. Independent of account role. |
Roles are stored on the account_user join table in Convex and resolved in middleware on every query and mutation (see 07-security-governance.md Part A section 4.2).
14.2 Authentication¶
Authentication is handled by Clerk. The app uses @clerk/nextjs for the sign-in and sign-up components and for middleware that gates authenticated routes.
// app/providers.tsx
import { ClerkProvider } from "@clerk/nextjs";
import { ConvexReactClient } from "convex/react";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { useAuth } from "@clerk/nextjs";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider>
<ConvexProviderWithClerk client={convex} useAuth={useAuth}>
{children}
</ConvexProviderWithClerk>
</ClerkProvider>
);
}
Every Convex query and mutation automatically receives the Clerk identity via ctx.auth.getUserIdentity(). There is no manual Authorization: Bearer <token> construction in the app; the Convex React client handles token refresh transparently. See 12-developer-guide.md for the full setup walkthrough.
14.3 Data access pattern¶
The app replaces the pre-consolidation REST endpoints with Convex queries, mutations, and actions. The functional grouping below preserves the original endpoint organisation so page-by-page work remains easy to map; the call form is the idiomatic Convex one.
Briefing page (/briefing):
const briefing = useQuery(api.briefing.getForUser);
// → { greeting, urgentItems, activeJobs, recentInteractions,
// knowledgeSnapshot, credits, unreadNotifications }
Agents page (/agents):
const agents = useQuery(api.agents.listAccessible); // List agents accessible to user
const sendMessage = useMutation(api.channels.sendMessage); // Send message to agent
const interaction = useQuery(api.channels.getInteraction, { id }); // Reactive status + response
const messages = useQuery(api.channels.getSessionMessages, { sessionId }); // Conversation history
Because Convex queries are reactive, the app does not poll for interaction status. The query resubscribes automatically when the backend writes the agent's response.
Activity page (/activity):
const activeJobs = useQuery(api.jobs.list, { status: "active" });
const completedJobs = useQuery(api.jobs.list, { status: "completed" });
const jobDetail = useQuery(api.jobs.get, { id }); // Detail with subjobs
const cancelJob = useMutation(api.jobs.cancel); // Cancel a job
Knowledge page (/knowledge):
const personalFacts = useQuery(api.knowledge.list, { agentId, scope: "user", scopeId: uid });
const teamFacts = useQuery(api.knowledge.list, { agentId, scope: "team", scopeId: tid });
const accountFacts = useQuery(api.knowledge.list, { agentId, scope: "account", scopeId: aid });
const addFact = useMutation(api.knowledge.add);
const deleteFact = useMutation(api.knowledge.remove);
Settings page (/settings):
const accounts = useQuery(api.accounts.listForUser); // List user's accounts
const updateAccount = useMutation(api.accounts.update); // Update account settings
const channels = useQuery(api.channels.listMine); // Connected channels
const connectChannel = useAction(api.channels.connect); // Triggers OTP flow
const members = useQuery(api.accounts.listMembers, { accountId });
Billing:
const credits = useQuery(api.accounts.getCredits, { accountId });
const services = useQuery(api.accounts.listServices, { accountId });
const setServiceKey = useMutation(api.accounts.setServiceKey);
const modelPrefs = useQuery(api.accounts.listModelPreferences, { accountId });
const setModelForTier = useMutation(api.accounts.setModelForTier);
App Admin:
const platformConfig = useQuery(api.admin.platform.getConfig);
const updatePlatformConfig = useMutation(api.admin.platform.updateConfig);
const platformServices = useQuery(api.admin.platform.listServices);
const addPlatformService = useMutation(api.admin.platform.addService);
const updatePlatformService = useMutation(api.admin.platform.updateService);
const platformModels = useQuery(api.admin.platform.listModels);
const addPlatformModel = useMutation(api.admin.platform.addModel);
const updatePlatformModel = useMutation(api.admin.platform.updateModel);
Notifications:
const notifications = useQuery(api.notifications.list); // Reactive; unread count included
const markAllRead = useMutation(api.notifications.markAllRead);
const markRead = useMutation(api.notifications.markRead);
Quality ratings (Predictive Planner):
const rate = useMutation(api.ratings.submit);
// { targetType: "interaction" | "job" | "media", targetId, rating: "positive" | "negative" | "" }
Admin pages:
const auditEntries = useQuery(api.admin.audit.list, { accountId, agentId?, decision? });
const teamMembers = useQuery(api.accounts.listMembers, { accountId });
const teams = useQuery(api.accounts.listTeams, { accountId });
const invitations = useQuery(api.accounts.listInvitations, { accountId });
const sendInvitation = useMutation(api.accounts.sendInvitation);
const usage = useQuery(api.usage.summary, { accountId });
Agent Studio:
const createAgent = useMutation(api.agents.create);
const updateAgent = useMutation(api.agents.update); // name, systemPrompt, llmTier, llmModel, etc.
const pauseAgent = useMutation(api.agents.pause);
const resumeAgent = useMutation(api.agents.resume);
const assignAgent = useMutation(api.agents.assign); // assign to context (team / user)
Agent fields available from the Convex schema: origin, deploymentStatus, accentColour, configurationSchema, installedFrom, llmTier.
14.4 Agent lifecycle states¶
The backend supports the four deployment states. The deploymentStatus field on the agent entity maps directly:
| State | deploymentStatus value |
Where it appears |
|---|---|---|
| In Development | in_development |
Studio tab |
| Testing | testing |
Studio tab |
| Available | available |
Available tab |
| Active | active |
Active tab |
The existing status field (active / paused / archived) is separate: it controls whether the agent is operational, not its lifecycle stage. An agent can be deploymentStatus = 'active' and status = 'paused' (deployed but temporarily disabled).
14.5 Onboarding flow¶
After Clerk signup, the app should:
- Call
api.accounts.listForUserto enumerate the user's account memberships. - If empty, show the onboarding wizard.
- Wizard collects: account name, slug, timezone, region.
- Call
api.accounts.createto create the account. The mutation also creates the initialaccount_userrow with roleowner. - Redirect to
/briefing.
See 09-external-api-tool-integration.md (account and onboarding API reference) for the full contract.
Part C: Documentation and developer portal UI¶
Part C specifies the documentation and developer portal that lives on the Thinklio marketing site (not the authenticated app). Two experiences share a layout system and a unified schema:
/docs: user documentation for end users, team members, and administrators./developer: developer documentation with API references, code examples, and integration guides.
The developer variant adds a two-column layout with a code panel on the right and endpoint cards in the content stream. Everything is driven from the same schema; the developer-only surfaces are optional extensions.
1. Overview¶
The portal is built on the same Next.js App Router codebase as the rest of thinklio.ai. All documentation components live under src/components/docs/. The initial implementation uses local TypeScript data files that mirror the database schema exactly, so the migration to the production backend is a pure data-loading change (see section 7).
2. Data model¶
A unified schema supports both documentation types. The same tables serve user docs and developer docs, differentiated by a doc_type discriminator. The schema below shows the Postgres reference (how it was first designed); in the Convex + Clerk architecture, these tables are defined in convex/schema.ts with equivalent shape (string unions replace Postgres enums, v.id("doc_section") replaces UUID foreign keys, system fields _id and _creationTime replace manual id / created_at columns). See 04-data-model.md for the canonical Convex form.
2.1 Tables¶
doc_section: top-level navigation groups.
id(PK)doc_type(enum:user,developer)slug(text, unique perdoc_type)title(text)description(text, nullable)icon(text, nullable; Phosphor icon component name)sort_order(int)status(enum:draft,published,coming_soon,beta,deprecated)
doc_page: individual pages within a section.
id(PK)section_id(FK →doc_section)slug(text, unique per section)title(text)description(text, nullable)content(text; markdown)audience(text array; for example,['individual', 'team', 'admin'])sort_order(int)status(enum)
api_endpoint: API endpoint definitions (developer docs only).
id(PK)page_id(FK →doc_page)method(enum:GET,POST,PUT,PATCH,DELETE)path(text; for example,/v1/channels/{channel_id}/messages)summary(text)description(text, nullable; markdown)request_body(JSON, nullable)parameters(JSON, nullable; array of{ name, in, type, required, description })response_body(JSON, nullable)status(enum)sort_order(int)
api_code_example: code examples per endpoint, one row per language.
id(PK)endpoint_id(FK →api_endpoint)language(text:curl,python,typescript,go)label(text; display label, for examplecURL,Python)code(text)sort_order(int)- Unique constraint:
(endpoint_id, language)
2.2 Reference SQL schema¶
The reference SQL schema below is preserved for archival completeness. The production deployment uses the equivalent Convex schema definitions.
CREATE TYPE doc_type AS ENUM ('user', 'developer');
CREATE TYPE doc_status AS ENUM ('draft', 'published', 'coming_soon', 'beta', 'deprecated');
CREATE TYPE http_method AS ENUM ('GET', 'POST', 'PUT', 'PATCH', 'DELETE');
CREATE TABLE doc_section (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
doc_type doc_type NOT NULL,
slug TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
icon TEXT,
sort_order INT NOT NULL DEFAULT 0,
status doc_status NOT NULL DEFAULT 'published',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (doc_type, slug)
);
CREATE TABLE doc_page (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
section_id UUID NOT NULL REFERENCES doc_section(id) ON DELETE CASCADE,
slug TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
content TEXT NOT NULL,
audience TEXT[],
sort_order INT NOT NULL DEFAULT 0,
status doc_status NOT NULL DEFAULT 'published',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (section_id, slug)
);
CREATE TABLE api_endpoint (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
page_id UUID NOT NULL REFERENCES doc_page(id) ON DELETE CASCADE,
method http_method NOT NULL,
path TEXT NOT NULL,
summary TEXT NOT NULL,
description TEXT,
request_body JSONB,
parameters JSONB,
response_body JSONB,
status doc_status NOT NULL DEFAULT 'published',
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE api_code_example (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
endpoint_id UUID NOT NULL REFERENCES api_endpoint(id) ON DELETE CASCADE,
language TEXT NOT NULL,
label TEXT NOT NULL,
code TEXT NOT NULL,
sort_order INT NOT NULL DEFAULT 0,
UNIQUE (endpoint_id, language)
);
CREATE INDEX idx_doc_section_type ON doc_section(doc_type, sort_order);
CREATE INDEX idx_doc_page_section ON doc_page(section_id, sort_order);
CREATE INDEX idx_api_endpoint_page ON api_endpoint(page_id, sort_order);
CREATE INDEX idx_api_code_example_endpoint ON api_code_example(endpoint_id, sort_order);
2.3 Current implementation (fake data)¶
The UI currently uses local TypeScript data files that mirror the database schema shape exactly. Migrating to the production backend requires only:
- Apply the equivalent Convex schema.
- Insert the data from the TypeScript files.
- Replace the data imports in
src/data/index.tswith Convex queries (useQuery(api.docs.getNavigation), etc.).
Data files:
src/data/user-docs.ts: user doc sections and pages (sourced from Part A of this document).src/data/developer-docs.ts: developer doc sections, pages, endpoints, and code examples (sourced from09-external-api-tool-integration.md).src/data/index.ts: unified lookup functions (getNavigation,getPage,getPrevNextPages, and so on).
Type definitions:
src/types/docs.ts: TypeScript interfaces matching the schema.
3. UI components¶
All documentation components live in src/components/docs/.
3.1 Shared components (used by both /docs and /developer)¶
| Component | Type | Purpose |
|---|---|---|
DocsLayout.tsx |
Client | Layout shell: sidebar + content area + optional right panel |
DocsSidebar.tsx |
Client | Collapsible navigation tree. Desktop: fixed 256px sidebar. Mobile: slide-in drawer |
DocsBreadcrumb.tsx |
Server | Breadcrumb navigation (Docs > Section > Page) |
DocsContent.tsx |
Server | Renders markdown content as styled HTML with a built-in parser |
DocsPagination.tsx |
Server | Previous / Next page navigation at the bottom of pages |
StatusBadge.tsx |
Server | Renders status badges (Coming Soon, Beta, Deprecated) |
3.2 Developer-specific components¶
| Component | Type | Purpose |
|---|---|---|
CodePanel.tsx |
Client | Right-side code panel with language tabs, syntax highlighting (prism-react-renderer), copy button, sticky positioning |
EndpointCard.tsx |
Client | API endpoint display: method badge, path with parameter highlighting, parameters table, request / response schemas |
ApiKeyPlaceholder.tsx |
Client | Styled API key display with masking and copy button |
3.3 Layout architecture¶
┌──────────────────────────────────────────────────────┐
│ Header (from root layout) │
├──────────┬───────────────────────┬───────────────────┤
│ Sidebar │ Content Area │ Code Panel │
│ (256px) │ (flex-1) │ (developer only) │
│ │ │ dark bg, sticky │
│ fixed │ Breadcrumb │ language tabs │
│ left │ Page title │ syntax highlight │
│ │ Prose content │ copy button │
│ │ Endpoint cards │ API key inject │
│ │ Prev/Next nav │ │
├──────────┴───────────────────────┴───────────────────┤
│ Footer (from root layout) │
└──────────────────────────────────────────────────────┘
Mobile: sidebar collapses to a hamburger-triggered drawer. Code panel stacks below content.
4. Route structure¶
/docs → Redirects to first page
/docs/[section]/[page] → User documentation page
/developer → Redirects to first page
/developer/[section]/[page] → Developer documentation page (with code panel)
Both use Next.js App Router dynamic segments with useParams().
5. User docs content structure¶
Sourced from Part A of this document (the end-user guide):
| Section | Pages |
|---|---|
| Getting Started | For Individual Users, For Team Members, For Administrators |
| Concepts | Agents, Agent Composition, Agent Studio, Knowledge, Channels, Tools, Jobs & Deferred Work, Governance |
| Using Your Agent | Conversations, Commands, Tips for Better Interactions |
| Privacy & Data | What Your Agent Remembers, What's Private, Your Data Rights |
| Troubleshooting | Common Issues, Getting Help |
6. Developer docs content structure¶
Sourced from 09-external-api-tool-integration.md:
| Section | Status | Pages (with endpoints) |
|---|---|---|
| Overview | Published | Introduction, Authentication, Versioning, Error Handling |
| Channel API | Beta | Send Message (POST), List Messages (GET), Sessions (POST, GET) |
| Platform API | Coming Soon | Agents (GET, POST, GET/:id, PATCH/:id), Jobs (POST, GET/:id), Knowledge (POST, GET), Usage (GET) |
| Integration API | Coming Soon | Tool Registration (POST), Tool Execution (contract description), Event Subscriptions (POST) |
| Cross-Cutting Concerns | Published | Governance, Cost Attribution |
All code examples include cURL, Python, TypeScript, and Go variants with a YOUR_API_KEY placeholder.
7. Backend migration plan¶
When ready to move from fake data to the production backend:
- Apply the Convex schema definitions (section 2.1, adapted from the reference SQL in section 2.2).
- Insert the fake data (scriptable from the TypeScript data files).
- Create a data access layer in
src/lib/docs/that calls Convex queries instead of reading local files. - Update
src/data/index.tsto re-export the Convex-backed access layer. - The component layer requires no changes: it consumes the same TypeScript interfaces regardless of data source.
8. Design decisions¶
Why a built-in markdown parser instead of a library? The content is authored by us, not user-generated. A simple parser handles the patterns we use (headings, lists, bold, inline code, paragraphs) without adding a dependency or processing overhead. If content complexity grows, a library like react-markdown can replace it.
Why fake data files instead of MDX? The data files mirror the exact shape of the database tables. This means the migration to the production backend is a data insertion exercise, not a content format migration. MDX would have required a build-time processing step and a different content authoring workflow.
Why 'use client' on doc pages? The documentation pages use useParams() for dynamic routing and useState for sidebar and code panel interactions. This makes them client components. Metadata is handled via parent layout.tsx files which remain server components.
Why a unified schema for both doc types? Both types share the same structural pattern (sections → pages). The developer variant extends with optional endpoint and code example relations. A single schema avoids duplication and allows shared navigation and lookup logic.
Dependencies added: prism-react-renderer for syntax highlighting in the developer docs code panel.
Part D: Internationalisation¶
Part D outlines Thinklio's internationalisation (i18n) architecture. It identifies the translation surfaces, proposes a locale resolution model, and flags decisions that need to be settled before a formal specification is written. Frontend marketing-website localisation is out of scope and handled separately.
The source for Part D (old doc 18) was written when Thinklio's backend was expected to be Go + PostgreSQL. The architecture in this part has been editorially translated to the current TypeScript + Convex stack: resource bundles are loaded by the Next.js app and Convex actions rather than by Go services, message formatting uses the platform's native Intl API (supplemented by a catalogue library such as i18next or @formatjs/intl), and data model references use Convex-style singular table names. Decisions, phasing, and the ADR remain unchanged.
1. Target languages¶
| Language | BCP 47 Tag | Script | Notes |
|---|---|---|---|
| English | en |
Latin | Platform default. Locale variants (en-AU, en-GB, en-US) supported via regional overrides |
| Spanish (neutral) | es |
Latin | Latin American neutral; avoids Castilian-specific conventions |
| Brazilian Portuguese | pt-BR |
Latin | Not European Portuguese |
| French | fr |
Latin | |
| German | de |
Latin | |
| Italian | it |
Latin | |
| Japanese | ja |
CJK | No plurals. Requires CJK-aware line breaking and text measurement |
| Korean | ko |
CJK | No plurals. Honourifics and formality levels affect agent tone |
| Simplified Chinese | zh-Hans |
CJK | No plurals. Distinct from Traditional Chinese (zh-Hant) |
English locale variants share the base en resource bundle, with per-locale overrides for spelling, date format, and currency conventions. The platform default is en. Adding a new language requires a new resource bundle and a registry entry; no code changes.
2. Two translation surfaces¶
Thinklio has two fundamentally different categories of translatable content, and each needs a different approach.
2.1 Platform strings (deterministic)¶
These are strings the platform itself produces. They are predictable, finite, and can be translated in advance:
- Governance messages (policy denials, trust level notifications, approval requests)
- Budget and cost notifications ("Budget limit reached", usage summaries)
- Job lifecycle updates ("Your research task has completed")
- Error responses across all three API surfaces
- Email notifications (welcome, password reset, usage alerts, job completion)
- Agent template names and descriptions
- Tool names and descriptions shown in Agent Studio
- Plan names and feature descriptions
- Admin dashboard labels and system messages
These are handled through conventional message catalogues: keyed string bundles per locale, loaded at module startup, resolved at runtime from the request context (on the server) or the user's locale store (in the app).
2.2 Agent responses (generative)¶
These are the outputs agents produce through LLM reasoning. They are unbounded, context-dependent, and cannot be pre-translated. Instead, the agent's language behaviour is controlled by injecting a locale directive into the system prompt during context assembly.
The LLM handles the actual language generation. The platform's job is to ensure the right locale reaches the system prompt, and that the directive accounts for register and formality conventions appropriate to the language (for example, formal German Sie vs informal du, Japanese keigo levels).
3. Locale resolution¶
A user's effective locale is resolved through a layered fallback:
The assignment-level override is important. A user whose personal preference is German might interact with a team agent in English because the team operates in English. The override sits on the agent_assignment entity, keeping the user_profile entity clean.
3.1 Where locale is set¶
| Entity | Field | Purpose |
|---|---|---|
user_profile |
locale |
User's personal language preference (BCP 47 tag, default en) |
agent_assignment |
locale |
Nullable override for this specific agent context |
account |
default_locale |
Account default for members who have not set a preference |
3.2 Where locale is consumed¶
Locale resolution happens in one place and flows everywhere else via context. In the Convex architecture, a shared helper (resolveLocale(ctx, { userId, agentAssignmentId })) is called inside the Convex query or mutation that authenticates the request, and the resolved locale is threaded through the return value (for web + mobile) or attached to the outbound message (for channel adapters and background actions).
For the three API surfaces (defined in 09-external-api-tool-integration.md):
- Channel API: resolved from the authenticated user's locale (with assignment override if applicable).
- Platform API: from
Accept-Languageheader, falling back to the account's default locale. - Integration API: from the external system's registration configuration or
Accept-Languageheader.
4. Platform string architecture¶
4.1 Resource bundles¶
Client and server use a shared i18n/ package within the monorepo. Messages are formatted via a catalogue library (@formatjs/intl on the client, a Convex-compatible catalogue module on the server) backed by the platform's native Intl API for pluralisation, number, date, and currency formatting.
i18n/
en.toml # Base English (complete set)
en-AU.toml # Australian English overrides
en-GB.toml # British English overrides
en-US.toml # American English overrides
es.toml
pt-BR.toml
fr.toml
de.toml
it.toml
ja.toml
ko.toml
zh-Hans.toml
Locale variant files (for example, en-AU.toml) contain only the keys that differ from the base language file. At load time, the variant is merged over the base. If a key is missing from both the variant and the base, the platform default (en) is used.
4.2 String key conventions¶
Keys are namespaced by domain, using dot notation:
[governance]
policy_denied = "This action is not permitted by your organisation's policy."
approval_required = "This action requires approval from {approver_role}."
budget_exceeded = "The {scope} budget of {budget_amount} has been reached."
[jobs]
completed = "Your task \"{job_title}\" has completed."
failed = "Your task \"{job_title}\" could not be completed: {reason}"
Interpolation uses named placeholders. Pluralisation follows CLDR rules (which correctly handle languages with no plural forms, two-form languages, and languages with complex plural rules like Arabic).
4.3 Formatting conventions¶
Number, date, currency, and measurement formatting must respect locale conventions:
| Concern | Example variation |
|---|---|
| Decimal separator | 1,234.56 (en) vs 1.234,56 (de) vs 1 234,56 (fr) |
| Date format | 16/03/2026 (en-AU) vs 03/16/2026 (en-US) vs 2026年3月16日 (ja) |
| Currency | $12.50 AUD vs €12,50 vs ¥1,250 |
| Time | 2:30 pm (en-AU) vs 14:30 (de) vs 午後2:30 (ja) |
These are handled by the Intl.NumberFormat, Intl.DateTimeFormat, and Intl.RelativeTimeFormat APIs, not by string catalogues. All user-facing numbers, dates, and currencies must be rendered via locale-aware formatters.
5. Agent response localisation¶
5.1 System prompt injection¶
During the Context step of the harness, the locale directive is assembled and injected into the system prompt. The directive goes beyond a simple "respond in German" instruction. It includes:
- Target language and regional variant
- Formality and register guidance appropriate to the language
- Any account-level language policies (for example, "always use formal register with external users")
The agent's core personality prompt and domain knowledge remain in their authored language (typically English). The LLM handles code-switching between the knowledge language and the response language. This avoids maintaining parallel translations of every agent's configuration. See 03-agent-architecture.md (context assembly) for where the directive is assembled.
5.2 Knowledge layer language handling¶
Knowledge facts are stored in the language they were expressed in, tagged with a locale field on the knowledge_fact table. There is no automatic translation of stored facts. At context assembly time, the Context service:
- Retrieves facts relevant to the query (via vector similarity and scope filtering).
- Includes the fact's source locale as metadata.
- Allows the LLM to translate as needed when incorporating facts into its response.
This preserves the fidelity of domain-specific content and avoids compounding translation errors in the knowledge layer. The trade-off is that cross-lingual retrieval quality depends on the embedding model's multilingual capability. For initial deployment, this is acceptable. If retrieval quality degrades for CJK languages, a cross-lingual embedding model or query translation step can be introduced later.
5.3 Account knowledge translation¶
Some organisations will want critical policy documents available in multiple languages (for example, compliance rules that must be precisely rendered, not LLM-paraphrased). The knowledge model supports this through duplicate facts with different locale tags. The Context service prefers facts matching the user's effective locale, falling back to the account's default locale.
This is optional. Most organisations will rely on the LLM to translate policy content at response time, and that will be adequate for the majority of use cases.
6. Data model additions¶
| Table | Column | Type | Notes |
|---|---|---|---|
user_profile |
locale |
string (BCP 47) | Default 'en'. Not null |
account |
default_locale |
string (BCP 47) | Default 'en'. Not null |
agent_assignment |
locale |
string (BCP 47), optional | Nullable override. Null means "use user's locale" |
knowledge_fact |
locale |
string (BCP 47) | Language the fact was captured in. Default 'en'. Not null |
agent_template |
locales |
object | Map of locale code to {name, description} for localised template metadata |
A supported_locales reference table or application-level registry lists the languages the platform actively supports, used for validation and UI locale pickers. See 04-data-model.md for the canonical Convex definitions.
7. API response pattern¶
All three API surfaces return both a machine-readable code and a localised human-readable message:
{
"error": {
"code": "BUDGET_EXCEEDED",
"message": "Das Budget von €500,00 für das Team wurde erreicht.",
"scope": "team",
"budget_amount": "500.00",
"currency": "EUR"
}
}
Clients that handle their own localisation can ignore the message field and build from the code and structured data. Clients that want platform-rendered messages use message directly. This means external integrators are never forced to depend on the platform's translations.
8. CJK considerations¶
Japanese, Korean, and Simplified Chinese introduce specific concerns beyond translation:
- No grammatical plurals. The pluralisation system must handle zero-plural languages cleanly (never produce constructions like
1 件のタスクvs2 件のタスクusing English plural logic).Intl.PluralRulesand CLDR rules handle this correctly. - Text length variance. CJK translations are often significantly shorter than English equivalents. UI layouts (Agent Studio, admin dashboard) must not assume English string lengths.
- Formality registers. Japanese has multiple politeness levels (keigo). Korean has formal/informal speech levels (존댓말 / 반말). Agent system prompt directives must account for this, and account-level policies may specify required formality.
- Input method considerations. Search and filtering in Agent Studio and the admin dashboard must handle CJK input correctly (no assumption of space-delimited words).
- Character encoding. UTF-8 throughout (already the Node and Convex default). No special action needed, but this should be validated in the test matrix.
9. Phasing¶
The i18n infrastructure should be threaded through the platform from Phase 1. Retrofitting locale propagation into an existing codebase is substantially more expensive than building it in from the start.
9.1 Phase 1 (Foundation and Single Agent)¶
localecolumn onuser_profiletable- Locale resolution helper callable from every Convex function
- Locale propagation through return values / messages to every client
i18npackage scaffolded with English string extraction (no hardcoded user-facing strings)- System prompt locale directive in the context assembler
localecolumn onknowledge_fact
All user-facing strings are written as catalogue lookups from day one, even though only the English bundle exists initially.
9.2 Phase 3 (Multi-Tenancy)¶
default_localeonaccountlocaleoverride onagent_assignment- Locale-aware knowledge retrieval (prefer matching locale)
localesmap onagent_template
9.3 Phase 5 (API and Channels)¶
- Localised API error responses across all three surfaces
Accept-Languagehandling for Platform and Integration APIs- Locale negotiation documentation in API contracts
9.4 Post-launch (Translation)¶
- Professional translation of resource bundles into target languages
- CJK-specific testing pass (text rendering, search, formality)
- Community or machine-assisted translation pipeline for ongoing string additions
10. Open questions¶
These need resolution before or during the formal specification.
Q1: Should agent personality prompts be translatable? Currently proposed as English-only with LLM code-switching. Some builders may want to author personality prompts directly in the target language for better tonal control. Do we support per-locale personality prompt variants on the agent entity?
Q2: How do we handle language in delegation chains? If Agent A operates in German and delegates to Agent B, does Agent B inherit the German locale, or use its own default? The current proposal (locale in context) would pass it through, but this may not always be desirable.
Q3: Cross-lingual knowledge retrieval quality. Is the default embedding model adequate for cross-lingual similarity search, or do we need a dedicated multilingual embedding model (for example, multilingual-e5-large) from the outset?
Q4: Right-to-left language support. Arabic and Hebrew are not in the initial target list, but should the data model and string infrastructure be designed to accommodate RTL from the start? The marginal cost is low if addressed now.
Q5: Translation workflow. What is the process for translating resource bundles? Professional translation, machine translation with human review, or community contribution? This affects file format choices and tooling.
Q6: Locale in audit trails. Should audit log entries record the locale in effect at the time of the event? This would allow organisations to verify that agents responded in the expected language, which may matter for compliance in regulated industries.
11. ADR-017¶
ADR-017: Internationalisation architecture and locale resolution.
User locale stored as BCP 47 tag with assignment-level override. Resolution order: assignment → user → account → platform default (
en). Platform strings handled via a catalogue library over the platform's nativeIntlAPI, loaded at module startup. Agent responses localised via system prompt locale directive during context assembly. Knowledge facts tagged with source locale; no mandatory multi-language duplication of knowledge. Locale resolved by a shared helper and propagated through context and message payloads. Infrastructure built from Phase 1; translations delivered post-launch. Nine languages at launch: English (with locale variants), Spanish, Brazilian Portuguese, French, German, Italian, Japanese, Korean, and Simplified Chinese.
References¶
- End-user guide source and publication: Part A of this document is the canonical end-user guide. It is the content source for the
/docsportal described in Part C. - App UI contract:
02-system-architecture.md(service topology and identity),11-convex-reference.md(Convex React client patterns, schemas),07-security-governance.md(Clerk integration, role model, permission gates),12-developer-guide.md(Convex + Clerk setup, environment configuration). - Data model:
04-data-model.mdforuser_profile,account,account_user,team,team_member,agent,agent_assignment,agent_template,knowledge_fact,notification,doc_section,doc_page,api_endpoint,api_code_example, and related tables. - Agent behaviour:
03-agent-architecture.mdfor context assembly, system prompt construction, delegation mechanics, job lifecycle surfaced in the activity page. - External APIs:
09-external-api-tool-integration.mdfor the Channel, Platform, and Integration API contracts used by both the developer portal (Part C) and the i18n response pattern (Part D section 7). - Agents catalogue and platform services:
08-agents-catalogue.mdfor the service registry (OpenRouter, Voyage AI, Postmark, and so on) surfaced in Settings > Account > Services & Keys. - Governance policy framework:
07-security-governance.mdPart B for the policies the briefing, activity, audit, and policies pages render. - Pricing and credits:
01-product-and-strategy.md(pricing tiers) for the model surfaced in Subscription & Billing.
Revision history¶
| Version | Date | Change |
|---|---|---|
| 1.0.0 | 2026-04-16 | Initial consolidated release. Supersedes pre-consolidation docs 12 (User Guide v02), 18 (Internationalisation v02), 23 (App UI Specification v03), 29 (Docs & Developer UI v01). Editorially updated to the Convex + Clerk architecture: Supabase Auth replaced with Clerk throughout Part B; REST endpoint examples replaced with Convex query / mutation / action calls (functional surface unchanged); TanStack React Query replaced with Convex React client; Go + golang.org/x/text i18n stack replaced with TypeScript + Intl + a catalogue library; Postgres reference schemas preserved in Part C for archival, with Convex form documented alongside; table names normalised to singular (doc_section, api_endpoint, user_profile, agent_assignment, knowledge_fact); cross-references retargeted to the 14-document canonical set. No content loss beyond renumbering, sentence-case normalisation, and the stack-migration edits called out above. |