Sync fork with ramseur/sovrant development; drop Lucide in favor of upstream icon conventions - #7
Merged
Conversation
- Remove username TEXT NOT NULL and users_username_unique constraint
from the users table definition (matches V043 SQLite table recreation)
- Update handle_auth_user_created trigger to not INSERT username
- Add idempotent ALTER TABLE users DROP COLUMN IF EXISTS username block
for existing Postgres/Supabase deployments upgrading from pre-V043
- Bump mirror version comment V001–V042 → V001–V043
Note: the user_id PK rewrite (usr_{hex} → email) from V043 does not
apply to Postgres/Supabase — user_id there has always been the GoTrue
UUID. Only the username column drop is reflected here.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PostgresSchema.sql is now standalone Postgres only — Supabase-specific trigger functions, RLS stubs, and GoTrue notes removed. db/supabase/migrations/20260625000000_initial_schema.sql is the new Supabase path: full schema + GoTrue mirror triggers + commented RLS policies. Run migrations from db/supabase/ with the Supabase CLI. Both files updated to schema version 43 (V043 username drop reflected). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All database files now live under db/: db/postgres/PostgresSchema.sql — standalone Postgres (embedded resource) db/supabase/migrations/... — Supabase CLI migrations Sovrant.Runtime.csproj updated to embed from new path (LogicalName preserved so PostgresSchemaInitializer lookup is unchanged). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ation - Schema version V042 → V043 throughout - All PostgresSchema.sql path references → db/postgres/ and db/supabase/migrations/ - File layout section replaced with db/ directory structure explanation - Admin customization workflow added to Supabase setup guide - Standalone Postgres setup guide no longer warns about Supabase section - Trigger pseudocode: removed stale username from INSERT - Pending implementation table updated to reflect db/ split as done Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ommit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Activates the commented-out RLS policy skeletons via a second Supabase migration (20260625000001_enable_rls.sql). Service-role key retains full unrestricted access; JWT-authenticated direct-DB callers are scoped to their own data at the DB layer, closing the dashboard/Edge Function gap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both providers run locally with no authentication. Placing a dummy key was required before; now the validation guard is skipped for local providers and an empty string is stored in the credential (the runtime OllamaProvider already uses string.Empty for auth). Web: label shows (optional) and placeholder changes when Ollama/LM Studio is selected. Desktop: ApiKeyLabel/ApiKeyWatermark computed properties bound in SettingsView.axaml; SelectedProvider change notifies both via NotifyPropertyChangedFor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OnSelectedProviderChanged clears ApiKey before LoadModelsForProviderAsync fires, so OpenRouter and other key-gated providers always fetched with an empty key and returned nothing. Fix: resolve an effectiveKey — form field when populated, otherwise the saved credential from the matching SavedProfiles entry. Ollama and LM Studio are unaffected (they use local HTTP with no auth). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FetchModelIdsAsync and FetchAuthenticatedModelIdsAsync unconditionally set
Authorization: Bearer {key}, producing a malformed header when the key is
empty. Ollama rejects this and returns no models.
Only set the Authorization header when the sanitized key is non-empty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Personal workspace is now checked by default; all other workspaces are opt-in. Matches user expectation that adding a provider makes it available to yourself immediately without any extra clicks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nt to V043 - Header: bump Last updated to 2026-06-29; add Phase 123, V040-V043, schema split (db/postgres + db/supabase/migrations) notes - Current State: 39 versioned migrations → 43 (V001–V043); add V040–V043 descriptions (stable MCP IDs, workspace memory privacy, memory owner scoping, email-as-user-id) - Current Focus table: add v1.3 wave rows for Phase 105 (MCP workspace gating) and Phase 123 (Memory System), both ✅ - Still pending Last audited: 2026-05-26 → 2026-06-29; list newly shipped phases (96, 105-partial, 123, V043, 40C schema split) - Phase 91 Knowledge Authoring: Deferred → Partial ✅ (Guidelines/Documents done; Skills Duplicate button + AvaloniaEdit Desktop fixes remain) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Current Focus: add v1.3 row for Phase 91 partial (admin Knowledge editing, Monaco editor, Avalonia 11→12 migration) - Current Focus: add v1.4 rows for V043 email-as-user-id breaking change and Ollama routing + project FK bug fixes - Current State: 2,222 tests → 2,208 (reflects current suite across 10 projects) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Current Focus table: add v1.5 wave rows for Phase 114 (skill enrichment), Phase 74 (markdown document templates), Phase 128 (code generation quality gates) — ordered by effort/impact - Last Updated header: note Phase 128 planned and v1.5 focus - Still pending table: add Phase 128 row - Phase 128 full section: ICodeValidator per-language, self-correction loop (max 2 rounds), guideline conformance check, V044 production scaffold enrichment (CI, .gitignore, Dockerfile, security scan, README, editorconfig) for all 21 templates; designed to work with any code-capable LLM Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s (V044) V044 migration updates every BuiltIn skill row (workspace_id='') with: - 2-3 sentence descriptions covering what/when/output for the IKnowledgeRouter harness and Skills page visibility - Agent list wiring for 9 skills that had natural delegations but NULL agents: billing-ops → data-analyst, content-engine/crosspost → content-writer, doc-update → doc-updater, lead-intelligence → sales-intelligence+researcher, project-flow → project-manager, prompt-optimize → prompt-optimizer, refactor → refactor-cleaner, search-first → researcher - verification-loop tools corrected: removes non-existent `Verify` tool Test assertions updated: schema version 43 → 44, migration count 43 → 44. Roadmap: Phase 114 marked Done, migration count 43 → 44, v1.5 row updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Phase 129 full section: surface-label rename only (no DB/runtime changes), dedicated Workflows page (goal-first launch form, active/recent cards, journal + artifacts detail view), positioning callout distinguishing AI-driven workflows from trigger-automation (n8n/Zapier/Make via MCP), /v1/workflows API alias proxying to /v1/missions, Phase 119 run-modes in the launch form; explicit non-goals table (no node editor, no cron, no connector library) - Still pending table: Phase 129 row added - v1.5 focus table: Phase 129 row added after Phase 126 - Last Updated header: note Phase 129 and v1.5 focus update Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A — Artifact security hardening - ArtifactRoutes.cs: zip download endpoint with correct content-disposition - ArtifactRoutes.cs: #pragma disable CA1849 around ZipArchiveEntry.Open() (no async overload) - Program.cs: X-Content-Type-Options / Cache-Control headers on artifact serve; force-download for unsafe-inline file types (html, js, svg, etc.) - Artifacts.razor: remove LocalArtifactStore cast; use IArtifactStore.ListAsync + IWorkspaceService.ListAllAsync; ReadAsync for preview; ArtifactItem gains WorkspaceId/WorkspaceName, drops FullDiskPath; .sln/.editorconfig added to TextExtensions - RemoteArtifactStore: field-name fix (stub SetCodeMetadataAsync added) B — Code manifest in ArtifactManifest - ArtifactManifest: new CodeManifest nested type (template_id, language, kind, build/run/test commands, entry_point); ArtifactManifest.Code property - IArtifactStore: SetCodeMetadataAsync(handle, metadata, ct) - LocalArtifactStore: async SetCodeMetadataAsync reads/merges _manifest.json - ScaffoldCommands.cs: new static helper deriving build/run/test/entry-point per language+kind for all 21 scaffold types (#pragma CA1308 — ASCII IDs) - CodeCreateTool/CodeCreateMultiTool: call SetCodeMetadataAsync after scaffold C — Scaffold enrichment (all 21 templates) - All 5 .NET scaffolds: .sln (SDK-style GUIDs), Directory.Build.props, .editorconfig, .github/workflows/ci.yml (dotnet build + test) - All 16 non-.NET scaffolds: .github/workflows/ci.yml per language (node/go/python/rust/java/kotlin/ruby/swift/lua/zig/cpp) D — LLM instruction enrichment - IProjectTemplate: optional default interface members BuildCommand, RunCommand, TestCommand, EntryPoint (null = ScaffoldCommands default; no existing impl changes) - CodeCreateTool: build_command/run_command/test_command/next_steps in response; BuildCodeManifest prefers template overrides over ScaffoldCommands defaults; ToolDefinition.Description updated - CodeCreateMultiTool: per-component commands + next_steps in response; ToolDefinition.Description updated - V045: seed knowledge_pages kind=''tools'' BuiltIn rows for CodeCreate and CodeCreateMulti with usage guide bodies - MigrationRunnerTests/OldDbUpgradeTests: bump schema version assertions to 45 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e scaffolds New CodeValidateTool (IArtifactStore-backed, no compiler required): - Reads run manifest (_manifest.json) to discover language, kind, build commands - Lists all files in the artifact run via IArtifactStore.ListAsync - Applies language-specific critical gates: .sln/.slnx for dotnet, package.json for node, go.mod for Go, Cargo.toml for Rust, pom.xml for Java, Package.swift for Swift, Gemfile for Ruby, build.zig for Zig, CMakeLists.txt for C++, *.rockspec for Lua, build.gradle.kts for Kotlin, pyproject.toml/setup.py for Python - Applies universal warning gates: README.md, .gitignore, .github/workflows/ci.yml - Returns pass/fail per gate with severity and remediation steps - Tool guide seeded via V046 migration (knowledge_pages kind=''tools'' BuiltIn) - Registered in ServiceCollectionExtensions alongside CodeCreate/CodeCreateMulti Tests (32 cases, 437 total passing): - All 21 scaffold templates pass CodeValidateTool via theory test - Targeted gate tests: dotnet sln/.slnx, node package.json, Go commands - Error cases: missing run_id, empty run, no code manifest - Remediation: critical gate failures include [CRITICAL] prefix - MigrationRunnerTests/OldDbUpgradeTests bumped to schema version 46 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sh out Phase 126 color/contrast section - Phase 128 (code generation quality gates): mark done everywhere (Current Focus, gap table, detail section status line), bump migration count to V001-V046 (V045/V046 seed tool guides) - Phase 129 (Missions -> Workflows): add dual-path execution idea - route through Claude Agent SDK dynamic workflow orchestration when a qualifying Claude tier is active, else fall back to Sovrant's own mission engine as the base version; model/tier gate left as an open design question - Phase 126 (chat conversation UX): add a dedicated color & contrast subsection grounded in the existing sovrant.css / Sovrant*Colors.axaml tokens - flags that status colors (pass/warn/fail) aren't actually re-themed between dark and light today, and sets a rule (icon+fill only, no colored text) until that's verified
…r non-admins
TopContextBar's "Set up →" for an unconfigured provider pointed at
/settings?tab=providers, a URL Settings.razor silently ignores (no such
tab exists) — the link was a dead end for every user, admin or not.
Point it at the real page (/admin/providers?provider=X) and have that
page read the query param to preselect the provider, matching Desktop's
existing Settings:Providers:{name} deep link. Since /admin/providers is
gated to system admins and non-admins have no path to act on an
unconfigured provider, the "Set up" prompt list is now admin-only —
non-admins only ever see providers already enabled for their workspace.
Also adds the Phase 130 roadmap item: OpenRouter account registration
and in-app key issuance via OAuth PKCE.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMGtGTeAbrmu7gaF3v1Y6e
…ership auth to artifact routes
Removes workspace-level (project-less) artifact storage. Every artifact
now nests under {ws}/projects/{proj}/artifacts/{run}; DefaultProjectId
is a real project folder like any other, not a routing bypass.
ArtifactScope.IsWorkspaceLevel is gone along with every branch that
consumed it (LocalArtifactStore, ArtifactLayoutMigrator, tests).
Also corrects the on-disk root default from ~/.sovrant/artifacts to
~/.sovrant/workspaces, matching the "workspace-first layout" the
existing docstrings already claimed but the path constant didn't.
Security fix: the two artifact-serving HTTP routes in Program.cs had
no authorization check — any authenticated user could fetch any
workspace's artifacts by guessing the URL. Both now 403 non-members
(admins and workspace members pass), matching
WorkspaceAuthGuards.RequireWorkspaceAccessAsync's existing rule for
the /v1/artifacts API. Artifacts.razor's listing page is scoped the
same way instead of calling ListAllAsync() for every viewer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMGtGTeAbrmu7gaF3v1Y6e
…-first layout Replaces the per-tool-call box stack with a single collapsible work strip per turn, on both Web and Desktop: - Collapsed by default: "N actions · Read x3 · Grep x2 · 2.4s" - Two-level expand: strip header -> one row per tool -> full detail for one tool at a time (expanding a second row collapses the first) - Live "doing X" indicator while tools are executing, synchronized with the tool-use row so there's no gap between the animated state and the strip appearing - Answer-first: completed turn renders the answer above the (now subordinate) work strip, with a thin separator between them - Error/warning state: header shows a ⚠ + count, expanded rows highlight red via the status dot, not colored text - Pending tool confirmations stay outside the strip and always visible — no change to the Allow once / Allow for turn / Deny flow Web: new WorkStrip.razor component, wired into ChatMessage.razor. Desktop: MessageViewModel gains work-strip state (IsWorkStripExpanded, ActiveDetailToolId, computed labels), ChatView.axaml replaces the old execution-status bar and per-tool ItemsControl with the strip markup. Color/contrast pass: sovrant.css now defines --status-pass/warn/fail in the light theme block instead of silently inheriting the dark values. Also removes a colored-text rule (.work-strip-row-error .work-strip-row-name) that colored the tool name red on error — measured ~3.7:1 against the light tool-use background, short of the 4.5:1 text threshold the phase's own color rule sets; the status dot fill + header icon already carry the error signal, matching what Desktop's XAML already did. Verified: solution builds clean, no references to removed pre-strip members (ToolUseViewModel.IsExpanded/ResultMaxLines/etc.). Smoke- tested the Web server boot + chat page load + fixed CSS being served; full interactive browser/Desktop verification pending UAT (roadmap updated to reflect Phase 126 as implemented, pending UAT sign-off). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DMGtGTeAbrmu7gaF3v1Y6e
Directory.Build.props and sdk/js/package.json to 1.5.0, marking the v1.5 wave (Phase 114, 74, 128 shipped; 126 pending UAT; 129 next). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012BsqbdrqG3rVhP77TnpWEL
Adds a backlog table row and full detail section for a planned feature letting admins import skill .md files from a git repo (optional subpath/ref) or raw URL, with schema validation, preview, slug-collision handling, and copy-on-write import into knowledge_pages. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012BsqbdrqG3rVhP77TnpWEL
…munication Extends Phase 57's coordination_events mailbox with sequence-numbered per-channel streams, durable per-consumer offsets, multi-subscriber fan-out, optional SignalR live push, and bounded retry/dead-lettering, so cross-group coordination survives crashes/restarts and network drops (missions, claw-to-claw federation). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012BsqbdrqG3rVhP77TnpWEL
…t 128 SmartRouter abandoned an explicit provider pin the moment it went unhealthy (e.g. an expired API key producing repeated 401s), falling back to cost-scored auto-selection across all registered providers. Ollama is always registered at cost 0.0 regardless of whether it's configured, so it silently won every fallback and every retry hit an unreachable localhost:11434. An explicit pin now always wins so the provider's real error surfaces instead. Separately, ModelCapabilities.MaxTools is designed to cap the tool list per model but is never populated anywhere, so the existing guard in FilterToolsForModel never fired and the full tool registry (built-in tools + enabled MCP servers) was sent unbounded. OpenAI's Chat Completions API and every OpenAI-compatible provider behind it hard- rejects requests over 128 tools with a 400. Added a 128-tool fallback cap used whenever no per-model override is set. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
…rsion assertion CHANGELOG.md's v1.5.0 entry documents everything since v1.4.0's tag — Phase 128/128e code generation quality gates, Phase 126 chat UX, Phase 114 skill enrichment, the artifact-routes auth fix, provider setup fixes, and this session's SmartRouter pin + tool-count fixes. SqliteStorageProviderTests.InitializeAsync_SetsSchemaVersion still asserted schema version 44 (from V044); three migrations have landed since (V044-V046) and MigrationRunnerTests/OldDbUpgradeTests were already bumped to 46 in f93339e — this test was the one straggler. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
Replaces the emoji-icon left navigation with a unified, collapsible
rail on both Sovrant Web and Sovrant Desktop: real line icons, a
left accent-bar for the active item, and Admin's 9 destinations
grouped under Overview/Access/Safety/System instead of a flat list.
Both apps already had working collapse/expand + group-switching
state machines — this is a restyle of existing navigation, not new
architecture, so the same six destinations and panel-swap mechanic
are unchanged.
Web (Blazor):
- RailNav.razor: inline SVG stroke icons + labels, replacing
emoji-only icon buttons
- NavButton.razor: icon now optional so sub-nav items can go
label-only
- AdminPanel.razor: OVERVIEW/ACCESS/SAFETY/SYSTEM group headers
- sovrant.css: enlarged rail width/type-scale, left accent-bar
active state, and flex-shrink:0 on every fixed-height row class
in a scrolling flex column — without it, a long list (Admin's 9
items) collapses every row to 0px height under overflow:hidden
once the flex container runs out of space, a bug caught and fixed
in the design-mockup stage before it reached real code
Desktop (Avalonia):
- MainWindow.axaml: single vertical group-nav list (icon+label
expanded, icon-only collapsed) replacing the old horizontal
icon-only row; left accent-bar for the active group
- New NavIcons.axaml: stroke-based StreamGeometry icons reusing
the same path data as Web's SVGs (Avalonia's geometry mini
language turned out to be SVG-compatible, arcs included)
- Each nav Button needs an explicit Height, not just a
stretch-filled parent Grid — otherwise FluentTheme's
:pointerover hover chrome renders shorter than the button's
actual bounds while the bound active-state Background still
fills correctly
- AdminPanelView/KnowledgePanelView/AgentsPanelView/WorkspacePanelView:
same OVERVIEW/ACCESS/SAFETY/SYSTEM grouping as Web; every sub-nav
button needs VerticalContentAlignment="Center" or its text sits
pinned to the top of the row instead of centered
- BrandPrimarySoft theme token (dark + light) for the tinted active
background; BoolToBrushConverter/NavActiveBrushConverter gain
soft-tint + always-visible-text variants; new
BoolToAlignmentConverter for collapsed-vs-expanded content
alignment
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
New docs/design/ folder: a place to verify UI designs for Web, Desktop, and (soon) CLI before/after implementation, versioned as static HTML previews (v1.html, v2.html, ...) instead of live app screenshots that go stale. v1 for both Web and Desktop documents the left-nav redesign shipped in 7970ca3 — real line icons, single collapsible rail, Admin grouped under Overview/Access/Safety/System — including the bugs found and fixed along the way (CSS flex-shrink row collapse on Web, Avalonia's VerticalContentAlignment and Button-Height/hover quirks on Desktop) so the next screen's design doesn't repeat them. This is the foundation for a formal design pass across every remaining screen, starting with Login, keeping v1's type scale, spacing, icon style, and color tokens rather than introducing new ones per screen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
The product name rendered twice on both platforms: once in the chrome
the platform owns (OS titlebar on Desktop, browser tab on Web) and
again in the rail's brand row immediately below it. v2 removes the
rail wordmark on both and grows the mark 34px -> 44px (radius 9 -> 12,
brand row 60 -> 68) so it reads as a logo instead of a favicon.
Desktop keeps its native titlebar as-is — no ExtendClientArea, no
custom window controls, no drag-region handling. This is a one-row
change per platform.
Also fixes the Web record itself: v1 drew the Web app inside a rounded
window frame, which made it read like the Desktop app. Web previews
from v2 on sit in browser chrome, which matters here because where the
product name lives is the whole subject of this version.
Adds a Web<->Desktop parity table and a Parity section to the README —
the two frontends should match unless a platform gives a reason not to.
It currently records one real gap: Web's nav rows are 42px against
Desktop's 40px.
README also notes for the upcoming Login pass that Desktop's
LoginWindow binds {DynamicResource BackgroundBrush}, a key that exists
in neither SovrantDarkColors.axaml nor SovrantLightColors.axaml.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
The first v2 pass cropped the rail to four items to fit a side-by-side comparison, which dropped Projects and Admin entirely, showed no sub-panels, and ran too short to see anything below the fold. Restructured both files: the before/after comparison is now a tight crop of just the brand row (which is all v2 actually changes), and below it sits the complete interactive shell — all six groups, every sub-panel, Admin's nine destinations across its four group headers, the Chat search + recents panel, collapse toggle, and a 780px stage so nothing truncates. Web's shell also drives a live breadcrumb and URL in the omnibar as you navigate, since the address bar is part of what makes it read as Web rather than Desktop. Parity table grows to cover the Chat panel and footer identity — which surfaced a second real gap: Web's footer shows email + workspace where Desktop shows username + role. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
Parity: Web's .rail-icon was 42px against Desktop's 40px — the one real
gap the v2 parity table flagged. Web now matches at 40px.
The second gap that table listed (footer showing email + workspace on
Web, username + role on Desktop) was not real. Both platforms already
render LocalPart(email) plus workspace role; the mock had simply used
different sample data on each side. Corrected the mock rather than the
code, and every parity row now reads Matched.
Login v3 — first screen pass, both platforms. Login predates the
shell's design system and carried its own scale: 5px radii on Web, 3px
and stock Avalonia controls on Desktop, ~34px inputs, and a bare text
heading where the product now leads with a mark. v3 puts both on the
shell's scale — 56px mark leading, 40px inputs at 9px radius, 44px
brand-filled primary button — and designs the error, busy, and
registration-closed states explicitly instead of leaving them implied.
Busy moves onto the button (spinner + "Signing in…") from a detached
progress bar, focus gets a visible ring rather than a border-color
shift alone, and the password field gains a reveal toggle.
Two Desktop bugs found while designing and recorded for the
implementation pass: LoginWindow binds {DynamicResource
BackgroundBrush}, a key defined in neither theme file, so the window
silently never gets its themed background; and error text hardcodes
Foreground="Red" instead of the StatusFail token.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
Replaces the six per-version files with exactly two: web.html and desktop.html. Each holds every screen, picked from an index on the left. The consolidation that matters is the screens themselves. The 21 destinations behind the nav are not 21 designs — they are five patterns plus data: Browse 13 list + detail (Artifacts, Skills, Users, Providers, ...) Overview 2 stat tiles + activity table (Dashboard, Command Center) Settings 4 sectioned control rows (Settings, Governance, Trust, Diagnostics) Conversation 1 Chat Entry 1 Login Those pages share no layout classes in the codebase today — each was built standalone, which is precisely why they drift. Designing the pattern once and rendering each screen as pattern + data is what stops that, and makes a new screen cheap instead of a new snowflake. desktop.html is generated from web.html with only the platform chrome swapped: tab strip and address bar become a native titlebar and window controls. Diffing the two yields 47 changed lines, all chrome, title, or the theme storage key — so parity is checkable rather than asserted. Verified all 22 entries render on both files with no undefined output, and layout resolves correctly (5 stat columns, 340/506 split, no horizontal overflow, Login full-bleed with no rail). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N32ftYb4tgyXtr4Ca75jD1
…on rail edge The mark showed up everywhere (rail brand row, 54px on Login) which added nothing a user needed. It now lives only where platform chrome already names the app: the browser tab favicon on Web, the native titlebar icon on Desktop. The rail brand row (and its "Sovrant" wordmark) is gone entirely — the collapse/expand toggle floats on the rail's own border edge instead of owning a header row, so Dashboard is the first thing in the nav with no blank space above it. Applied identically to real code (MainLayout.razor/sovrant.css on Web, MainWindow.axaml on Desktop) and to docs/design/web.html + desktop.html, which stay in parity at 47 chrome-only diff lines.
The prior commit (5038190) removed .rail-brand-row entirely, but left a CSS comment claiming its height aligned with .top-context-bar (the class no longer exists, and there's no rail border near that height to align with anymore) and a README paragraph describing the brand row as still present ("an unlabeled bar holding the collapse toggle") when it's gone — the toggle now floats directly on the rail's border.
…h line icons The mark-placement rule (tab/titlebar only) was already being violated on the highest-traffic screen: Chat's empty-state hero and every assistant message avatar reused the brand-mark treatment (colored square + bold glyph — the mock literally used "S", real code used a raw ⚡ emoji). The six welcome-state suggestion tiles also used raw emoji, contradicting the "real icons, not emoji" standard from the earlier nav redesign. Fixed on both platforms: the hero icon and every assistant avatar now render the same chat-bubble line icon already used in the rail's own Chat nav item, in neutral (not brand-colored) styling. Suggestion tiles reuse the same icon set as the rail. Desktop gains 4 new NavIcons.axaml StreamGeometry resources (IconSwarm/IconMission/IconOrchestrate/ IconConnect), hand-converted from the same SVG path data Web uses and verified by screenshot. docs/design/web.html + desktop.html gain a Thread/Welcome toggle on the Chat screen so the mock can actually demonstrate both states the Conversation pattern claims to have (previously dead CSS). Parity holds at 47 chrome-only diff lines.
KindIcon() on both platforms prefixed every activity-row kind pill with one of five emoji (🎯👥🤖💬🔗) — the mock never had this (kind pills are always plain text there), so real code was out of step with the design record, not the other way around. Deleted KindIcon() everywhere (both Razor methods, both Desktop row-VM properties) — kind pills now show plain text only, matching web.html/desktop.html. Privacy lock/unlock (🔒/🔓/🔒) and the error-banner warning triangle (⚠) are real line icons now: inline SVG on Web, new IconLock/IconUnlock StreamGeometry resources in NavIcons.axaml on Desktop. Verified the lock shape by pixel-sampling the rendered Desktop window and by exercising the equivalent (same path logic) toggle live on Web, since the Desktop click didn't land precisely enough to re-verify interactively there. Left alone this pass: the shared BoolToLockIconConverter still returns emoji for AgentsView.axaml and one ChatView.axaml site — changing it would require updating those out-of-scope call sites too, tracked for the Browse-pattern pass.
Swept Artifacts, Documents, Memory, Agents, Projects, Users/Admin, Workspaces, System Integrations, and Platform Integrations (Skills, Tools, Code Templates, and Providers were already clean). Same root cause as the Chat and Overview passes: web.html never had these emoji, so real code was the one out of step with the design record. Fixed: warning-triangle error banners (10 files), a folder icon (Artifacts), a chat-bubble icon (Documents' "Chat to create", Agents' "Launch chat"), lock/unlock (Memory notes, Agents' own-run privacy toggle), a generic package icon replacing the PostgreSQL/Supabase mascot emoji, and a refresh icon replacing the OAuth "waiting" spinner. Every icon reuses path data already verified earlier this session — no new hand-drawn geometry. Left alone deliberately: the ✕ close/remove glyph (~6 sites) — a plain typographic symbol, not a pictorial emoji, same category as the existing → ▲▼ sort/link glyphs. Web verified live in Chrome including interactive states. Desktop builds clean with the same proven icon geometry, but this pass's Desktop screens weren't interactively re-verified live — see docs/design/README.md for why (SetForegroundWindow silently failed to focus the app from the automation context; stopped rather than risk clicks landing on the wrong window).
Last pattern in the sweep. Governance, Trust Boundary, Diagnostics, and Settings were already clean on both platforms; Orchestration's ModeIcon() returned C# unicode escapes (people/bolt/bee) for Sequential/Parallel/Swarm, plus one hardcoded bee on the "Swarm Defaults" badge. Desktop's run-mode picker is a plain-text ComboBox with no icons, so nothing to fix there. Replaced with three straight-line icons (horizontal lines for Sequential, vertical lines for Parallel, the reused package icon for Swarm) — no arcs, zero hand-drawing risk. ModeIcon() now returns SVG markup rendered via MarkupString, matching Chat's suggestion-tile pattern. Verified live in Chrome: list badge and detail-header badge both render correctly. Closes out the pattern-by-pattern sweep (Conversation → Overview → Browse → Settings). Remaining known items: the shared BoolToLockIconConverter deferred from the Chat pass, and the ✕ typographic glyphs left alone throughout — both tracked in docs/design/README.md.
BoolToLockIconConverter (Desktop) now returns the IconLock/IconUnlock StreamGeometry via Application.Current.TryGetResource (same pattern as BoolToBrushConverter/NavActiveBrushConverter) instead of emoji text. Updated all three call sites — AgentsView.axaml and ChatView.axaml's session-level privacy toggle — to bind Path.Data instead of TextBlock.Text. Chat.razor had two more emoji this sweep missed: the Web twin of the session privacy toggle (🔒/🔓) and the remember-form's "🔒 Private" checkbox label, plus the error-banner ⚠ explicitly deferred at the end of the original Chat pass. All fixed the same way as their Dashboard/Memory/Agents equivalents. LoginWindow.axaml: Background bound to a DynamicResource key (BackgroundBrush) that exists in neither theme file, so the window never got its themed background — now SurfaceBackground. Error text Foreground was hardcoded Red instead of the StatusFail token — now themed.
… decision Web never had a favicon at all — no file, no <link> tag. Rather than draw new mark artwork, reused the app's existing lightning-bolt icon (already Sovrant.Desktop/Assets/icon.png) as favicon.ico, so both platforms now share the same real mark instead of Web having nothing and Desktop having an asset nobody looked at closely. Went through an SVG favicon first, then corrected to a proper multi-resolution .ico (16-256px) since that's the actual standard browsers request by default, not just what modern ones happen to support. docs/design/web.html + desktop.html's .fav/.tico swatches now show the bolt shape instead of the placeholder "S", closing the open decision tracked in the README since the original nav redesign.
…st mocks Added an explicit scope note and a commit-by-commit table of every production file touched since the two-file mock consolidation (8 commits, 33 files across both platforms). The dated sections already described real code changes, but nothing said so up front — someone skimming could reasonably assume this folder only tracked web.html/ desktop.html iteration.
Screen-by-screen check across all 5 patterns in the browser (Login, Dashboard, Chat, Artifacts, Users, Orchestration, Diagnostics) — no design roughness found; the pattern-once approach holds across every screen checked. Design-only, no src/ changes. Resolved both items tracked since the original review: - Login theme on a fresh machine: App.razor hardcoding data-theme="dark" preempts prefers-color-scheme; the mock already does this correctly by leaving data-theme unset until the viewer picks. Decision: match the mock. Not implemented — this is the design record, not the fix. - Control-height scale: audited every real height in use, found it clusters into three real tiers (28-32 / 34-36 / 40-44px) rather than being random. Documented as the standard going forward instead of forcing a mass CSS rewrite with no way to re-verify it visually.
…een count Caught by inspection: Orchestration was rendering as a bare Settings screen (two sections) with no team list, no Run panel, no Members. The real Orchestration.razor is Browse-shaped — a searchable team list + detail pane — just with a richer detail (Run, Run Profile, Members instead of one key/value block), which is what made it read as Settings. Also surfaced a second, unrelated bug while fixing this: the screen was never counted in the "21 screens" total despite being its own nav destination the whole time. Actual count is 22. Design-only, no src/ changes: - S.orchestration reclassified Browse, given a real team + a dedicated three-section detail renderer (orchTeamDetailHTML) - Swarm Defaults wired up as a Team/Defaults toggle — a real second view of the same screen, not a separate destination — reusing and generalizing the chatToggle mechanism (renamed screenToggle) rather than building a parallel one - Two new line icons (three horizontal/vertical lines) for the Sequential/Parallel run-mode badge, matching what already shipped in real Orchestration.razor during the emoji-cleanup pass - Pattern table, intro count, and parity line-count all corrected (Browse 13->14, Settings stays 4, total 21->22, parity 47->49) Verified live in Chrome on both platforms: team list, all three detail sections, and the Team/Defaults toggle all render correctly. Parity diff re-confirmed line-by-line at 49 chrome-only lines — caught and fixed one accidental wording drift between the two files in the process. Found but explicitly not fixed (design-only pass): real Orchestration.razor line 16 has one more emoji (⚙) the earlier Settings-pattern sweep missed, since it never actually reviewed this screen's real code closely.
…tforms Orchestration.razor:16 had a gear emoji (⚙) on the "Swarm defaults" button, missed by the earlier Settings-pattern sweep since that pass never actually opened this file closely (it was mis-tagged Settings and reviewed only at the data level). Found the exact same bug on Desktop while checking — OrchestrationView.axaml:15, same entity, same missed-by-the-same-sweep reason. Both now use the package/box icon already established for "Swarm Defaults" elsewhere (Chat suggestions, System Integrations, the mock). Web inlines the SVG directly; Desktop reuses the existing IconSwarm StreamGeometry. Kept the existing button/command wiring unchanged — still opens the same Swarm Defaults panel. Verified live in Chrome: icon renders correctly, button still opens the panel.
…oggle Matches the approved mock: the header now shows explicit Team/Defaults buttons (active tab filled, inactive outlined) instead of a single gear icon, on both Web and Desktop. Desktop's BoolToTabBrushConverter also had a latent bug fixed along the way — it looked up brush resources via app.Styles.TryGetResource, which can't see resources declared in Application.Resources (where BrandPrimary/TextPrimary live), so both buttons silently rendered transparent.
… favor of upstream design pass Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ia icon resources Reverts the fork's emoji-to-Lucide migration (PR #3) now that upstream/development ships its own icon system. Removes SovrantIcon (Web + Desktop), Blazicons.Lucide and Lucide.Avalonia package refs, and restores CatalogEntry.Icon. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings
ramseur/sovrantdevelopment(46 commits) into the fork and aligns the fork with upstream's UI conventions.upstream/development→main. 37 files conflicted; all were emoji→icon hunks where both sides removed emoji independently. Upstream's side was taken everywhere.Path/Icon*resources on Desktop) and does not use Lucide. RemovedSovrantIcon(Web + Desktop),Blazicons.Lucide/Lucide.Avaloniapackage refs,_Importsentry, and restoredCatalogEntry.Icon.Net diff vs
upstream/developmentis now only the fork's non-icon work: login onboarding (Login.razor,LoginWindow.axaml,LoginViewModel),Sidebar.razorUX refresh,docs/userflow.md+docs/images/web-flow-*.png.Verification:
dotnet build Sovrant.slnxsucceeds;dotnet test2230 pass / 9 fail — the 9 are Windows-path /cmd.exe-dependent tests (PathToUri_Converts_Windows_Path,ProcessAgentTests,ModelOverrideLoaderTests,GetAccessUrl_ReturnsFileUri,CodeGraderTests.Command_With_OutputFile_Substitution) unrelated to this change (run on Linux).Link to Devin session: https://app.devin.ai/sessions/d1b1be50c04f4787bcc00befb37bf805
Open in Devin Desktop: https://app.devin.ai/desktop/session/d1b1be50c04f4787bcc00befb37bf805?variant=devin
Requested by: @xingh