From 57c2bdb2ad2749e41ac2481a482cb2206afeef83 Mon Sep 17 00:00:00 2001
From: Till JS
Date: Thu, 16 Apr 2026 15:29:07 +0200
Subject: [PATCH] feat(workbench): scope TagSelector in SceneHeader + agent
auto-infer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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)
---
.../workbench/scenes/SceneHeader.svelte | 54 +++++++++++++++++++
.../src/lib/stores/workbench-scenes.svelte.ts | 23 +++++++-
2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte
index 1b9120ae3..fb49dcd86 100644
--- a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte
+++ b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte
@@ -12,12 +12,40 @@
import { workbenchScenesStore } from '$lib/stores/workbench-scenes.svelte';
import { Sparkle } from '@mana/shared-icons';
import { goto } from '$app/navigation';
+ import { TagSelector, type Tag } from '@mana/shared-ui';
+ import { useAllTags } from '@mana/shared-stores';
+ import { useAgents } from '$lib/data/ai/agents/queries';
interface Props {
scene: WorkbenchScene | null;
}
const { scene }: Props = $props();
+ const allTags = $derived(useAllTags());
+ const agents = $derived(useAgents());
+
+ // Auto-infer scopeTagIds from bound agent if scene has no explicit override
+ const effectiveScopeTagIds = $derived.by(() => {
+ if (!scene) return [];
+ if (scene.scopeTagIds?.length) return scene.scopeTagIds;
+ if (scene.viewingAsAgentId) {
+ const agent = agents.value.find((a) => a.id === scene.viewingAsAgentId);
+ return agent?.scopeTagIds ?? [];
+ }
+ return [];
+ });
+
+ const selectedScopeTags = $derived(
+ allTags.value.filter((t) => effectiveScopeTagIds.includes(t.id))
+ );
+
+ async function handleScopeChange(tags: Tag[]) {
+ if (!scene) return;
+ const ids = tags.map((t) => t.id);
+ await workbenchScenesStore.updateScene(scene.id, {
+ scopeTagIds: ids.length > 0 ? ids : undefined,
+ });
+ }
// The seeded default scene is called "Home". Its empty-description
// placeholder gets a welcoming line instead of the generic prompt.
@@ -131,6 +159,20 @@
onblur={(e) => commitDescription(e.currentTarget, scene.description ?? '')}
>
+
+
+ 0 ? '' : 'Bereiche filtern…'}
+ addTagLabel="Bereich hinzufügen"
+ />
+ {#if !scene.scopeTagIds?.length && scene.viewingAsAgentId && effectiveScopeTagIds.length > 0}
+ via Agent
+ {/if}
+
+