Merged from ramseur/dev into my work - #31
Open
xingh wants to merge 18 commits into
Open
Conversation
update change log
PR: v1.3.0 — Security, Avalonia 12, UI Polish Branch: development → main 18 commits | 2,222 tests passing | 0 build errors --- Security - Scriban 5.12.0 → 7.2.4 — clears 1 Critical + 8 High + 3 Moderate CVEs (GHSA-5wr9-m6jw-xx44 and 11 others) - Suppress SQLitePCLRaw.lib.e_sqlite3 NU1903 — no patched version exists yet (GHSA-2m69-gcr7-jv3q); suppressed globally, tracked for removal when 2.1.12+ ships - Fix OpenRouterPricingClient warmup — no longer attempts to fetch pricing at startup without an API key configured Dependency Updates - Avalonia 11.3.0 → 12.0.4 — major version upgrade; drop unused Markdown.Avalonia (replaced by SafeMarkdownPresenter); fix all Avalonia 12 API breaks (GotFocusEventArgs, IClipboard.SetTextAsync, TextBox.Watermark) - Bulk NuGet updates — Microsoft.Extensions.* → 10.0.9, Markdig → 1.3.2, ModelContextProtocol → 1.4.0, CommunityToolkit.Mvvm → 8.4.2, Spectre.Console → 0.57.0, xunit/coverlet/test SDK updates Bug Fixes - Command Center privacy — private records with empty owner_user_id (legacy migrated rows) were bypassing the mask; now correctly shown as (private) on both web and desktop - Command Center startup — desktop was opening on Command Center with the Agents icon selected; now opens on User Dashboard with the correct nav state - Command Center audit view — all private records now mask as (private) for all viewers including the owner; Command Center is an admin audit view, not a personal view - ProcessAgent pipe race — cmd.exe processes that exit before reading stdin no longer throw IOException: pipe is being closed Web UI - Admin edit/revert for standard document templates — admins can now edit any DB-backed document template and revert to the built-in version - Admin edit buttons restored on Skills and User Document Templates pages - Knowledge sub-nav sorted alphabetically — Artifacts, Code Templates, Documents, Memory, Skills, Tools (web + desktop) - Monaco editor for prompt and JSON editing on web - Admin-gate agent create/edit/clone/delete on web Tests & Build - Migration count assertions updated (40 → 42) for V041/V042 migrations - All project NoWarn elements fixed to inherit $(NoWarn) from Directory.Build.props rather than overriding it
docs: add 1.3.0 changelog entry
Fixes and consolidations
- Constrain chat column to ~752px centered (messages, input, bottom bar, error banner, connections) - User messages redesigned as right-aligned bubbles (no avatar) - Assistant messages flat/clean (no heavy card box) - Input bar: integrated wrapper with focus ring, icon send/stop buttons - Token counter moved inline with bottom bar (no extra padding) - Hero state: larger logo, box-shadow, improved typography and suggestion cards - Sidebar: add New Chat button; date-group session list (Today / Yesterday / This week / Older)
…essaging, progress feedback (fixes ramseur#27)
feat: Claude/Codex-style chat UX refresh
…boarding Clarify first-run login onboarding and conditional auth messaging across Web/Desktop
…roperty name conflict
Finish emoji-to-Lucide migration; fix SovrantIcon property conflict
… 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>
…lopment
* fix: sync PostgresSchema.sql with V043 (drop username column)
- 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>
* Split PostgresSchema.sql into standalone Postgres and Supabase paths
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>
* Move PostgresSchema.sql to db/postgres/ for consistent db layout
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>
* Update persistence.md for V043, db/ layout, and admin schema customization
- 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>
* Remove PostgresSchema.sql from src/ (moved to db/postgres/ in prior commit)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add Phase 127: Supabase Row Level Security to roadmap
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>
* Make API key optional for Ollama and LM Studio on provider add form
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>
* Fix model list not loading when switching providers on Settings page
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>
* Fix model list not loading for Ollama on web and desktop
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>
* Pre-select personal workspace when adding a provider (web and desktop)
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>
* docs(roadmap): audit pass — mark Phase 123 done, update migration count 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>
* docs(roadmap): add v1.3/v1.4 focus table rows; fix test count to 2,208
- 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>
* docs(roadmap): add Phase 128; mark Phase 114/74/128 as v1.5 focus
- 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>
* docs(roadmap): add Phase 126 to v1.5 focus wave
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(knowledge): Phase 114 — enrich all 32 built-in skill descriptions (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>
* docs(roadmap): add Phase 129 — Missions → Workflows rename + UX review
- 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>
* feat(phase-128): Code generation quality gates — Parts A–D
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>
* feat(phase-128e): CodeValidateTool — structural quality gates for code 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>
* docs(roadmap): mark Phase 128 done, add Phase 129 dual-path idea, flesh 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
* fix(web): route provider setup deep-link to /admin/providers, hide for 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
* refactor(artifacts): projects-only storage layout, add workspace membership 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
* feat(phase-126): chat conversation UX — collapsed work strips, answer-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
* chore(version): bump to 1.5.0
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
* docs(roadmap): add Phase 131 — skill import from git repo/URL
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
* docs(roadmap): add Phase 132 — durable streams for agent-to-agent communication
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
* fix(routing): honor provider pin over cost fallback, cap tool count at 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
* docs(changelog): add v1.5.0 entry; test(storage): fix stale schema version 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
* feat(nav): modernize left-nav on Web and Desktop
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
* docs(design): add docs/design as the cross-platform design record
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
* docs(design): v2 brand row — one product name per platform
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
* docs(design): make v2 previews complete — full shell, all groups
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
* feat(nav): match Web nav row height to Desktop; docs(design): Login v3
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
* docs(design): consolidate to two pages — 21 screens, 5 patterns
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
* feat(nav): confine brand mark to tab/titlebar; float collapse toggle 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.
* docs(design): fix stale references to the deleted rail brand row
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.
* feat(chat): stop reusing the brand mark, replace suggestion emoji with 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.
* feat(overview): remove emoji from Dashboard and Command Center
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.
* feat(browse): remove emoji across the Browse pattern
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).
* feat(settings): remove emoji from Orchestration run-mode badges
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.
* fix(design): close out deferred lock converter and LoginWindow bugs
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.
* feat(design): give Web a real favicon, close out the placeholder-mark 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.
* docs(design): make clear this record tracks real shipped code, not just 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.
* docs(design): complete the visual pass, resolve the two long-open items
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.
* docs(design): fix Orchestration's mis-tagged pattern, correct the screen 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.
* fix(orchestration): replace the gear emoji with a real icon, both platforms
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.
* Swap Orchestration's Swarm-defaults gear button for a Team/Defaults toggle
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.
* Drop Lucide icon migration in favor of upstream's inline SVG / Avalonia 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>
---------
Co-authored-by: Eric Ramseur <ramseur@anant.us>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Rahul Singh <rahul.xavier.singh@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Sidebar session grouping currently mixes DateTimeOffset timestamps with DateTime boundaries, which will not compile and needs correction before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates the login and onboarding experience across the Web (Blazor) and Desktop (Avalonia) apps to better support first-run setup (create the initial administrator), clarify registration/approval flows, and refresh navigation UX/documentation.
Changes:
- Web/Desktop login now detects first-run and adapts UI/actions (create admin account vs sign-in), with clearer approval-required messaging and busy labels.
- Web sidebar adds a + New Chat action and groups recent sessions by date buckets (Today/Yesterday/This Week/Older).
- Adds a screenshot-based
docs/userflow.mdwalkthrough of the Web app user journey.
File summaries
| File | Description |
|---|---|
| src/Sovrant.Web/Components/Pages/Login.razor | Adds first-run setup UX, info messaging, and busy/status labeling to the web login flow. |
| src/Sovrant.Web/Components/Layout/Sidebar.razor | Adds “New Chat” and groups recent sessions by date buckets. |
| src/Sovrant.Desktop/Views/LoginWindow.axaml | Mirrors first-run/login/registration/approval UX updates in the desktop login window. |
| src/Sovrant.Desktop/ViewModels/LoginViewModel.cs | Adds state + labels to support the updated desktop login UX (first run, approval, busy label, info message). |
| docs/userflow.md | New documentation with screenshots describing the web app’s end-to-end user flow. |
Review details
- Files reviewed: 5/32 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+238
to
+242
| var now = DateTimeOffset.Now; | ||
| var todayStart = now.Date; | ||
| var yesterdayStart = todayStart.AddDays(-1); | ||
| var weekStart = todayStart.AddDays(-7); | ||
|
|
Comment on lines
+18
to
+23
| <div class="login-sub" style="margin-bottom:8px">Welcome! Let's set up your server.</div> | ||
| <div class="login-info"> | ||
| <strong>First-time setup</strong> — no accounts exist yet. The first account you create | ||
| becomes the <strong>administrator</strong>, with full control over registration, | ||
| approvals, and server settings. | ||
| </div> |
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.
No description provided.