Notes can now be clustered into named sections in the tab bar: each tab
gets a 🏷 button to assign it to a section, and clicking a section's
label renames (or, given an empty name, ungroups) every page in it.
note_pages gains a `section` column. Since the app has no migration
framework, database.py adds the column to existing SQLite files at
startup via PRAGMA table_info + ALTER TABLE. core/notes.set_section()
keeps same-section pages contiguous by renumbering position whenever a
page's section changes, so the tab bar and the AI-facing title list
(now grouped under "## section" headings) can both treat "adjacent" as
"same group" without a separate ordering field.
Also fixes a bug in the tab rename input: ref="renameInput" sits inside
a nested v-for, which Vue 3 binds as an array rather than a single
element, so renameInput.value?.select() was throwing on every rename.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a note_pages table backing a tabbed notes panel where the user and
the model can both read and write. Only page titles (plus a short
preview) are injected into the system prompt on every turn; full page
content is kept out of context and fetched on demand via a read_note
tool, with write_note letting the model append to, replace, or create a
page.
Generalizes llm.resolve_web_search into resolve_tool_calls so the
tool-calling loop handles web_search and the new note tools through one
path. The chat stream emits a notes_updated SSE event when the model
edits a note so the frontend panel can refresh; local edits are tracked
as dirty and never clobbered by that refresh.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sessions can now be downloaded as a JSON file containing the session
metadata and every message with its tags, and re-imported as a new
session from that same format.
GET /chat/sessions/{id}/export streams the session as a file download.
POST /chat/sessions/import validates the roles, then recreates the
session under a fresh UUID so importing never collides with an existing
session. The sidebar gets a per-row download button and an import button
that feeds a hidden file input.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Chat/memory/logs/models APIs were reachable without any auth even
though the app is deployed publicly behind Caddy HTTPS; only the
settings screen had a password. Add an optional SITE_PASSWORD-backed
session cookie gate in front of everything (settings included, on
top of its existing SETTINGS_PASSWORD), with a matching login screen
on the frontend. Stays fully backward compatible: with SITE_PASSWORD
unset the app behaves exactly as before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add a password-protected /api/settings endpoint (HTTP Basic auth,
backend/app/core/auth.py) backed by a DB-stored allowlist of
connection settings (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS creds,
OLLAMA_API_BASE, TAVILY_API_KEY, LOCAL_KB_EMBEDDING_MODEL). Saved
values override .env and apply immediately via os.environ, so
Lightsail deployments no longer need SSH + `.env` edits to rotate
keys. Values are always returned masked to the frontend.
- Replace ModelSelector.vue's hardcoded model list with a DB-backed
/api/models CRUD API (read is public, writes reuse the settings
password) so the chat model dropdown can be edited from the GUI;
seed it once with the previous hardcoded presets on first boot.
- Fix local_knowledge.py reading LOCAL_KB_EMBEDDING_MODEL once at
import time instead of per-call, which would have silently ignored
GUI/DB overrides for the embedding model.
- Add SettingsPanel.vue (API keys + model management UI) and document
the new SETTINGS_PASSWORD env var in .env.example and the Lightsail
deploy guide.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add backend/frontend Dockerfiles, nginx reverse proxy config, and
docker-compose.yml to run the app on AWS Lightsail; document the setup
in docs/deploy-lightsail.md. Fix a .gitignore path anchoring bug that
left backend/knowledge_base/web_search/ untracked instead of ignored.
- Summarize web search results into structured Markdown via LLM before
saving them to the local knowledge base, and support regenerating
existing entries from their source URLs (backend/app/core/memory_kb).
- Downgrade vite to ^6 to match @vitejs/plugin-vue's peer dependency
range, fixing a failing `npm ci` (found while testing the Docker build).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Split backend/app/core into weather/, discord/, memory_kb/, search/
subpackages by responsibility, keeping config.py and llm.py as the
shared foundation; updated all import sites accordingly.
- Add local Markdown knowledge base support (local_knowledge.py,
knowledge_base/fgo.md, LOCAL_KB_* settings) that embeds and injects
relevant docs into the system prompt by topic similarity.
- Add ruff and pyright as backend dev dependencies with basic config
in pyproject.toml for linting and type checking.
- Document local machine quirks in CLAUDE.md (Postgres on port 8080,
SSLKEYLOGFILE breaking litellm/pyright via OPENSSL_Uplink crashes).
- Add backend/run_dev.ps1 dev launcher and docs/discord-bot.md.
Introduces websearch.py (Tavily) + knowledge.py to ground chat responses
in search results, tagging.py to tag user and assistant messages via LLM
and pick related topics for the Discord useless-tips job, and
word_memory.py to track recent conversation nouns (surfaced in the new
WordPool.vue sidebar) used to pick tip topics close to a related tag.
- Cache the latest fetched tomorrow weather and expose it via /api/system/weather/latest
- Add a header Clock widget showing date/time plus the cached weather summary
- Redirect useless-talk mentions from the weather bot to the useless-tips webhook
- Switch Bedrock auth from bearer token to standard IAM access key/secret
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>