Commit graph

3216 commits

Author SHA1 Message Date
Till JS
f0c38da784 feat(rituals): switch icon from Lightning to ArrowClockwise
Lightning was inherited from the ai-rituals era (AI-feature vibe) and
didn't match what rituals actually express — recurring, cyclical
practice. ArrowClockwise reads as "loop / recurrence / do this
regularly", which fits both utility and ceremony flavours.

Lightning is kept for `automations` (still the right match there).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:51:37 +02:00
Till JS
2b96953ad1 fix(llm): user-friendly error messages when no LLM tier available
Track skip reasons per tier in the orchestrator (no-consent,
no-backend, not-available, not-ready, runtime-error) and expose
them via NoTierAvailableError.getUserMessage() with actionable
German text pointing the user to the right settings page.

Before: "No tier could run task 'companion.chat' (attempted: cloud)"
After:  "Cloud (Gemini): Cloud-Einwilligung fehlt. Aktiviere sie
         unter Einstellungen → KI."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:46:39 +02:00
Till JS
c642e1be78 feat(workbench): add inline module help — ? icon in PageShell header
Clicking the ? icon in a workbench panel header toggles an inline help
view that replaces the ListView content. Shows module description,
feature list, and usage tips. Help content for ~45 modules defined in
a central help-content.ts registry, auto-attached via registerApp().

- AppDescriptor gains optional `help` field (description, features, tips)
- PageShell gains onHelp/helpOpen props with highlighted active state
- AppPage renders help inline in the page-body, not as a popover
- help-content.ts: per-module descriptions, features, and tips (German)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:44:48 +02:00
Till JS
2bdb48bdd1 feat(research): add mana-research service — Phase 1 + 2
New Bun/Hono service on port 3068 that bundles many web-research providers
behind a unified interface for side-by-side comparison. All eval runs
persist in research.* (mana_platform) so quality can be reviewed later.

Providers (Phase 1+2):
  search:  searxng, duckduckgo, brave, tavily, exa, serper
  extract: readability (via mana-search), jina-reader, firecrawl

Endpoints:
  POST /v1/search, /v1/search/compare       — single + fan-out
  POST /v1/extract, /v1/extract/compare     — single + fan-out
  GET  /v1/runs, /v1/runs/:id               — history
  POST /v1/runs/:run/results/:id/rate       — manual eval
  GET  /v1/providers, /v1/providers/health  — catalog + readiness

Auto-routing: when `provider` is omitted, queries are classified via regex
(fast path, 0ms) with optional mana-llm fallback, then routed to the first
available provider for that query type (news → tavily, academic → exa,
semantic → exa, etc.).

Credits: server-key calls go through mana-credits reserve → commit/refund
so failed provider calls don't charge the user. BYO-keys supported via
research.provider_configs (UI arrives in Phase 4).

Cache: Redis with graceful degradation (1h TTL for search, 24h for
extract). Pay-per-use APIs only — no subscription-gated providers.

Docs: docs/plans/mana-research-service.md + docs/reports/web-research-capabilities.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:42:25 +02:00
Till JS
004fc0b2fd feat(credits): add 2-phase debit (reserve/commit/refund)
Introduces credit_reservations table + three internal endpoints so services
that need to charge only after a downstream call succeeds (notably the
upcoming mana-research fan-out across paid provider APIs) can reserve
credits atomically, then commit on success or refund on failure. One-shot
/credits/use remains for synchronous operations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:41:41 +02:00
Till JS
2df9ecdcaa feat(rituals): rename ai-rituals → rituals, add ceremony step types
The module was named "ai-rituals" because every step was a tool call
(log drink, show tasks, create task from text input). That framing
excluded a whole class of rituals that *don't* capture data —
personal ceremonies that just want to hold the user's attention for a
minute: the morning coffee, the Sunday reset, the before-bed shutdown.

Changes:

  - Renamed the module: apps/web/src/lib/modules/ai-rituals → rituals
  - App id 'ai-rituals' → 'rituals' in app-registry/apps.ts
  - Moved the category from 'ai' to 'life' in app-registry/categories.ts
    (personal practice, not an AI subsystem)
  - Added RitualCategory = 'utility' | 'ceremony' | 'mixed' on both
    LocalRitual and RitualTemplate. Defaults to 'utility' on read so
    existing data from before this change stays accessible.
  - 3 new step types in the RitualStepConfig union:
      - presence : markdown body + optional countdown, no tool call.
                   Use case: "Fünf Minuten still trinken."
      - breath   : guided breathing with a circle that expands/contracts
                   on inhale/exhale. Presets: box (4-4-4-4), 4-7-8,
                   coherent (5-0-5-0), plus custom timings.
      - media    : image + caption (mantra / photo / quote) with
                   optional linger timer.
  - RitualRunner extended: timer teardown on step change, breath state
    machine with phase-driven scaling animation, stop/early-exit for
    both.
  - 3 ceremony templates seeded:
      - Morgenkaffee    : Wasser → Aufbrühen → 3 tiefe Atemzüge →
                          5 Min still trinken
      - Sonntag-Reset   : Ankommen → Streaks → Was nehme ich mit? →
                          Nächste Woche → Handy weg (mixed)
      - Vor dem Schlaf  : Bildschirme aus → 4-7-8 Atmung → Journal-
                          Eintrag → Loslassen
  - ListView: category filter chips (Alle / Utility / Zeremoniell),
    templates grouped by category in the picker, category pill on each
    ritual row (hidden for the default 'utility').
  - docs/MODULE_REGISTRY.md: moved from AI-System (now 8) to Gesundheit
    & Wellness (now 11).

No schema migration — the new `category` field is optional on
LocalRitual and falls back to 'utility' when undefined, so Dexie
doesn't need a version bump. Existing rituals (none in production)
keep working.

Heads-up for scenes: anyone who had 'ai-rituals' pinned to a workbench
scene will need to re-add it as 'rituals'. Acceptable given
pre-launch state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:41:26 +02:00
Till JS
a2423b4932 fix(wetter): add icons to detail grid (wind, humidity, pressure, UV)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:27:16 +02:00
Till JS
fef71dd571 fix(wetter): design improvements — scroll chips, hierarchy, dedup names
- LocationPicker: horizontal scroll instead of wrapping chips, action
  buttons now show text labels (Standort, Hinzufügen, Verwalten)
- CurrentConditions: temperature is now the dominant hero element (4rem),
  deduplicate "Berlin, Berlin" → "Berlin", added last-updated timestamp
- Fix "Uebersicht" → "Übersicht" umlaut in tab labels
- Better visual hierarchy: temperature dominates, details recede

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:24:10 +02:00
Till JS
ef91b61e20 feat(wetter): improve location management with save/remove/default
Rework LocationPicker with three actions:
- "+" button opens search that saves results as persistent locations
- Gear button opens manage panel to set default (★) or remove cities
- Saved locations appear as chips; default location auto-loads on open

Search results show "Speichern" label and auto-save on click. Already
saved locations show "Gespeichert" instead. Default location marked
with a blue dot in chips and a star in the manage panel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:13:30 +02:00
Till JS
1add202c56 fix(library): make form labels and inputs readable
The EntryForm labels were using --color-text-muted at 0.85rem, which on
a dark theme made them almost invisible against the purple-tinted
inline-create container. Same issue for the <legend>s.

Changes:
  - labels + legend use inherit (full foreground color) at 0.88rem with
    font-weight 500 so they pop against the background
  - inputs get a more opaque background (--color-background fallback)
    and slightly darker borders so fields are distinguishable as
    interactive targets, not just text runs
  - added explicit ::placeholder color so the muted hint text is
    readable but not competing with the actual value
  - h2 bumped to font-weight 600
  - details-section summary gets color: inherit + slightly bigger font

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:11:10 +02:00
Till JS
cf4d849187 feat(wetter): full feature parity for workbench ListView
Replace the compact ListView with the full weather view including
LocationPicker, tab switcher (Uebersicht / Quellen-Vergleich),
all weather components, and the multi-model comparison — same
functionality as the /wetter page route.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:08:51 +02:00
Till JS
d2cf8223e2 feat(library): move search to top of the controls
New control order: search (full-width, flex) + "+ Neu" button → KindTabs
→ status chips + favourites toggle. Search is the primary entry point
when the user knows what they're looking for; tabs + filters refine the
grid when browsing. The create button stays aligned with search because
that's where the user's eye already is when they decide "nope, not here,
I'll add it".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:06:13 +02:00
Till JS
5bdacaa5ea feat(wishes): add Wünsche module — wishlists with price tracking
New module for managing wishes/gift ideas with lists, price targets,
product URLs, price history, and AI tools. Includes ListView with
filter tabs, inline list management, search, and DetailView with
notes and price history. Encrypted at rest (title, description, URLs,
notes). Registered in database v24, module-registry, crypto registry,
seed registry, tool init, and DnD type system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:02:37 +02:00
Till JS
fea37c36a4 feat(library): drop page h1, move create to inline accordion
The workbench already renders the app name ("Bibliothek") as the scene
tile header, so the ListView's own <h1>Bibliothek</h1> + subtitle was
a duplicate header stack. Removed.

The "+ Neu" flow is no longer a full-screen modal overlay. The button
now sits inline at the end of the KindTabs row and toggles between
"+ Neu" / "× Schließen". When active, the EntryForm expands in-place
right under the controls, above the grid — no z-index dialog, no
backdrop, no ESC-to-close plumbing. Fits the workbench tile/window
aesthetic (content stays within the tile boundary, no overlays
escaping the window).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:02:21 +02:00
Till JS
9b8c69123c feat(wetter): add multi-model source comparison view
New "Quellen-Vergleich" tab on the weather page that fetches the same
location from 5 weather models in parallel (DWD ICON-D2, ICON-EU,
ECMWF IFS, NOAA GFS, Open-Meteo Best Match) and displays them stacked
for easy comparison of temperature, precipitation, and daily forecasts.

Adds /api/v1/wetter/compare endpoint and SourceComparison.svelte.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:57:05 +02:00
Till JS
85bba162db feat(library): register as workbench app (Kreativ category)
Library was listed in MANA_APPS (for the tier/branding registry) and had
a /library route, but it wasn't yet registered in the workbench app
registry — so users couldn't add it as a tile to their Workbench scene.

Adds:
  - registerApp({ id: 'library', icon: Stack, … }) in app-registry/apps.ts
    with a "+ Neuer Eintrag" context-menu action (emits the standard
    mana:quick-action CustomEvent, ready to be listened to in ListView
    once we want an in-workbench create flow).
  - library → 'creative' entry in app-registry/categories.ts so it
    appears in the Kreativ section of the app picker.

Only the list view is registered; the detail view still uses the
route-based pattern (/library/entry/[id]) and the route-level +page.svelte
wrapper. Migrating DetailView to the workbench ViewProps shape (params +
navigate + goBack) is deferred — the route works fine for now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:53:01 +02:00
Till JS
24704e28b6 fix(wetter): mount routes before auth middleware
Weather data is public — no user-specific data involved. Move the
wetter route registration above authMiddleware() so requests don't
require a JWT token. Rate limiting still applies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:37:17 +02:00
Till JS
96a7202daa feat(wetter): register workbench panel with ListView
Add ListView.svelte (compact weather card for workbench panels),
register via registerApp() in apps.ts with CloudSun icon, and
assign to 'life' category so it appears in the Leben section
of the AppPagePicker.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 13:33:59 +02:00
Till JS
a252160585 feat(library): M3 — progress tracking (pages, episodes, issues) + restart
ProgressControls.svelte renders typ-spezifische Fortschritts-UI:
  - book   → range slider + page input + "Fertig"-Button; auto-completes
             the entry (status=completed, times++) when current == total
  - series → collapsible season/episode grid; each episode is a toggleable
             pill that writes into details.watched with a watchedAt stamp;
             auto-completes once watched.length == totalEpisodes
  - comic  → ±1 issue bumper; auto-completes on issueCount reach
  - movie  → atomic, no progress widget

libraryEntriesStore.restartEntry: flips a completed entry back to active,
stamps startedAt=today, clears completedAt. Preserves the per-episode
watched list so users keep the history of the previous run-through; they
can reset individual episodes via the tracker if they want a fresh pass.

DetailView embeds <ProgressControls {entry}> below the status row and
renders a "↻ Nochmal lesen/sehen" button whenever status === 'completed'.

docs/plans/library-module.md: M1 + M2 + M3 marked DONE with commit IDs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:17:22 +02:00
Till JS
364178496a feat(library): M2 — CRUD form, grid view, detail view
Adds the user-facing surface for the Bibliothek module:

Components (components/):
  - KindTabs         — Alle / Bücher / Filme / Serien / Comics with counts
  - StatusFilter     — Geplant / Läuft / Fertig / Pausiert / Abgebrochen chips
  - RatingStars      — 0–5 stars, click to set, click again to clear
  - StatusBadge      — colored status pill
  - CoverImage       — lazy <img> with kind-emoji fallback
  - EntryCard        — grid card (cover + title + rating + status)
  - EntryForm        — create/edit with kind selector + typ-spezifische
                       Felder (pages, runtime, seasons, issues, format)

Views (views/):
  - GridView         — responsive grid of EntryCards + empty state
  - DetailView       — cover, metadata, status picker, rating, delete/fav
                       actions, review display, typ-spezifische details
                       (book pages/format, movie runtime/director, series
                       seasons/episodes, comic issues/publisher).
                       Edit toggles in-place to EntryForm.

Route:
  - /library              — rewritten ListView (tabs + filters + grid + FAB)
  - /library/entry/[id]   — DetailView

Progress features (episode tracker for series, page slider for books,
times-counter button for re-reads/re-watches) are deferred to M3 since
they need dedicated interaction patterns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 03:57:55 +02:00
Till JS
8c6502d0ff feat(library): add Bibliothek module — books/movies/series/comics log
M1 skeleton for a new media-consumption module. Single-table design with
a `kind: 'book' | 'movie' | 'series' | 'comic'` discriminator and a
discriminated `details` union for kind-specific fields (pages / runtime /
episode tracker / issue count). Shared kern: status, rating, review,
favourites, times counter, completedAt — which enables cross-media
queries like a year-in-review.

Dexie migration v26 was already registered in module-registry.ts /
database.ts via the preceding wetter commit (62aac6dfd); this commit
adds the actual module code, encryption registry entry, app-icon,
MANA_APPS entry, Kreativität & Medien category row, and the module
plan at docs/plans/library-module.md.

Encrypted fields (via ENCRYPTION_REGISTRY):
  title, originalTitle, creators, review, tags
Plaintext (intentional):
  kind, status, year, rating, genres, completedAt, isFavorite, times,
  externalIds, details — all needed for the tab filter, status chips,
  Jahresrückblick range-scan, and progress UIs.

Product decisions (frozen in the plan):
  - audiobooks = kind='book' with details.format='audio'
  - manga     = kind='comic' (no sub-discriminator)
  - metadata lookup (M7) lands as an endpoint in apps/api, not a
    standalone service

Guest seed ships one example per kind (Dune, Arrival, Severance, Saga)
so first-run users immediately see what the module does.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 03:49:01 +02:00
Till JS
62aac6dfdb feat(wetter): add weather module with Open-Meteo, DWD alerts, and rain nowcast
New module providing weather data for the DACH region via three sources:
- Open-Meteo (DWD ICON-D2 model) for current conditions and 7-day forecast
- DWD warnings endpoint for severe weather alerts
- Rainbow.ai / Open-Meteo fallback for minute-level rain nowcast

Includes API proxy with in-memory caching, Svelte 5 UI with location
picker, hourly/daily forecast, alert cards, and precipitation bar chart.
Two AI tools (get_weather, get_rain_forecast) enable the companion to
answer weather questions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 03:46:15 +02:00
Till JS
20aeccfaca chore(hooks): drop --fail-on-warnings from pre-push svelte-check
Some checks failed
CI / Build mana-sync (push) Has been cancelled
CI / Build mana-notify (push) Has been cancelled
CI / Build mana-api-gateway (push) Has been cancelled
CI / Build mana-crawler (push) Has been cancelled
CI / Build mana-media (push) Has been cancelled
CI / Build mana-credits (push) Has been cancelled
CI / Build mana-web (push) Has been cancelled
CI / Build chat-backend (push) Has been cancelled
CI / Build chat-web (push) Has been cancelled
CI / Build todo-backend (push) Has been cancelled
CI / Build todo-web (push) Has been cancelled
CI / Build calendar-backend (push) Has been cancelled
CI / Build calendar-web (push) Has been cancelled
CI / Build clock-web (push) Has been cancelled
CI / Build contacts-backend (push) Has been cancelled
CI / Build contacts-web (push) Has been cancelled
CI / Build presi-web (push) Has been cancelled
CI / Build storage-backend (push) Has been cancelled
CI / Build storage-web (push) Has been cancelled
CI / Build telegram-stats-bot (push) Has been cancelled
CI / Build food-backend (push) Has been cancelled
CI / Build food-web (push) Has been cancelled
CI / Build skilltree-web (push) Has been cancelled
Docker Validate / Build calendar-web (push) Has been cancelled
Docker Validate / Build quotes-web (push) Has been cancelled
Docker Validate / Build todo-backend (push) Has been cancelled
Docker Validate / Build todo-web (push) Has been cancelled
Docker Validate / Build mana-auth (push) Has been cancelled
Docker Validate / Build mana-sync (push) Has been cancelled
Docker Validate / Build mana-media (push) Has been cancelled
26 pre-existing warnings (a11y, unused CSS) block every push. These
are valid lint warnings, not type errors — they shouldn't gate pushes.
Errors (0 currently) still block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 02:53:44 +02:00
Till JS
40a3a8cdd2 fix(settings): remove stale showTitle prop from SecuritySection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:39:22 +02:00
Till JS
97adfa7020 chore: update scheduled tasks lock 2026-04-16 16:36:33 +02:00
Till JS
4b21e3f448 docs: add MODULE_REGISTRY.md — index of all 72 webapp modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:36:26 +02:00
Till JS
35ffa8a079 docs(landing): devlog entries Apr 9–15
Seven devlog posts covering the daily development sprint:
- Apr 9: News module, Body tracker, Nutriphi AI photo, infra marathon
- Apr 10: Journal sync, credits/billing, geocoding, a11y
- Apr 11: Settings redesign, geocoding, deployment, monitoring
- Apr 12: UI redesign, wallpaper generator, floating input, drink module
- Apr 13: Companion brain, sleep/stretch/recipes/mail modules
- Apr 14: AI Workbench, actor attribution, missions, key-grants
- Apr 15: Multi-agent workbench, news-research, settings, theme migration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:36:18 +02:00
Till JS
efc7641a60 chore(ai): P2 batch — prompt sync, perf, dedup, scope unification
Six P2 items from the AI Workbench audit:

#7 Prompt ↔ loop budget sync:
  System prompt now says "1 bis 5 Schritte pro Planungsrunde, bis zu 5
  Planungsrunden" — matches MAX_REASONING_LOOP_ITERATIONS. Cross-ref
  comment added to runner.ts.

#9 SceneHeader: useAgents() → useAgent(id):
  Only loads the single bound agent instead of the full agent list.
  Eliminates unnecessary Dexie churn on every scene header render.

#10 Unified scope filter:
  New scope-filter.ts with filterByScopeTagMap() (batch, sync) and
  filterByScopeAsync() (per-record). Both scope-context.ts (AI) and
  scene-scope.svelte.ts (UI) now import from the shared module —
  zero duplicated filter logic.

#11 Research dedup:
  Research input ID changed from `news-research-${Date.now()}` to
  `news-research-${mission.id}` — re-runs overwrite instead of
  appending duplicates.

#12 Kontext injection policy clarified:
  loadAgentKontextAsResolvedInput no longer falls back to the global
  singleton. Comment + code aligned: kontext injection is explicit
  (via input picker), not auto. Dead loadKontextAsResolvedInput
  kept for potential future opt-in auto-inject feature.

Audit doc updated with all items marked DONE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:33:52 +02:00
Till JS
a480393bfd fix(ai): P1 batch — N+1 queries, vault-locked, debug hardening, timeout
Four P1 fixes from the AI Workbench audit:

#3 N+1 junction queries → batch lookups:
  - TagLinkOps gains getTagIdsForMany(entityIds) — single
    where(field).anyOf(ids).toArray() instead of N calls.
  - filterBySceneScopeBatch() uses a pre-fetched Map<id, tagId[]>.
  - All 4 module queries (notes, todo, contacts, calendar) migrated.
  - 500 notes now = 2 Dexie queries (records + junctions) instead of 501.

#4 Vault-locked detection in readLocalNote:
  - Catches VaultLockedError from decryptRecords.
  - Throws descriptive "Vault ist gesperrt" instead of returning null.
  - Tools surface it as a clear error to the planner ("bitte Vault
    entsperren") instead of "Notiz nicht gefunden".

#5 Debug log hardening:
  - Resolved-input content truncated to 500 chars before storage.
  - Time-based purge: entries older than 7 days auto-deleted.
  - Reduces privacy exposure if device is stolen/profile synced.

#6 Timeout 90s → 180s:
  - 5 LLM calls on slow models (Ollama/GPU) regularly hit 90s.
  - 180s gives comfortable headroom for the reasoning loop.

Audit doc updated with status markers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:25:17 +02:00
Till JS
93358ed002 fix(ai): P0 — tool exception handling + mission run mutex
Two critical fixes from the AI Workbench audit:

1. Tool exceptions in the reasoning loop:
   stage(ps, aiActor) is now wrapped in try-catch. If a tool throws
   (Dexie error, vault locked, network timeout), the step is recorded
   as failed with the error message in the summary, and the loop
   continues with the next step. Previously, one broken tool crashed
   the entire iteration.

2. Concurrent mission scope interleaving:
   runMission() now serializes through a promise-based mutex. Two
   concurrent calls (double-click, cadence overlap) queue instead of
   interleaving — prevents the ambient withAgentScope() from stomping
   a running mission's scope with a different agent's tags.

   scope-context.ts also gains filterByScopeExplicit(records, scopeTagIds,
   getTagIds) — the explicit, race-safe variant that doesn't read
   ambient state. Callers that already have the scope should prefer it.

Also adds docs/optimizable/ai-workbench-audit-2026-04-16.md with the
full audit (P0–P2, 12 items).

Runner tests: 8/8.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:17:08 +02:00
Till JS
484761e475 fix(docker): remove deleted subscriptions pkg + add shared-ai to sveltekit-base
packages/subscriptions was deleted in the credits-merge cleanup; the
COPY line in the base Dockerfile broke every subsequent --no-cache
build. Also adds packages/shared-ai which was missing (webapp depends
on it since the Multi-Agent Workbench rollout).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 16:15:01 +02:00
Till JS
9dd2c64de2 fix(credits): replace octal literal placeholders with real toast messages
Three toast.success('\1') calls broke Vite's strict-mode parser on
startup. Replaced with proper German messages: purchase success,
cancel confirmation, reactivation confirmation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:34:00 +02:00
Till JS
57c2bdb2ad feat(workbench): scope TagSelector in SceneHeader + agent auto-infer
The SceneHeader (left side of the workbench homepage) now shows a
TagSelector directly above the template-gallery button. Users can
assign scope tags to the active scene — filtering notes/tasks/contacts/
calendar to only records tagged with those scopes (+ untagged globally
visible).

Auto-inference: when a scene is bound to an agent via viewingAsAgentId
and the scene has no explicit scopeTagIds, the agent's scopeTagIds
are used instead. A small "via Agent" hint appears so the user knows
the scope comes from the binding. Explicitly setting scope tags on the
scene overrides the agent's.

New store methods: setSceneScopeTags + updateScene (both sync the
reactive scene-scope store when the active scene is affected).
patchScene accepts scopeTagIds in its type union.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:29:07 +02:00
Till JS
fe141e193e docs: add langfristige Roadmap-Punkte zu AI_AGENTS_IDEAS.md
Update the AI agents backlog with:
- Status update: mark SSE streaming, dynamic tool catalog, MCP server,
  guardrails, OTel tracing, budget enforcement as done (with commit refs)
- New item #9: Agent-to-Agent Delegation (the biggest remaining gap)
- New item #10: A2A Agent Cards (depends on #9)
- New item #11: Graph-based Mission Workflows (low priority)
- New item #12: Agent Long-Term Memory via Embeddings

Each item includes problem statement, industry comparison, implementation
sketch, dependencies, effort estimate, and impact assessment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:27:38 +02:00
Till JS
b7f83cb734 fix: migrate remaining inline toasts + delete dead /subscription route
Fix 2 broken showToast() calls in SyncSection (function was removed
but two call sites survived — runtime error on deactivate/interval).

Migrate inline toasts to central toast store in:
- gifts/+page.svelte (11 refs)
- gifts/redeem/[code]/+page.svelte (9 refs)

Delete routes/(app)/subscription/+page.svelte — dead standalone route
from before the credits merge. Update Stripe redirect URLs in
subscriptions API to use /?app=credits&success/canceled=true.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:27:18 +02:00
Till JS
4b41549d20 fix(profile): expand data model + fix interview field mappings
- Add leisure section (media, sports, pets) + social.livingSetup to userContext
- Fix interview questions: each maps to its own field, no more bio overwrites
  (leisure.favoriteMedia → leisure.media, leisure.sports → leisure.sports,
   social.living → social.livingSetup, social.pets → leisure.pets)
- Add merge flag for array fields (goals.learn merges into goals, not replaces)
- Store.setField() supports merge=true for deduped array merging
- All ContextOverview sections now always visible with empty-state hints
- All tag-based sections (languages, goals, allergies) are inline-editable
- Routine/nutrition/social link to interview for editing
- EditProfileModal: restore email change UI (Ändern button + verification flow)
- Update AI resolver with leisure + livingSetup fields
- Add leisure to crypto registry encryption fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:24:11 +02:00
Till JS
a1bb703086 docs: final report update — 7/10 roadmap items done, all tables consistent
Fix missing strikethroughs in §6 table (#1, #2, #6) and update Fazit
to reflect final state: 7 of 10 items done. Document remaining 3
langfristige Punkte with context on dependencies and priorities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:23:37 +02:00
Till JS
fabf259526 feat(ai-agents): missions lookup + simple policy + agent fingerprint (UX 3-6)
Four UX improvements that make agents more discoverable and their
behavior more transparent. All svelte-check clean (0 errors in
changed files).

=== UX 3: Reverse-Mission-Lookup ===

Agent detail view now shows a "Missions (N)" section listing all
missions owned by this agent with status dots + state labels. Includes
a "+ Neue Mission für [agent]" button that navigates to the template
gallery. Users no longer have to mentally cross-reference between the
agents and missions modules.

=== UX 4: Simple-Mode Policy ===

The Policy section defaults to three radio-card presets:
- Standard (Vorschlag für alles)
- Vorsichtig (alles Vorschlag, keine Auto-Writes)
- Aggressiv (gleichartige Schreibvorgänge automatisch)

The full per-module matrix is now hidden behind "▸ Erweitert
anzeigen". This covers 90% of users who just want a quick
conservative/aggressive toggle. Power-users still get the full
matrix.

=== UX 5: Policy Natural Language Summary ===

Above the preset radios, a preformatted block summarizes the current
policy in plain German: "Gesperrt: X, Y · calendar: automatisch ·
Alles andere: Vorschlag". Generated from the policy object. Updates
live when the user switches presets or changes module overrides.

=== UX 6: Agent Fingerprint on List-Views ===

New <AgentDot record={item} /> component: reads __lastActor from
any Dexie record, resolves the agent's avatar via the live useAgents
query, and renders a tiny inline emoji dot next to the item title.
When no AI actor wrote the record, renders nothing (zero-width).

Wired into:
- /todo — task title row, after the title span
- /notes — note title row, after the title span

Each module import is a single line (`import AgentDot from ...`);
the component is self-contained (owns its own query + styles).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:22:55 +02:00
Till JS
26e1c4774f feat(scene-scope): wire filterBySceneScope into notes/todo/contacts/calendar queries
The four modules with tag junctions now filter their main useAll*
queries through filterBySceneScope: when a scene has scopeTagIds set,
only records tagged with at least one matching tag (+ untagged records)
appear in the UI. Modules without tag junctions (drink, food, habits,
journal, dreams, places) are unaffected — their records are always
globally visible.

- useAllNotes → noteTagOps.getTagIds
- useAllTasks → taskTagTable junction lookup
- useAllContacts → contactTagOps.getTagIds
- useAllCalendarItems → eventTagOps.getTagIds (calendar-sourced blocks
  only; task/habit blocks pass through unfiltered)

When no scene scope is active (scopeTagIds undefined), filterBySceneScope
is a no-op identity pass — zero overhead for unscoped scenes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:22:47 +02:00
Till JS
62fc566693 docs: mark OTel tracing (#7) as done in architecture report
7 of 10 roadmap items now complete. Remaining: Agent-to-Agent (#4),
A2A Agent Cards (#8), Graph Workflows (#9), Agent Memory (#10).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:21:45 +02:00
Till JS
76577869e1 feat(mana-ai): OpenTelemetry tracing + Grafana Tempo backend
Add distributed tracing to the mana-ai background runner so mission
execution can be visualized end-to-end in Grafana.

Instrumentation (services/mana-ai/):
- tracing.ts: OTel provider setup with OTLP/HTTP exporter, withSpan() helper
- tick.ts: tick.planMission span with mission/agent/user attributes
- client.ts: planner.complete span with LLM model, tokens, latency

Infrastructure:
- docker/tempo/tempo.yaml: Grafana Tempo config (OTLP HTTP on 4318)
- docker-compose: tempo service + tempo_data volume + mana-ai env var
- docker/grafana/provisioning/datasources/tempo.yml: auto-provisioned

Trace flow:
  tick.planMission (root span)
    └── planner.complete (child span)
        ├── llm.model = "gpt-4o-mini"
        ├── llm.tokens.total = 1234
        └── llm.response.length = 567

Enable: set OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
View: Grafana → Explore → Tempo datasource

Also fixes: removed broken @mana/subscriptions workspace ref from arcade.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:21:23 +02:00
Till JS
8def989ed9 chore: global ToastContainer, migrate inline toasts, delete SETUP.md
Add ToastContainer.svelte to (app) layout — renders toasts from the
central toast.svelte store (stacked, auto-dismiss, color-coded by
type). Previously the store existed but had no renderer.

Migrate inline toast implementations to the central store:
- SyncSection: showToast() → toast.success/error(), strip DOM + CSS
- Credits ListView: same migration, remove showToast + inline toast
- Profile ListView: same migration, remove showToast + inline toast

Delete apps/mana/apps/web/SETUP.md — completely outdated (references
Supabase, teams, organizations — all removed long ago). Real docs
live in CLAUDE.md and docs/LOCAL_DEVELOPMENT.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:18:50 +02:00
Till JS
0ddaab53e4 feat(workbench): Scene.scopeTagIds + reactive scene-scope store
WorkbenchScene grows an optional scopeTagIds field so scenes can act
as data-scope lenses: when set, module queries filter records to those
tagged with at least one of the scene's tags (+ untagged = global).

New reactive store scene-scope.svelte.ts:
  - setSceneScopeTagIds(ids) — called by scene store on switch/init
  - getSceneScopeTagIds()    — read by module queries
  - filterBySceneScope()     — reusable filter (same semantics as
                               AI scope-context's filterByScope)

Wired into workbench-scenes.svelte.ts:
  - setActiveScene() syncs scope on manual switch
  - liveQuery subscription syncs scope on init/sync/tab-focus

Module queries can now opt into scene scoping by calling
filterBySceneScope in their useAll* hooks — not wired yet (each
module opts in as needed). The foundation is in place.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:15:44 +02:00
Till JS
fad7f4bea3 feat(ai): guardrail layer — pre/post-plan + pre-execute checks
Add a guardrail system that runs alongside the Mission Runner pipeline
to catch obvious issues before they waste tokens or corrupt data.

Architecture (packages/shared-ai/src/guardrails/):
- types.ts: Guardrail, GuardrailResult, 4 phase interfaces
- builtin.ts: 4 built-in guardrails (always active):
  - input-size-limit: blocks >100K chars of resolved input
  - plan-step-limit: blocks plans with >25 steps (runaway planner)
  - duplicate-destructive-tool: warns if undo_drink called 2x
  - empty-required-params: blocks create_task without title
- runner.ts: runPrePlanGuardrails/runPostPlanGuardrails/runPreExecuteGuardrails

Wired into runner.ts at 3 checkpoints:
- Before deps.plan() — pre-plan check
- After plan received — post-plan check
- Before each stage() call — pre-execute check

Guardrails are synchronous, never hit the network, and produce
clear error messages when they block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:11:34 +02:00
Till JS
f5392b8b63 fix(profile): update profile.test.ts for new avatar upload + email change API
- Replace getAvatarUploadUrl test with changeEmail + uploadAvatar tests
- Fix authStore mock: getValidToken instead of getAccessToken
- Add getManaApiUrl mock for avatar upload endpoint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:09:59 +02:00
Till JS
c412508b95 feat(ai-scope): wire filterByScope into list_tasks/contacts/events + note tag UI
All major list-returning auto-tools now filter by the ambient agent
scope: list_notes (already done), list_tasks (via taskTagTable),
get_contacts (via contactTagOps), get_todays_events (via eventTagOps).
Untagged records pass through (globally visible); tagged records are
only returned when at least one tag matches the agent's scopeTagIds.

Notes detail view (/notes/[id]) grows a TagSelector widget between
the content textarea and the color picker, powered by the new
noteTagOps junction. Users can manually tag notes to scope them to
specific agents — complements the AI's add_tag_to_note tool.

Also: todo/stores/tags.svelte.ts created (taskLabelOps wrapper around
the existing taskLabels junction for the scope filter).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:06:11 +02:00
Till JS
ed01d24f2d feat(ai): add AI tools for myday, goals, mood, finance, and times
Expand agent tool coverage from 28 to 47 tools across 16 modules:

- myday: get_myday_summary (full daily context in one call)
- goals: list_goals, get_goal_progress, create_goal, pause/resume/complete_goal
- mood: log_mood, get_mood_today, get_mood_insights (trends + correlations)
- finance: extend add_transaction, add get_month_summary + list_transactions
- times: extend start/stop_timer, add get_timer_status, get_time_stats, list_projects

All tools registered in both AI_TOOL_CATALOG (shared-ai) and webapp init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:01:12 +02:00
Till JS
acd7e0d6b0 docs: update architecture comparison — 5/10 roadmap items done
Update report to reflect all completed work:
- Matrix: streaming , tool registration updated to 29 tools + MCP
- §5.2 Streaming: marked done
- §5.3 Tool System: marked done
- §6 Table: items 1-3 + 5 struck through with commit refs
- §8 Fazit: updated gaps and recommendations

5 of 10 roadmap items complete in one session:
1. SSE Streaming, 2. Dynamic Tool Registry, 3. Budget Enforcement,
5. MCP Server Export (27/29 tools with DB ops), plus Tool Drift Fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:00:09 +02:00
Till JS
ce57e11950 feat(mana-ai): server-side token budget enforcement per agent
Implement rolling 24h token budget enforcement in the mana-ai tick loop.
Agents with maxTokensPerDay set are now rate-limited server-side.

Changes:
- PlannerClient: extract usage.total_tokens from mana-llm response
- planOneMission: return {plan, tokensUsed} tuple
- tick loop: check getAgentTokenUsage24h() before planning; skip with
  'skipped-budget' decision if over limit
- tick loop: record token usage after successful plan via
  recordTokenUsage() INSERT into mana_ai.token_usage
- migrate.ts: new mana_ai.token_usage table with rolling window index
- metrics.ts: mana_ai_tokens_used_total counter (by agent_id)

Budget flow:
  Agent.maxTokensPerDay = 50000
  → tick checks: SELECT SUM(tokens_used) WHERE ts > now()-24h
  → if sum >= 50000: skip mission, emit skipped-budget metric
  → else: plan mission, INSERT token_usage row

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:41:31 +02:00
Till JS
e2d540a958 refactor(settings): rewrite GeneralSection inline + delete @mana/subscriptions
GeneralSection: replace the GlobalSettingsSection wrapper (which
rendered its own SettingsSection pill + SettingsCard, requiring
title="" to suppress the inner header) with inline settings rows.
Each setting is a label+control row with scoped CSS — no double-card,
no wrapper hack.

Delete packages/subscriptions/ — the package is dead after merging
its SubscriptionPage into the Credits & Abo workbench app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:33:35 +02:00