Noema is a calm, local-first communication and intelligence app for power users.
This repository contains the first foundational vertical slice: a mobile-first PWA shell with one functional tab (Chat) and clean extension points for future capabilities.
- Next.js App Router + TypeScript + Tailwind architecture
- Mobile-first dark glassmorphism shell
- Top bar + bottom tab navigation
- Functional Chat tab
- message list + composer
- long-press multi-select mode + bulk actions
- bottom-sheet message actions (via message action button / desktop context menu)
- markdown rendering with highlighted fenced code blocks
- Local-first persistence using Dexie (IndexedDB) + Zustand
/api/agentroute with provider adapter- deterministic
mockprovider by default - optional server-side OpenAI provider when configured
- deterministic
- Installable PWA baseline via
src/app/manifest.ts
- Auth and multi-user features
- Server-side database
- OCR/media upload pipeline
- Real translation implementation
- Advanced offline/service-worker strategy
- Scheduler/autonomous agent orchestration
src/
app/
api/agent/route.ts # server route for agent calls
globals.css # global styles/theme baseline
layout.tsx # metadata/icons/viewport
manifest.ts # App Router manifest
page.tsx # app shell + tab routing
components/
chat/
layout/
ui/
lib/
ai/
providers/
db/
store/
types/
public/
icons/ # PWA icons (SVG placeholders)
See .env.example.
AGENT_PROVIDER(mockoropenai)- Recommended first deployment:
mock
- Recommended first deployment:
OPENAI_API_KEY(required only whenAGENT_PROVIDER=openai)OPENAI_MODEL(optional model override)
npm install
npm run devOpen http://localhost:3000.
npm run build
npm run startThis repository is deployable as a standard Next.js project from repo root.
Use these settings in Vercel:
- Framework Preset: Next.js
- Root Directory:
/(repo root) - Build Command:
next build(default) - Output Directory:
.next(default) - Install Command:
npm install(default)
Then set environment variables:
AGENT_PROVIDER=mock(recommended for first deploy)- optionally
OPENAI_API_KEYandOPENAI_MODELif/when you switch provider to OpenAI
- Primary manifest source is
src/app/manifest.ts(App Router idiomatic). - PWA icons/static assets are in
public/icons. - This deployment-rescue pass intentionally uses text-safe SVG assets to avoid binary-file PR issues.
If your-project.vercel.app shows 404: NOT_FOUND, verify in Vercel dashboard:
- Project -> Settings -> General -> Root Directory is
/(repo root). - Project -> Settings -> Git -> Production Branch matches your pushed branch (usually
main). - The latest deployment was created from the correct repository and commit SHA.
- Build logs show Next.js routes generated (for this app,
/,/api/agent,/manifest.webmanifest).
This repo also includes vercel.json with framework: "nextjs" to remove framework detection ambiguity.
Noema now includes an API Lockbox screen under Settings for BYOK provider management.
Included providers in this pass (with 5 representative models each):
- OpenAI
- Google Gemini
- Anthropic
- xAI
- DeepSeek
- Moonshot / Kimi
- Qwen
- Mistral
Details:
- model and pricing metadata is locally curated from official provider documentation links in
src/lib/providers/catalog.ts - pricing is read-only in UI and may be
N/Awhere official docs vary by region/tier - BYOK secrets are stored locally on-device in this phase via a lockbox abstraction (encryption hook prepared for later hardening)
- Gemini safety filters expose all four harm categories with default
BLOCK_NONE, plus user-selectable filter level toggles
Noema now treats raw markdown strings as the canonical text format for displayable text surfaces.
- shared renderer:
src/components/markdown/markdown-renderer.tsx - canonical storage contract helpers:
src/lib/markdown/contract.ts - current syntax support: headings, emphasis, strikethrough, blockquotes, ordered/unordered/task lists, links, tables, inline code, fenced code blocks, and horizontal rules
- raw HTML rendering is disabled
- Obsidian-style
[[wikilink]]and![[embed]]tokens are transformed to safe internal link tokens for forward compatibility
- Long-press enters multi-select mode on chat messages.
- While multi-select is active:
- tap messages to toggle selection
- use the selection action bar for copy/delete/convert-to-note
- Message-specific action sheet is available from the message actions button (
...) and desktop right-click, avoiding long-press gesture conflicts on mobile.
- Markdown is the canonical content format across chat and note conversion flows.
- Supported markdown in renderer includes headings, quotes, lists, links, tables, inline/fenced code, and horizontal rules.
- Note conversion utilities now produce canonical markdown notes with frontmatter prep (
title,created,updated,tags) for Obsidian-friendly export preparation. - Export is currently an architecture layer (planned files/paths in
Notes/+Assets/), not a full vault filesystem writer yet.
- Real translation for single/bulk actions
- Full notes UI/editor and vault file writer
- Attachment binary export pipeline (only naming/embed conventions are prepared)
- Documents are markdown-native and store source content as raw
bodyMarkdown. - Organizer currently contains:
- Documents (functional list + editor + preview),
- Tasks (placeholder),
- Calendar (placeholder).
- Current document capabilities:
- create/open/edit documents with debounced autosave
- edit metadata (folder, tags, pin, archive)
- filter by all/pinned/archived + optional folder chips
- document long-press selection mode and bulk actions
- attachment/link relationship groundwork
- OCR/import/export groundwork placeholders and utilities
- Deferred:
- full OCR capture pipeline
- full export/import file picker + vault packaging flow
- Tasks/Calendar implementation
- Added a canonical local-first TaskRecord model with:
- status workflow:
inbox | todo | doing | done | archived - priority:
low | normal | high | urgent - markdown-native description (
descriptionMarkdown) - due/completion/tags/folder/pin metadata
- intake/source fields for manual/voice/AI/message/document conversion paths
- status workflow:
- Added subtask-ready structure (
subtasks) as a clean extension point without introducing dependency graphs yet. - Persistence is now prepared via Dexie
taskstable and ZustanduseTaskStorefor hydration + CRUD/status updates. - Task markdown uses the same shared markdown storage contract as chat/documents (
TASK_MARKDOWN_CONTRACTaliases the app markdown contract). - Organizer now includes a functional mobile Tasks list with quick filters (
Today,Upcoming,All,Done,Archived), metadata-rich rows, and a floating create-action button. - Tasks FAB now opens a capture launcher with:
- input method choice: Type task or Speak task
- intake mode choice: Guided form or Conversational
- persisted default-mode preference (
guided_formby default) and optional “remember last used mode”
- Guided intake mode now runs an AI-assisted structuring step (runtime-backed with local heuristics fallback), then opens an editable structured draft (title, description, due, duration, priority, status, optional subtasks) before save/discard.
- Conversational intake mode now provides a compact task-focused Q&A flow that progressively resolves clarifications, shows draft summary, and can switch into manual structured edit before final save.
- Tasks now include a dedicated detail/edit screen with markdown description edit/preview, status/priority/due/duration controls, subtasks editor, tags, pin/archive controls, and debounced autosave.
- Tasks list now supports long-press action sheet + multi-select mode with bulk complete/archive/pin/delete actions for mobile workflows.
- Tasks now support a view switcher with List (default) and a compact Board view grouped by status (
Inbox,Todo,Doing,Done; archived-focused lane when filtered to archived). - Tasks now include reminder groundwork (
reminderEnabled,reminderAt,reminderState, optional reminder note/attempt metadata) with editor controls and utility hooks for future in-app/local/push reminder integrations. - Tasks remain user-owned and markdown-friendly: descriptions are markdown-native and editable in-place with preview.
- Intake modes are intentionally split:
- Guided form for structured fields and edits
- Conversational for compact Q&A clarification flow
- Calendar foundation now includes a canonical local-first event model (
CalendarEventRecord), Dexie persistence + Zustand store, shared markdown contract reuse, and task-bridge-ready fields (linkedTaskId,sourceType: task_projection). - Organizer Calendar now has a functional mobile home screen with date context,
Agenda | Day | Monthview selector (Agenda default), today jump, directional date navigation, empty states, and event-create FAB. - Agenda now groups events by day with practical metadata chips (all-day, location, linked-task, reminder, color-tag), and Day now uses a compact time-aware timeline layout optimized for phones.
- Month view now uses a mobile-friendly grid with current-day and selected-day highlighting, subtle event density indicators, and a linked selected-day event panel below the grid.
- Calendar events now support mobile create/edit via a dedicated event sheet (title, markdown description, start/end, all-day, timezone, location, reminder, color tag, linked task ID) with explicit Save and validation.
- Tasks and Calendar are now bridged for first-pass scheduling: task action sheets can project due tasks into linked calendar events (
sourceType: task_projection,linkedTaskId), and task cards show a “Scheduled” indicator when linked events exist. - Calendar reminder groundwork now includes
reminderState, optionalreminderNote, and reminder candidate utilities for future in-app/push dispatch integration. - Calendar recurrence groundwork now includes a simple preset UX (
none,daily,weekly,monthly,custom) backed byrecurrencePreset+recurrenceRuleutilities for future recurring instance expansion. - Calendar now includes a mobile actions layer: long-press (or context press) on events opens a bottom sheet with open/edit/duplicate, quick reschedule presets (later today/tomorrow/next week), compact datetime reschedule, complete/cancel/archive, and guarded delete.
- Calendar now includes AI-assisted event intake: FAB opens an intake launcher, fuzzy requests can be structured into an editable guided draft with targeted clarifications, and users confirm/edit/discard before save.
- Deferred in this phase: full Calendar scheduling, always-on background reminder automation, and autonomous task agents.
- Deferred:
- deeper project/task views beyond single-task edit surface
- autonomous agent task workflows
- Added reusable manual recording/transcription button (
VoiceCaptureButton) for input surfaces. - Recording behavior is tap-on/tap-off with no automatic speech cutoff:
- tap once to start recording
- speak as long as needed
- tap again to stop and transcribe
- transcript is inserted into the invoking input field
- Added STT provider abstraction under
src/lib/sttand server routePOST /api/stt/transcribe. - Providers in this phase:
openai(implemented)google_cloud(adapter placeholder)android_native(future-native placeholder)
- OpenAI STT models exposed exactly as:
gpt-4o-mini-transcribe(default)gpt-4o-transcribe
- Added STT preferences in Settings:
- provider selection
- OpenAI transcription model
- optional preferred language code
- remember-last-provider toggle
- Deferred:
- realtime streaming speech recognition
- TTS / voice playback
- Android native SpeechRecognizer runtime integration
Noema now includes a functional Agents tab for local agent profile management.
- create, edit, duplicate, and delete agent profiles
- local persistence via Dexie/IndexedDB (
agentstable) - structured agent schema (identity, typography, model binding, behavior, generation settings, metadata)
- provider/model selectors use the shared provider catalog
- lockbox configuration status is shown per provider (selectable even if not configured)
- generation controls are filtered to provider/model-supported settings
- curated self-hosted font set via
next/font/google: Inter, Manrope, IBM Plex Sans, Space Grotesk, Merriweather, JetBrains Mono - roleplay is structured (toggle + 0-5 intensity) and prompt composition uses reusable utilities
- live preview uses deterministic local template output (no live API call)
Deferred in this stage:
- autonomous behavior/scheduling/tool execution
- agent-to-agent orchestration
- marketplace/public publishing
- memory retrieval engine
- Agent Studio provider/model selectors read directly from the shared provider catalog (single source of truth).
- Provider options display configured/not-configured state from Lockbox records.
- Unconfigured providers are still selectable for profile design, but editor warns runtime calls are unavailable until configured.
- Generation controls are filtered to provider/model-supported settings and incompatible values are sanitized when provider/model changes.
src/lib/runtime/types.tsintroduces typed runtime contracts for invocation modes, streaming modes, execution requests/results, provider payloads, and structured error codes.src/lib/runtime/prompt-pipeline.tscomposes final runtime system prompts from structured agent fields + invocation mode policy.src/lib/runtime/payload-builder.tsbuilds provider-ready payloads from agent profile + provider/model metadata + lockbox status + conversation context and validates compatibility.src/lib/runtime/execute-agent.tsexecutes provider payloads through provider adapters and returns structured results.src/lib/runtime/agent-runtime-core.tsprovides an end-to-end build+execute entrypoint for future chat/runtime integration.
Current deferments:
- full streaming transport plumbing in chat UI
- complete UI wiring for every invocation mode
- autonomous/scheduled/background agent execution
- Chat composer can select/clear an active agent per thread (stored locally for the default thread).
- Sending a message with an active agent builds runtime payloads from agent profile + provider/model metadata + lockbox config.
- Agent responses are inserted as styled agent messages with agent identity metadata (avatar shape/image, font, accent, provider/model info).
- Streaming behavior currently supports one-shot and simulated chunked/stream display while preserving runtime streaming mode contracts.
- If provider is not configured (or adapter is unavailable), chat inserts clear system status messages instead of failing silently.
- Message long-press sheet includes an Agent action group: ask selected agent, ask different agent, summarize (private), rewrite, explain, and convert to note.
- Invocation actions pass selected message content into Agent Runtime Core payload building with invocation mode metadata.
- Output visibility now distinguishes
publicvsghost(private) result metadata; private results are visually tagged in-thread. - If no active agent exists, long-press invocation can prompt user to pick an agent and continue the action.
GNU Affero General Public License v3.0 (AGPL-3.0-only). See LICENSE.