Skip to content

feat(ux): complete UX overhaul — design system, onboarding, web polish#1277

Draft
ilblackdragon wants to merge 42 commits intostagingfrom
ux-overhaul
Draft

feat(ux): complete UX overhaul — design system, onboarding, web polish#1277
ilblackdragon wants to merge 42 commits intostagingfrom
ux-overhaul

Conversation

@ilblackdragon
Copy link
Member

Summary

Comprehensive UX overhaul unifying CLI and web design language. Makes every surface feel like the same product — polished, calm, and intentional.

  • Design system: Unified emerald green accent across CLI/web, typography scale, spacing tokens, motion system with reduced-motion support
  • Boot screen: Progressive disclosure — 3 lines instead of 10, hint to ironclaw status
  • Onboarding: Auto-detect API keys, skip interactive steps, modern branding, dot stepper, smart provider ordering, --step flag for selective re-onboarding
  • Web chat: Welcome card with suggestion chips, syntax highlighting, user messages as right-aligned chat bubbles, streaming polish, connection indicator, skeleton loading
  • Doctor/REPL: Grouped diagnostics (Core/Features/External), redesigned /help with quick start section
  • Accessibility: aria-live, aria-label, focus-visible, touch targets, mobile optimization, prefers-contrast: more
  • i18n: All new strings added to en.js and zh-CN.js

Test plan

  • cargo fmt --check — clean
  • cargo clippy --all --all-features — zero warnings
  • cargo test — 3141+ tests pass
  • Snapshot tests pass (CLI help output)
  • JS syntax validation — all files pass node --check
  • Visual check: boot screen (ironclaw)
  • Visual check: onboarding (ironclaw onboard --quick)
  • Visual check: doctor (ironclaw doctor)
  • Visual check: web gateway — welcome card, messages, code blocks, approval cards
  • Visual check: NO_COLOR=1 ironclaw produces clean uncolored output
  • Visual check: prefers-reduced-motion: reduce in DevTools
  • Visual check: 375px viewport width

🤖 Generated with Claude Code

jayzalowitz and others added 30 commits March 10, 2026 12:22
Port the complete psychographic profiling system from NPA into IronClaw,
including enriched profile schema, conversational onboarding, profile
evolution, and three-tier prompt augmentation.

Personal onboarding moved from wizard Step 9 to first assistant
interaction per maintainer feedback — the First Contact system prompt
block now instructs the LLM to conduct a natural onboarding conversation
that builds the psychographic profile via memory_write.

Changes:
- Enrich profile.rs with 5 new structs, 9-dimension analysis framework,
  custom deserializers for backward compatibility, and rendering methods
- Add conversational onboarding engine with one-step-removed questioning
  technique, personality framework, and confidence-scored profile generation
- Add profile evolution with confidence gating, analysis metadata tracking,
  and weekly update routine
- Replace thin interaction style injection with three-tier system gated on
  confidence > 0.6 and profile recency
- Replace wizard Step 9 with First Contact system prompt block that drives
  conversational onboarding during the user's first interaction
- Add autonomy progression to SOUL.md seed and personality framework to
  AGENTS.md seed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pace seeds

Remove the interactive onboarding_chat.rs engine in favor of a simpler
bootstrap flow: fresh workspaces get a proactive LLM greeting that
naturally profiles the user. Identity files are now seeded from
src/workspace/seeds/ instead of being hardcoded. Also removes the
identity-file write protection (seeds are now managed), adds routine
advisor integration, and includes an e2e trace for bootstrap greeting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nboarding-and-routine-advisor

# Conflicts:
#	tests/support/test_rig.rs
…prompt injection

Identity files (SOUL.md, AGENTS.md, USER.md, IDENTITY.md) are injected into
every system prompt. Rather than hard-blocking writes (which broke onboarding),
scan content through the existing Sanitizer and reject writes with High/Critical
severity injection patterns. Medium/Low warnings are logged but allowed.

Also clarifies AGENTS.md identity file roles (USER.md = user info, IDENTITY.md =
agent identity) and adds IDENTITY.md setup as an explicit bootstrap step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…wiring

The field is now actively used by the agent loop to suppress BOOTSTRAP.md
injection — remove the stale "not yet wired" TODO.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the user authenticates via NEAR AI Cloud API key (option 4),
api_key_login() stores the key via set_runtime_env(). But
build_nearai_model_fetch_config() was using std::env::var() which
doesn't check the runtime overlay — so model listing fell back to
session-token auth and re-triggered the interactive NEAR AI
authentication menu.

Switch to env_or_override() which checks both real env vars and the
runtime overlay.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
persist_assistant_response was called with channel="default",
user_id="system" but the assistant thread was created via
get_or_create_assistant_conversation("default", "gateway") which owns
the conversation as user_id="default", channel="gateway". The mismatch
caused ensure_writable_conversation to reject the write with:

  WARN Rejected write for unavailable thread id user=system channel=default

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Content-Security-Policy header (added in f48fe95) blocks inline JS
via script-src 'self'. All onclick/onchange attributes in index.html
are replaced with getElementById().addEventListener() calls. Dynamic
inline handlers in app.js (jobs, routines, memory breadcrumb, code
blocks, TEE report) are replaced with data-action attributes and a
single delegated click handler on document.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…chema field

- Bootstrap IncomingMessage now uses ("default", "gateway") consistently
  with persist and session registration calls
- Update bootstrap_greeting.json fixture: schema_version → version to
  match current PROFILE_JSON_SCHEMA

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… profile sync

- BOOTSTRAP.md: fix target "profile" → "context/profile.json" so the
  write hits the correct path and triggers profile sync
- IDENTITY_FILES: add context/assistant-directives.md to the scanned
  set since it is also injected into the system prompt
- sync_profile_documents(): scan derived USER.md and assistant-directives
  content through Sanitizer before writing, rejecting High/Critical
  injection patterns
- profile_evolution_prompt(): wrap recent_messages_summary in <user_data>
  delimiters with untrusted-data instruction to mitigate indirect
  prompt injection
- routine-advisor skill: update cron examples from 6-field to standard
  5-field format for consistency with routine_create tool docs

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nboarding-and-routine-advisor

Resolved conflicts:
- src/agent/routine.rs: kept both normalize_cron tests and tool_rounds tests
- src/channels/web/static/{app.js,index.html}: adopted staging's element IDs
  and data-action names, updated HEAD's addEventListener bindings to match
- src/tools/builtin/memory.rs: kept sanitizer-based IDENTITY_FILES scanning
  (replacing staging's PROTECTED_IDENTITY_FILES hard block), added staging's
  looks_like_filesystem_path guard and tests
- src/workspace/mod.rs: merged bootstrap_pending/completed fields with
  search_defaults field
- tests/e2e_advanced_traces.rs: kept both MCP lifecycle and bootstrap tests
- src/agent/agent_loop.rs: added missing StatusUpdate import

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Quick-mode wizard now checks LLM_BACKEND, NEARAI_API_KEY,
ANTHROPIC_API_KEY, and OPENAI_API_KEY env vars to pre-populate
the provider setting, so users aren't re-prompted for credentials
they already supplied. Also teaches setup_nearai() to recognize
NEARAI_API_KEY from env (previously only checked session tokens).

Includes web UI cleanup (remove duplicate event listeners) and
e2e test response count adjustment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nboarding-and-routine-advisor

# Conflicts:
#	src/tools/builtin/routine.rs
The cron normalizer now always expands to 7-field format, so the
stored schedule is "0 0 9 * * * *" not "0 0 9 * * *".

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In quick mode, if NEARAI_API_KEY is set in the environment and the
backend was auto-detected as nearai, skip the interactive inference
provider and model selection steps. The API key is persisted to the
secrets store and a default model is set automatically.

Also simplify the static fallback model list for nearai to a single
default entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DEFAULT_MODEL const and default_models() fallback list in
  llm/nearai_chat.rs; use from config, wizard, and .env.example so the
  default model is defined in one place
- Restore multi-model fallback list in setup wizard (was reduced to 1)
- Move BOOTSTRAP_GREETING to module-level const (out of run() body)
- Replace LLM-based bootstrap with static greeting (persist to DB before
  channels start, then broadcast — eliminates startup LLM call and race)
- Fix double env::var read for NEARAI_API_KEY in quick setup path
- Move thread sidebar buttons into threads-section-header (web UI)
- Remove orphaned .thread-sidebar-header CSS and fix double blank line
- Update bootstrap e2e test for static greeting (no LLM trace needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: add ActiveConfigSnapshot to expose resolved LLM backend,
  model, and enabled channels via /api/gateway/status
- Add missing Agent settings (daily cost cap, actions/hour, local tools)
- Add Sandbox, Routines, Safety, Skills, and Search setting groups
- Settings import/export (JSON download + file upload)
- Active env defaults shown as placeholders in Inference settings
- Styled confirmation modals replace window.confirm() for remove actions
- Global restart banner persists across settings subtab switches
- Client-side validation with min/max constraints on number inputs
- Accessibility: aria-label on inputs, role=status on save indicators
- Settings search filters rows across current subtab
- Smooth CSS transitions for conditional field visibility (showWhen)
- Tunnel settings in Channels subtab
- Mobile responsive settings layout at 768px breakpoint
- i18n keys for toolbar, search, and import/export in en + zh-CN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… section

Remove the "Registered Tools" table from the extensions tab (debug info
not useful to end users), clean up associated CSS/i18n/JS. Additional
settings page UI polish: extension card state styling, layout refinements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use refreshCurrentSettingsTab() in SSE event handlers to reduce duplication
- Remove unused formatGroupName/formatSettingLabel helpers
- Use i18n keys for MCP Configure/Reconfigure buttons
- Add data-i18n-placeholder to settings search input
- Remove data-i18n from confirm modal button (set dynamically by showConfirmModal)
- Fix cargo fmt in main.rs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on-check]

- Update TABS list: replace extensions/skills with settings
- Add settings_subtab/settings_subpanel selectors to helpers
- Update test_connection, test_skills, test_extensions, test_wasm_lifecycle
  to navigate via Settings > subtab instead of top-level tabs
- Move MCP card tests to use go_to_mcp() helper (MCP is now a separate subtab)
- Remove tools table tests and mock_ext_apis tools= parameter
- Fix CSP violation: replace inline onclick on confirm modal cancel button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses PR #927 review comments (#1, #3) — identity file write
protection and unsanitized profile fields in system prompt.

Instead of scanning at the tool layer (memory.rs) or the sync layer
(sync_profile_documents), injection scanning now lives in
Workspace::write() and Workspace::append() for all files that are
injected into the system prompt. This ensures every code path that
writes to these files is protected, including future ones.

- Add SYSTEM_PROMPT_FILES const and reject_if_injected() in workspace
- Add WorkspaceError::InjectionRejected variant
- Add map_write_err() in memory.rs to convert InjectionRejected to
  ToolError::NotAuthorized
- Remove redundant IDENTITY_FILES/Sanitizer from memory.rs
- Remove redundant sanitizer calls from sync_profile_documents()
- Move sanitization tests to workspace::tests
- Existing integration test (test_memory_write_rejects_injection)
  continues to pass through the new path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sion-check]

- Use I18n.t() for MCP empty state, export/import toasts, confirm modal
- Fix CLI channel card using wrong channel key ('repl' -> 'cli')
- Fix settings search counting hidden rows as visible
- Add aria-label i18n for settings search input
- Add common.loadFailed i18n key (en + zh-CN)
- Update E2E tests: WASM channel tests use Channels subtab,
  remove tests use custom confirm modal instead of window.confirm

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…kip-regression-check]

- WASM channel tests: filter by display name to avoid matching built-in
  channel cards in the Channels subtab
- Skills remove test: click confirm modal button instead of using
  window.confirm (skill removal now uses custom confirm modal)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion-check]

- approval_needed SSE: refresh any active settings subtab, not just
  Extensions — approvals can surface from Channels/MCP setup flows too
- renderCardsSkeleton: remove nested .extensions-list wrapper that
  caused skeleton cards to render constrained inside grid cells

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ion-check]

Use expect_response to deterministically wait for the /api/extensions
reload triggered by handleAuthCompleted → refreshCurrentSettingsTab,
instead of a fixed 600ms sleep that was too short under CI load.
Also remove stale /api/extensions/tools route handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…p-regression-check]

Inject a counter wrapper around refreshCurrentSettingsTab to verify it's
actually called, and wait for the async fetch to complete before
asserting the reload count.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nboarding-and-routine-advisor

Also moves bootstrap greeting into src/workspace/seeds/GREETING.md
(loaded via include_str!) to keep user-facing copy out of Rust code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ilblackdragon and others added 6 commits March 15, 2026 14:24
…tstrap

Address Copilot review:
- Use LazyLock<Sanitizer> to avoid rebuilding Aho-Corasick + regexes
  on every workspace write
- has_profile check now requires non-empty content, not just file
  existence, to prevent empty profile.json from suppressing onboarding
- Add seed_tests integration tests (libsql-backed) verifying:
  - Empty profile.json does not suppress BOOTSTRAP.md seeding
  - Non-empty profile.json correctly suppresses bootstrap for upgrades

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-927-1191

# Conflicts:
#	src/channels/web/static/app.js
Introduce a unified terminal design system (src/cli/fmt.rs) with NO_COLOR
compliance and use it across all CLI output. Redesign the boot screen,
setup wizard, doctor/status commands, REPL help and approval flow. On the
web side: full-width messages, streaming cursor, auth transitions, empty
states, connection banners, keyboard shortcuts, ARIA accessibility, color
system cleanup, and responsive tablet layout. Add contextual thinking
messages, per-turn cost display, and a formatted top-level error handler
with recovery hints.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 1 — Design System Foundation:
- Unify CLI accent from cyan to emerald green (#34d399) with truecolor detection
- Rename bold_cyan() → bold_accent(), add hint() for dim italic tips
- Web: add typography scale (--text-xs to --text-3xl), replace 200+ hardcoded font-sizes
- Web: spacing audit replacing hardcoded values with --space-* tokens
- Web: motion system (easing/duration tokens) + prefers-reduced-motion support
- Web: prefers-contrast: more media query for accessibility

Phase 2 — First Impressions:
- Boot screen progressive disclosure (3-4 lines vs 10, hint to ironclaw status)
- Onboarding: auto-detect API keys (Anthropic/OpenAI/OpenRouter), skip interactive steps
- Onboarding: minimal wordmark banner replacing ASCII art
- Onboarding: dot-based step indicator (● ◉ ○) replacing progress bar
- Onboarding: provider smart ordering (detected keys first with checkmarks)
- Onboarding: warm completion card with key facts
- Onboarding: --step flag for selective re-onboarding (deprecates --channels-only/--provider-only)

Phase 3 — Web Chat & Interactions:
- Welcome card with i18n suggestion chips
- Code block syntax highlighting via highlight.js CDN
- Turn cost SSE handler with token/cost badge
- Streaming: reduced debounce 150ms→50ms, 10K force-flush safeguard
- Connection indicator: amber disconnect, reconnection attempt counter
- Skeleton loading states for threads/history
- Tool card progress bar animation, icon pop on complete
- Streaming cursor pulse, typing indicator dots
- Refined approval card styling with keyboard hints
- Thread sidebar: preview lines, active accent border
- Input area: footer row, char count, send button glow
- User messages: right-aligned chat bubbles with accent tint

Phase 4 — Polish & Accessibility:
- Doctor: grouped output (Core/Features/External sections)
- REPL: redesigned /help with quick start + categorized commands
- Web: aria-live on chat messages and toasts, aria-label on icon buttons
- Web: focus-visible styles, touch targets, safe area padding
- Web: mobile optimization (375px breakpoint, iOS zoom prevention)
- i18n: new keys in en.js and zh-CN.js for welcome card, connection, messages

Bug fixes during review:
- Fix duplicate event listeners causing language switch and sidebar toggle to no-op
- Fix sidebar collapse hiding toggle button (keep + and « visible when collapsed)
- Restore message copy button that was accidentally removed

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 17, 2026 03:09
@github-actions github-actions bot added scope: agent Agent core (agent loop, router, scheduler) scope: channel Channel infrastructure scope: channel/cli TUI / CLI channel scope: channel/web Web gateway channel scope: channel/wasm WASM channel runtime scope: tool/builtin Built-in tools scope: llm LLM integration scope: workspace Persistent memory / workspace scope: config Configuration scope: setup Onboarding / setup scope: docs Documentation size: XL 500+ changed lines risk: high Safety, secrets, auth, or critical infrastructure contributor: core 20+ merged PRs labels Mar 17, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a significant user experience upgrade across the application, focusing on consistency, ease of use, and intelligent personalization. It integrates new AI capabilities for task management and routine automation, while also bolstering security and improving the overall polish of both the command-line and web interfaces.

Highlights

  • Comprehensive UX Overhaul: Implemented a unified design system across CLI and web interfaces, including consistent accent colors, typography, spacing, and motion. This aims to provide a polished, calm, and intentional product experience.
  • Streamlined Onboarding Experience: The onboarding process has been significantly improved with auto-detection of API keys, the ability to skip interactive steps, modern branding, and a new --step flag for selective re-onboarding. A progressive disclosure boot screen now provides a concise overview.
  • Enhanced Web Chat Features: The web chat now includes a welcome card with suggestion chips, syntax highlighting for code blocks, user messages displayed as right-aligned chat bubbles, improved streaming polish, a connection indicator, and skeleton loading states for a smoother user experience.
  • New AI Assistant Capabilities: Introduced new skills for task delegation (delegation) and routine suggestions (routine-advisor), allowing the AI to help users break down tasks, set deadlines, track progress, and automate recurring activities.
  • Improved CLI Diagnostics and UI: The doctor command now groups diagnostics (Core/Features/External) and the REPL's /help command has been redesigned with a quick start section. Terminal output uses a new fmt module for consistent ANSI styling.
  • Psychographic Profile and Personalization: Added a new profile.rs module to define psychographic profile types and an analysis framework. This enables the AI to build and evolve a user's profile, generating personalized USER.md and assistant-directives.md documents.
  • Robust Prompt Injection Protection: Implemented prompt injection scanning for system-prompt-injected files (e.g., SOUL.md, USER.md) to prevent malicious overwrites and ensure the integrity of the agent's core instructions.
  • Accessibility and Internationalization: Enhanced accessibility with aria-live, aria-label, focus-visible, touch targets, and mobile optimization. All new strings have been added to English and Chinese (zh-CN) localization files.
Changelog
  • .env.example
    • Updated the default NEARAI_MODEL to a new value.
  • CLAUDE.md
    • Added profile.rs to the src/ directory description.
  • skills/delegation/SKILL.md
    • Added a new skill for task delegation, including activation keywords, patterns, and a detailed process for clarifying, breaking down, tracking, and executing tasks.
  • skills/routine-advisor/SKILL.md
    • Added a new skill for suggesting and creating cron routines based on user context and observed patterns, with guidelines for when and how to suggest routines.
  • src/agent/agent_loop.rs
    • Implemented a static bootstrap greeting (BOOTSTRAP_GREETING) that is persisted to the database and broadcast on first launch, ensuring immediate user feedback.
    • Added logic to emit per-turn cost summaries after agent execution.
    • Removed verbose debug logging for message processing and session resolution.
  • src/agent/dispatcher.rs
    • Updated status messages during LLM calls and tool execution to be more contextual, showing 'Thinking (step X)...' and specific tool names like 'Running command...'.
    • Added contextual_tool_message helper function to generate descriptive messages for single tool calls.
  • src/agent/routine.rs
    • Introduced normalize_cron_expression to convert 5-field and 6-field cron expressions to the 7-field format required by the cron crate.
    • Updated next_cron_fire to use the new cron normalization function, improving flexibility for schedule definitions.
    • Added new unit tests for cron expression normalization across different field counts.
  • src/agent/thread_ops.rs
    • Integrated logic to calculate and emit per-turn token usage and cost summaries via StatusUpdate::TurnCost.
  • src/app.rs
    • Added logic to check profile_onboarding_completed setting and mark the workspace's bootstrap as completed if already true, preventing re-injection of bootstrap instructions for existing users.
  • src/boot_screen.rs
    • Refactored the boot screen to display a more compact, three-tier status panel, focusing on essential information (name, version, model, backend, URLs).
    • Removed less critical details (database, tool count, features) from the main boot screen, directing users to ironclaw status for full details.
    • Added startup elapsed time to the boot screen footer.
  • src/channels/channel.rs
    • Added TurnCost variant to the StatusUpdate enum to convey per-turn token usage and cost information.
  • src/channels/repl.rs
    • Updated REPL UI to use the new crate::cli::fmt module for consistent ANSI styling, including hints, accents, and status indicators.
    • Improved the /help command output with a quick start section and grouped commands.
    • Implemented smart_truncate for tool parameter display, showing both ends of long strings.
    • Refined the appearance of approval cards and status updates with new ANSI color codes and symbols.
  • src/channels/wasm/wrapper.rs
    • Modified status_to_wit to explicitly skip StatusUpdate::TurnCost events for WASM channels, as they are web-gateway-only.
  • src/channels/web/mod.rs
    • Added active_config field to GatewayState to store a snapshot of the active configuration for the frontend status endpoint.
  • src/channels/web/server.rs
    • Defined ActiveConfigSnapshot struct to capture current LLM backend, model, and enabled channels.
    • Integrated ActiveConfigSnapshot into GatewayState and the GatewayStatusResponse for the web frontend.
  • src/channels/web/sse.rs
    • Added TurnCost as a new SseEvent type for broadcasting token usage and cost to connected clients.
  • src/channels/web/static/app.js
    • Implemented streaming debounce for assistant messages to improve UI responsiveness during long generations.
    • Added a connection status banner to inform users about disconnections and reconnections.
    • Introduced a send cooldown mechanism to prevent rapid message sending and handle rate limiting.
    • Added a welcome card with suggestion chips for new chat threads.
    • Integrated syntax highlighting for code blocks in chat messages using highlight.js.
    • Refactored tab switching to include a new 'Settings' tab with subtabs for Inference, Agent, Channels, Networking, Extensions, MCP, and Skills.
    • Implemented structured settings rendering with dynamic input types, descriptions, and restart indicators.
    • Updated extension and skill loading to use skeleton loaders and refresh based on the active settings subtab.
    • Replaced native window.confirm with a custom confirmation modal for removal actions.
    • Added keyboard shortcuts overlay and ARIA accessibility attributes for improved usability.
  • src/channels/web/static/i18n/en.js
    • Added new internationalization strings for the 'Settings' tab and its subtabs (Inference, Agent, Channels, Networking, MCP).
    • Included new strings for the welcome card, connection status, and structured settings elements.
    • Removed old 'tools' related strings, reflecting the consolidation into the 'Settings' tab.
  • src/channels/web/static/i18n/zh-CN.js
    • Added new internationalization strings for the 'Settings' tab and its subtabs (Inference, Agent, Channels, Networking, MCP) in Chinese.
    • Included new strings for the welcome card, connection status, and structured settings elements in Chinese.
    • Removed old 'tools' related strings, reflecting the consolidation into the 'Settings' tab.
  • src/channels/web/static/index.html
    • Integrated highlight.js for client-side syntax highlighting of code blocks.
    • Updated the authentication screen hint for clarity.
    • Modified the tab bar to include a new 'Settings' tab and removed 'Extensions' and 'Skills' as top-level tabs.
    • Added new HTML structure for settings subtabs, including search, export/import buttons, and structured configuration panels.
    • Implemented a custom confirmation modal to replace browser's native confirm dialog.
    • Added ARIA attributes to tab elements for improved accessibility.
  • src/channels/web/test_helpers.rs
    • Added active_config to the TestGatewayBuilder struct for test setup consistency.
  • src/channels/web/types.rs
    • Added TurnCost variant to the SseEvent enum for broadcasting token usage and cost data.
  • src/channels/web/ws.rs
    • Updated test setup to include active_config in GatewayState initialization.
  • src/cli/doctor.rs
    • Refactored the doctor command output to use the new crate::cli::fmt module for consistent ANSI styling.
    • Grouped diagnostic checks into 'Core', 'Features', and 'External' sections for better readability.
    • Improved the summary line with colored pass/fail/skip counts.
  • src/cli/fmt.rs
    • Added a new module fmt to centralize terminal styling, including color tokens (accent, bold, success, warning, error, dim, link, hint, reset), width detection, and rendering primitives (separators, key-value lines, status icons, box drawing, check lines).
    • Implemented logic to respect NO_COLOR environment variable and non-TTY output for color rendering.
  • src/cli/mod.rs
    • Added fmt module to the CLI module exports.
    • Introduced a new --step argument to the onboard command, allowing users to run specific setup steps (e.g., provider, channels).
  • src/cli/status.rs
    • Refactored the status command output to use the new crate::cli::fmt module for consistent and visually appealing presentation of system information.
  • src/config/llm.rs
    • Updated the default NEARAI_MODEL to use crate::llm::DEFAULT_MODEL for consistency.
  • src/error.rs
    • Added InjectionRejected variant to WorkspaceError to specifically handle cases where content is rejected due to prompt injection detection.
  • src/lib.rs
    • Added profile module to the library exports.
  • src/llm/mod.rs
    • Exported DEFAULT_MODEL and default_models from nearai_chat for broader use within the application.
  • src/llm/nearai_chat.rs
    • Defined DEFAULT_MODEL constant for the default NEAR AI model.
    • Provided default_models function to offer a fallback list of NEAR AI models for the setup wizard.
  • src/main.rs
    • Implemented format_top_level_error to provide colored and contextual error messages with recovery hints for common startup failures.
    • Added startup_start timestamp to measure and display the application's startup duration on the boot screen.
    • Ensured the WASM channels directory is created on startup, even if no channels are installed, to support hot-activation.
    • Passed an ActiveConfigSnapshot to the gateway channel, providing frontend with current LLM configuration and enabled channels.
  • src/profile.rs
    • Added a new module defining PsychographicProfile and its sub-components (PersonalityTraits, CommunicationPreferences, CohortClassification, etc.).
    • Included ANALYSIS_FRAMEWORK and PROFILE_JSON_SCHEMA constants to guide LLM-based profile generation and evolution.
    • Implemented is_populated, to_user_md, to_assistant_directives, and to_heartbeat_md methods for rendering profile data into various workspace documents.
    • Added custom deserializers for backward compatibility with older profile formats and robust handling of trait scores.
  • src/setup/README.md
    • Updated the setup README to clarify that personal onboarding now occurs conversationally with the running assistant, rather than as part of the initial wizard.
  • src/setup/mod.rs
    • Exported the new profile_evolution module.
    • Exported SetupError from the wizard module.
  • src/setup/profile_evolution.rs
    • Added a new module for generating LLM prompts to facilitate weekly psychographic profile evolution based on recent conversations.
    • Defined profile_evolution_prompt to instruct the LLM on how to update a profile given current data and conversation summaries.
    • Provided PROFILE_EVOLUTION_ROUTINE_PROMPT for the routine that triggers profile updates.
  • src/setup/prompts.rs
    • Updated the select_many prompt UI with new checkbox styling (green checkmark for selected, dim dot for unselected).
    • Replaced the ASCII art banner with a minimal wordmark banner (ironclaw).
    • Modified print_step to use a dot-based indicator (● ● ◉ ○ ○) for a more modern and compact visual representation of progress.
  • src/setup/wizard.rs
    • Implemented the --step flag for the onboard command, allowing users to run specific setup steps (e.g., ironclaw onboard --step provider,model).
    • Added auto-detection of API keys from environment variables for NEAR AI, Anthropic, OpenAI, and OpenRouter, allowing the wizard to skip interactive prompts if credentials are found.
    • Updated NEAR AI model selection to use crate::llm::default_models as a fallback if the API is unreachable.
    • Refactored the final summary output to use the new crate::cli::fmt module, presenting a concise completion card with key facts and action hints.
  • src/tools/builtin/memory.rs
    • Removed the PROTECTED_IDENTITY_FILES constant, as prompt injection protection is now handled generically by the workspace module.
    • Added map_write_err to convert WorkspaceError into ToolError, specifically mapping InjectionRejected to ToolError::NotAuthorized.
    • Modified memory_write to call workspace.mark_bootstrap_completed() and workspace.sync_profile_documents() when context/profile.json is written, automating profile-related document updates.
  • src/tools/builtin/routine.rs
    • Updated RoutineCreateTool and RoutineUpdateTool to utilize the new normalize_cron_expression function, ensuring compatibility with 5-field and 6-field cron schedules.
  • src/workspace/document.rs
    • Added new constants PROFILE (context/profile.json) and ASSISTANT_DIRECTIVES (context/assistant-directives.md) to paths for psychographic profile and derived behavioral directives.
  • src/workspace/mod.rs
    • Introduced SYSTEM_PROMPT_FILES constant to list files whose writes are subject to prompt injection scanning.
    • Implemented is_system_prompt_file to check if a path corresponds to a system-prompt-injected file.
    • Added SANITIZER static lazy-loaded instance and reject_if_injected function to perform prompt injection detection on writes to sensitive files.
    • Added bootstrap_pending and bootstrap_completed atomic flags to manage the first-run bootstrap greeting and its suppression.
    • Implemented sync_profile_documents to automatically generate and merge USER.md, context/assistant-directives.md, and HEARTBEAT.md based on the context/profile.json content.
    • Updated system_prompt_for_context to dynamically inject profile personalization (Tier 1 summary, Tier 2 full context) and the profile JSON schema during bootstrap onboarding.
    • Modified seed_if_empty to use new include_str! for seed files and to conditionally seed BOOTSTRAP.md only if the workspace is fresh and no profile exists, preventing redundant onboarding.
  • src/workspace/seeds/AGENTS.md
    • Updated content to include guidelines for passive profile building and managing identity files (USER.md, IDENTITY.md).
  • src/workspace/seeds/BOOTSTRAP.md
    • Revised content for the first-run bootstrap ritual, focusing on greeting, natural user learning, mandatory profile saving, and style guidelines.
  • src/workspace/seeds/GREETING.md
    • Added a new static greeting message for the initial user interaction.
  • src/workspace/seeds/HEARTBEAT.md
    • Updated content for the heartbeat checklist seed file.
  • src/workspace/seeds/IDENTITY.md
    • Updated content for the agent's identity seed file.
  • src/workspace/seeds/MEMORY.md
    • Updated content for the memory guidelines seed file.
  • src/workspace/seeds/README.md
    • Updated content for the workspace overview seed file.
  • src/workspace/seeds/SOUL.md
    • Updated content for core values, boundaries, and autonomy guidelines.
  • src/workspace/seeds/TOOLS.md
    • Updated content for environment-specific tool notes seed file.
  • src/workspace/seeds/USER.md
    • Updated content for the user context seed file.
  • tests/e2e/helpers.py
    • Updated UI selectors to reflect the new settings subtab structure and the custom confirmation modal.
    • Modified the TABS list to include 'settings' instead of 'extensions' and 'skills' as top-level tabs.
  • tests/e2e/scenarios/test_extensions.py
    • Adapted E2E tests for extensions to navigate through the new 'Settings' tab and its 'Extensions' subtab.
    • Removed tests related to the dedicated 'tools' table, as tools are now managed within extensions.
    • Updated tests for MCP servers to use the new 'MCP' settings subtab.
    • Modified tests to interact with the new custom confirmation modal instead of window.confirm.
  • tests/e2e/scenarios/test_skills.py
    • Adjusted E2E tests for skills to navigate through the new 'Settings' tab and its 'Skills' subtab.
    • Updated tests to interact with the new custom confirmation modal for skill removal.
  • tests/e2e/scenarios/test_wasm_lifecycle.py
    • Updated E2E tests for WASM lifecycle to reflect navigation through the new 'Settings' tab and its 'Extensions' subtab.
  • tests/e2e_advanced_traces.rs
    • Added a new test case (bootstrap_greeting_fires) to verify that a fresh workspace triggers the static bootstrap greeting before any user message or LLM interaction.
  • tests/e2e_builtin_tool_coverage.rs
    • Updated cron schedule assertion to match the new 7-field normalized format.
  • tests/openai_compat_integration.rs
    • Added active_config to GatewayState initialization in test setups for consistency.
  • tests/support/gateway_workflow_harness.rs
    • Included active_config in GatewayState initialization within the test harness.
  • tests/support/test_channel.rs
    • Added channel_name field to TestChannel and a with_name method to allow custom channel naming in tests.
    • Updated send_message and send_message_in_thread to use the configurable channel name.
  • tests/support/test_rig.rs
    • Introduced keep_bootstrap flag to TestRigBuilder to control whether the bootstrap pending flag is cleared, enabling tests for the proactive greeting.
    • Modified TestRigBuilder::build to conditionally name the test channel 'gateway' when keep_bootstrap is true, ensuring the bootstrap greeting is received.
  • tests/ws_gateway_integration.rs
    • Added active_config to GatewayState initialization in test setups.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Comprehensive UX overhaul spanning CLI and web surfaces, plus new “conversational onboarding” via workspace bootstrap/profile files. The PR also adds safety scanning for system-prompt-injected workspace documents and expands gateway status payloads for frontend display.

Changes:

  • Introduces a shared CLI formatting “design system” (cli::fmt) and refreshes boot/status/doctor/REPL output accordingly.
  • Adds workspace seed templates + bootstrap greeting/onboarding flow, psychographic profile scaffolding, and prompt-injection scanning for system-prompt-injected workspace files.
  • Polishes web gateway UI structure (Settings tab + subtabs), adds SSE/WS event types (turn cost), and updates E2E/integration tests to match.

Reviewed changes

Copilot reviewed 65 out of 66 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/ws_gateway_integration.rs Updates test gateway state construction to include active_config.
tests/support/test_rig.rs Adds bootstrap-aware test rig behavior (optionally preserve bootstrap + ensure gateway channel name).
tests/support/test_channel.rs Makes test channel name configurable (needed for bootstrap tests).
tests/support/gateway_workflow_harness.rs Updates harness gateway state construction to include active_config.
tests/openai_compat_integration.rs Updates test gateway state construction to include active_config.
tests/e2e_builtin_tool_coverage.rs Updates expected cron expression to normalized 7-field format.
tests/e2e_advanced_traces.rs Adds E2E test asserting bootstrap greeting fires on fresh workspace.
tests/e2e/scenarios/test_wasm_lifecycle.py Updates navigation to match new Settings + Extensions subtab layout.
tests/e2e/scenarios/test_skills.py Updates navigation to Settings > Skills and adapts removal confirmation flow.
tests/e2e/scenarios/test_extensions.py Refactors tests for new Settings subtabs (Extensions/MCP/Channels) and custom confirm modal.
tests/e2e/helpers.py Adds selectors for Settings subtabs/panels + confirm modal; updates tab list.
src/workspace/seeds/USER.md New seed template for user context.
src/workspace/seeds/TOOLS.md New seed template for environment-specific tool notes.
src/workspace/seeds/SOUL.md New seed template for assistant “values/boundaries”.
src/workspace/seeds/README.md New seed template documenting workspace structure.
src/workspace/seeds/MEMORY.md New seed template for long-term memory file.
src/workspace/seeds/IDENTITY.md New seed template for assistant identity.
src/workspace/seeds/HEARTBEAT.md New seed template for heartbeat checklist.
src/workspace/seeds/GREETING.md Adds static first-run greeting content persisted/broadcast on bootstrap.
src/workspace/seeds/BOOTSTRAP.md Adds detailed first-run bootstrap instructions for conversational onboarding.
src/workspace/seeds/AGENTS.md New seed template for session routines/operational instructions.
src/workspace/mod.rs Adds system-prompt file injection scanning, bootstrap flags, profile injection logic, and profile→document sync.
src/workspace/document.rs Adds canonical paths for context/profile.json and context/assistant-directives.md.
src/tools/builtin/routine.rs Normalizes cron expressions to 7-field format before validation/storage.
src/tools/builtin/memory.rs Routes injection rejections to NotAuthorized, marks bootstrap completed, and syncs derived docs on profile write.
src/setup/wizard.rs Adds --step selective onboarding, provider autodetect from env, and refreshes completion summary UX.
src/setup/prompts.rs Updates interactive prompt rendering (step indicator, banner, checkbox UI).
src/setup/profile_evolution.rs New module to generate weekly profile-evolution prompts + routine prompt template.
src/setup/mod.rs Exposes SetupError, exports profile_evolution, and documents conversational onboarding.
src/setup/README.md Documents that personal onboarding happens via workspace bootstrap in the running assistant.
src/settings.rs Adds profile_onboarding_completed persisted flag (alias supported).
src/main.rs Adds top-level error formatting with hints, startup timing, ensures WASM channels dir exists, and publishes active config snapshot.
src/llm/nearai_chat.rs Updates NEAR AI default model and provides fallback model list for setup wizard.
src/llm/mod.rs Re-exports DEFAULT_MODEL and default_models().
src/lib.rs Exposes new profile module.
src/error.rs Adds WorkspaceError::InjectionRejected.
src/config/llm.rs Updates default NEAR AI model to crate::llm::DEFAULT_MODEL.
src/cli/status.rs Switches status output to cli::fmt key/value lines and updated layout.
src/cli/mod.rs Exposes cli::fmt and adds onboard --step flag (deprecates older single-step flags).
src/cli/fmt.rs New shared terminal formatting/color token module with NO_COLOR + TTY detection.
src/cli/doctor.rs Groups diagnostics and uses cli::fmt for consistent rendering.
src/channels/web/ws.rs Updates test gateway state construction to include active_config.
src/channels/web/types.rs Adds SSE event turn_cost and wires event typing for WS/SSE payloads.
src/channels/web/test_helpers.rs Updates helper gateway state construction to include active_config.
src/channels/web/static/index.html Adds Settings tab/subtabs layout, confirm modal, aria attributes, and Highlight.js assets.
src/channels/web/static/i18n/zh-CN.js Adds Settings and new UI strings, updates extensions wording.
src/channels/web/static/i18n/en.js Adds Settings and new UI strings, updates extensions wording.
src/channels/web/sse.rs Wires SSE event type mapping for turn_cost.
src/channels/web/server.rs Adds ActiveConfigSnapshot and returns active config fields in /api/gateway/status.
src/channels/web/mod.rs Adds with_active_config and maps StatusUpdate::TurnCost → SSE event.
src/channels/wasm/wrapper.rs Explicitly skips web-only status updates (suggestions + turn cost) for WASM channels.
src/channels/repl.rs Migrates REPL output to cli::fmt, improves truncation, and refreshes /help and approval rendering.
src/channels/channel.rs Adds StatusUpdate::TurnCost.
src/boot_screen.rs Reworks boot screen to a 2-tier summary and links to ironclaw status for full details.
src/app.rs Loads profile_onboarding_completed from settings to suppress bootstrap injection for existing users.
src/agent/thread_ops.rs Emits StatusUpdate::TurnCost after a response.
src/agent/routine.rs Adds cron normalization and updates cron parsing to accept 5/6/7-field expressions.
src/agent/dispatcher.rs Improves thinking/status messages with tool-name-aware wording.
src/agent/agent_loop.rs Adds bootstrap greeting persistence + broadcast flow driven by workspace bootstrap flag.
skills/routine-advisor/SKILL.md New skill to suggest routines based on user patterns + cron examples.
skills/delegation/SKILL.md New skill to guide task delegation + persistence via memory/routines.
CLAUDE.md Updates repo map documentation to include new profile.rs.
.env.example Updates example NEAR AI model default.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +492 to +516
// Emit per-turn cost summary
{
let usage = self.cost_guard().model_usage().await;
let (total_in, total_out, total_cost) =
usage
.values()
.fold((0u64, 0u64, rust_decimal::Decimal::ZERO), |acc, m| {
(
acc.0 + m.input_tokens,
acc.1 + m.output_tokens,
acc.2 + m.cost,
)
});
let _ = self
.channels
.send_status(
&message.channel,
StatusUpdate::TurnCost {
input_tokens: total_in as u32,
output_tokens: total_out as u32,
cost_usd: format!("${:.4}", total_cost),
},
&message.metadata,
)
.await;
Comment on lines 553 to +565
// Top border: ┌ tool_name requires approval ───
let top_label = format!(" {tool_name} requires approval ");
let top_fill = box_width.saturating_sub(top_label.len() + 1);
let top_border = format!(
"\u{250C}\x1b[33m{top_label}\x1b[0m{}",
"\u{250C}{}{top_label}{}{}",
fmt::warning(),
fmt::reset(),
"\u{2500}".repeat(top_fill)
);

// Bottom border: └─ short_id ─────
let bot_label = format!(" {short_id} ");
let bot_fill = box_width.saturating_sub(bot_label.len() + 2);
let bot_border = format!(
"\u{2514}\u{2500}\x1b[90m{bot_label}\x1b[0m{}",
"\u{2500}".repeat(bot_fill)
);
// Bottom border: └─────
let bot_fill = box_width.saturating_sub(1);
let bot_border = format!("\u{2514}{}", "\u{2500}".repeat(bot_fill));
Comment on lines +15 to +20
/// - stdout is not a terminal (pipe, file redirect, CI)
fn colors_enabled() -> bool {
if std::env::var_os("NO_COLOR").is_some() {
return false;
}
std::io::stdout().is_terminal()
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request includes several changes to improve the IronClaw agent. The default NEARAI_MODEL in .env.example was updated to Qwen/Qwen3.5-122B-A10B. A new profile.rs file was added to the src/ directory for psychographic profile types. The delegation and routine-advisor skills were added. A bootstrap greeting was added to the agent loop. The agent dispatcher was updated to provide more contextual thinking messages based on tool names. The routine advisor was updated to normalize cron expressions. The boot screen was updated to be more compact. The REPL channel was updated to use a new color scheme and to truncate long strings. The web gateway channel was updated to include per-turn cost summaries. The web gateway was updated to include a snapshot of the active configuration. The web gateway's javascript was updated to include a number of new features, including a settings tab, a confirmation modal, and a welcome card. A number of other changes were made to improve the agent's performance and stability. The code reviewer suggested that the errors from get_or_create_assistant_conversation and persist_assistant_response should be handled to prevent silent failures. The code reviewer also suggested that the current implementation of normalize_cron_expression for 5-field expressions might be subtly incorrect and that a more robust approach would be to join the fields collected from split_whitespace. The code reviewer also suggested that the logic for handling the bootstrap process can be simplified.

Comment on lines +273 to +281
let thread_id = store
.get_or_create_assistant_conversation("default", "gateway")
.await
.ok();
if let Some(id) = thread_id {
self.persist_assistant_response(id, "gateway", "default", BOOTSTRAP_GREETING)
.await;
}
thread_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The errors from get_or_create_assistant_conversation and persist_assistant_response are being ignored. This can lead to silent failures where the bootstrap greeting is not persisted to the database, which could be confusing for new users. It would be more robust to handle these potential errors, for example by logging them. This aligns with the principle of robust error handling and logging, as seen in the rule regarding tokio::task::spawn_blocking.

                let thread_id = match store
                    .get_or_create_assistant_conversation("default", "gateway")
                    .await
                {
                    Ok(id) => {
                        if let Err(e) = self
                            .persist_assistant_response(id, "gateway", "default", BOOTSTRAP_GREETING)
                            .await
                        {
                            tracing::warn!("Failed to persist bootstrap greeting: {}", e);
                        }
                        Some(id)
                    }
                    Err(e) => {
                        tracing::warn!("Failed to get or create bootstrap conversation: {}", e);
                        None
                    }
                };
References
  1. When handling errors, log them to capture debugging information and prevent silent failures. It is good practice to distinguish between different error types in the message.

pub fn normalize_cron_expression(schedule: &str) -> String {
let fields: Vec<&str> = schedule.split_whitespace().collect();
match fields.len() {
5 => format!("0 {} *", schedule.trim()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of normalize_cron_expression for 5-field expressions might be subtly incorrect. Using format!("0 {} *", schedule.trim()) could lead to issues if schedule.trim() itself contains extra spaces that are not handled by split_whitespace. A more robust approach would be to join the fields collected from split_whitespace.

Suggested change
5 => format!("0 {} *", schedule.trim()),
5 => format!("0 {} *", fields.join(" ")),

Comment on lines +699 to +718
let bootstrap_injected = if self.is_bootstrap_completed() {
if self
.read(paths::BOOTSTRAP)
.await
.is_ok_and(|d| !d.content.is_empty())
{
tracing::warn!(
"BOOTSTRAP.md still exists but profile_onboarding_completed is set; \
suppressing bootstrap injection"
);
}
false
} else if let Ok(doc) = self.read(paths::BOOTSTRAP).await
&& !doc.content.is_empty()
{
parts.push(format!(
"## First-Run Bootstrap\n\n\
A BOOTSTRAP.md file exists in the workspace. Read and follow it, \
then delete it when done.\n\n{}",
doc.content
));
}
parts.push(format!("## First-Run Bootstrap\n\n{}", doc.content));
true
} else {
false
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for handling the bootstrap process can be simplified. Instead of checking is_bootstrap_completed and then reading the file, you can combine these checks for better readability and to avoid nested if statements.

Suggested change
let bootstrap_injected = if self.is_bootstrap_completed() {
if self
.read(paths::BOOTSTRAP)
.await
.is_ok_and(|d| !d.content.is_empty())
{
tracing::warn!(
"BOOTSTRAP.md still exists but profile_onboarding_completed is set; \
suppressing bootstrap injection"
);
}
false
} else if let Ok(doc) = self.read(paths::BOOTSTRAP).await
&& !doc.content.is_empty()
{
parts.push(format!(
"## First-Run Bootstrap\n\n\
A BOOTSTRAP.md file exists in the workspace. Read and follow it, \
then delete it when done.\n\n{}",
doc.content
));
}
parts.push(format!("## First-Run Bootstrap\n\n{}", doc.content));
true
} else {
false
};
let bootstrap_injected = if self.is_bootstrap_completed() {
if self.read(paths::BOOTSTRAP).await.is_ok_and(|d| !d.content.is_empty()) {
tracing::warn!(
"BOOTSTRAP.md still exists but profile_onboarding_completed is set; suppressing bootstrap injection"
);
}
false
} else if let Ok(doc) = self.read(paths::BOOTSTRAP).await && !doc.content.is_empty() {
parts.push(format!("## First-Run Bootstrap\n\n{}", doc.content));
true
} else {
false
};

Copy link
Collaborator

@zmanian zmanian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: massive UX overhaul + psychographic profiling + identity file safety

This is a 36-commit, 7300-line PR spanning psychographic profiling, identity file injection scanning, bootstrap/onboarding redesign, CLI design system, web UI overhaul, i18n, new skills, and new SSE events. Observations below.

Critical: CI did not run (fork PR)

Only classify/scope ran. No Clippy (any feature combo), formatting, panic-check, or regression enforcement. For a PR touching 66 files across Rust, JS, CSS, and HTML, full CI is mandatory before merge. Either push a maintainer commit to the branch or run local CI.

Concerning: scope should be split

This combines at least 4 orthogonal features:

  1. Psychographic profiling (profile.rs, onboarding_chat.rs, profile_evolution.rs, seeds)
  2. Identity file write protection (memory.rs -> workspace injection scanning)
  3. Web UI overhaul (CSS/JS/HTML, i18n, settings tabs)
  4. CLI design system (fmt.rs, boot screen, REPL, doctor/status)

Each would benefit from independent review and rollback capability. I'd strongly suggest splitting this so each feature can land and be tested independently.

Concerning: [skip-regression-check] on functional commits

Commits 35 and 36 both use [skip-regression-check] but contain substantial functional changes (SSE event handling, streaming debounce changes, boot screen restructuring, connection status logic). These aren't pure style changes.

Concerning: highlight.js CDN dependency

Commit 36 introduces syntax highlighting via a CDN. External CDN dependencies create availability risks (offline users, CDN outages) and supply chain risk (CDN compromise). Consider bundling or using a self-hosted copy.

Concerning: profile types use String instead of enums

CommunicationPreferences fields (detail_level, formality, tone, etc.) are all String. Per project conventions ("prefer strong types over strings"), these should be enums. This makes invalid states representable and means deserialization won't catch typos.

Positives:

  • Identity file injection scanning evolution is good -- moving from tool layer (memory.rs) to Workspace::write/append (commit 20) ensures all write paths are protected
  • LazyLock for the sanitizer (commit 33) avoids rebuilding Aho-Corasick on every write
  • The non-empty profile check for bootstrap suppression is a solid edge case fix
  • CSP-compliant event handlers (commit 7) is a good security improvement
  • The routine_trigger_message Cow pattern is efficient

Minor notes:

  • deserialize_trait_score in profile.rs silently returns 50 on deser failure -- intentional for LLM robustness but worth a comment
  • StatusUpdate::TurnCost -- verify the enum variant definition is included in this diff (I didn't find it in the patch)
  • The env_or_override fix for NEARAI_API_KEY (commit 5) is a standalone bug fix that should land independently

Copy link
Collaborator

@zmanian zmanian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated Review: UX overhaul + psychographic profiling + identity file safety

Updating my earlier review -- scope is fine as a single PR given the interconnected nature of the changes.

Critical: CI did not run (fork PR)

Only classify/scope ran. No Clippy (any feature combo), formatting, panic-check, or regression enforcement. For a PR touching 66 files across Rust, JS, CSS, and HTML, full CI is mandatory before merge. Either push a maintainer commit to the branch or run local CI.

Concerning: [skip-regression-check] on functional commits

Commits 35 and 36 both use [skip-regression-check] but contain substantial functional changes (SSE event handling, streaming debounce changes, boot screen restructuring, connection status logic). These aren't pure style changes.

Concerning: highlight.js CDN dependency

Commit 36 introduces syntax highlighting via a CDN. External CDN dependencies create availability risks (offline users, CDN outages) and supply chain risk (CDN compromise). Consider bundling or using a self-hosted copy.

Concerning: profile types use String instead of enums

CommunicationPreferences fields (detail_level, formality, tone, etc.) are all String. Per project conventions ("prefer strong types over strings"), these should be enums. This makes invalid states representable and means deserialization won't catch typos.

Positives:

  • Identity file injection scanning evolution is good -- moving from tool layer (memory.rs) to Workspace::write/append (commit 20) ensures all write paths are protected
  • LazyLock for the sanitizer (commit 33) avoids rebuilding Aho-Corasick on every write
  • The non-empty profile check for bootstrap suppression is a solid edge case fix
  • CSP-compliant event handlers (commit 7) is a good security improvement
  • The routine_trigger_message Cow pattern is efficient
  • The env_or_override fix for NEARAI_API_KEY (commit 5) is a nice catch

Minor notes:

  • deserialize_trait_score in profile.rs silently returns 50 on deser failure -- intentional for LLM robustness but worth a comment
  • StatusUpdate::TurnCost -- verify the enum variant definition is included in this diff (I didn't find it in the patch)

@ilblackdragon ilblackdragon marked this pull request as draft March 17, 2026 04:01
@ilblackdragon
Copy link
Member Author

This is still a draft and waiting for #927 and #1191 to merge (this merged them internal)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: high Safety, secrets, auth, or critical infrastructure scope: agent Agent core (agent loop, router, scheduler) scope: channel/cli TUI / CLI channel scope: channel/wasm WASM channel runtime scope: channel/web Web gateway channel scope: channel Channel infrastructure scope: config Configuration scope: docs Documentation scope: llm LLM integration scope: setup Onboarding / setup scope: tool/builtin Built-in tools scope: workspace Persistent memory / workspace size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants