Skip to content

feat: DX improvements — dark mode, status command, memory previews#102

Merged
rohitg00 merged 2 commits intomainfrom
feat/dx-improvements
Apr 9, 2026
Merged

feat: DX improvements — dark mode, status command, memory previews#102
rohitg00 merged 2 commits intomainfrom
feat/dx-improvements

Conversation

@rohitg00
Copy link
Copy Markdown
Owner

@rohitg00 rohitg00 commented Apr 8, 2026

Summary

Closes the DX gap with graphify by adding polish that makes the value visible.

  • Viewer dark mode: Toggle in header, persists to localStorage, respects prefers-color-scheme. Fixes hardcoded canvas colors for graph grid, labels, and tooltips.
  • Memory search previews: 2-line content preview with search term highlighting via <mark>. Concept tags shown inline (max 4 badges).
  • Token Savings card: Dashboard stat showing estimated savings vs full-context (observations * ~80 tokens vs sessions * TOKEN_BUDGET).
  • CLI status command: npx @agentmemory/agentmemory status shows health, sessions, graph stats, viewer URL without opening browser.
  • README "First Steps": Worked Session 1 → Session 2 example showing what agentmemory captures and how context injection works.
  • SkillKit install: npx skillkit install agentmemory for 32+ agents.

Test plan

  • All 646 tests pass
  • Build succeeds
  • Manual: open viewer :3113, toggle dark mode, verify graph canvas looks correct
  • Manual: search memories, verify preview + highlighting
  • Manual: check Token Savings card on dashboard
  • Manual: run npx @agentmemory/agentmemory status

Summary by CodeRabbit

  • New Features

    • SkillKit integration option for “Any agent” (32+ agents)
    • CLI status command for engine health, sessions, and graph stats
    • Dark theme toggle with persisted preference
    • Token savings metric in dashboard
    • Search highlighting and expanded memory previews with concept tags
  • Documentation

    • Added post-install “First Steps” guide with verification commands and real-time viewer walkthrough

…oken savings

Viewer:
- Dark mode toggle (persists to localStorage, respects prefers-color-scheme)
- Fix hardcoded canvas colors for dark theme (grid, labels, tooltips)
- Memory search shows 2-line content preview with search term highlighting
- Concept tags shown inline on memory cards (max 4)
- Token Savings stat card on dashboard (estimates savings vs full context)

CLI:
- New `agentmemory status` command — shows connection, health, sessions,
  graph stats, viewer URL without opening browser

README:
- SkillKit universal install: `npx skillkit install agentmemory` (32+ agents)
- "First Steps After Install" section with worked Session 1 → Session 2 example
- Shows actual compressed observation format and context injection
- "How to verify" checklist
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

Added a CLI status subcommand that probes the REST engine and renders health/sessions/graph stats; expanded README with a SkillKit Quick Start and post-install verification steps; enhanced the viewer UI with a dark theme toggle, richer memory previews with search highlighting and concept chips, and a "Token Savings" stat.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added Quick Start integration for "Any agent via SkillKit" (npx skillkit install agentmemory), "First Steps After Install" explaining silent post-hook memory building, example flows showing PostToolUse and SessionStart behavior, and concrete verification commands/links for status, health endpoint, and the real-time viewer.
CLI Status Command
src/cli.ts
Reworked CLI dispatch to agentmemory [command] [options], added status subcommand that checks engine reachability, concurrently fetches /agentmemory/health, /agentmemory/sessions, /agentmemory/graph/stats with 5s timeouts, and renders a formatted multi-line status report (health, session count, graph node/edge counts, circuit breaker state, heap MB, uptime, viewer URL). Updated help/usage output.
Viewer Theme & UX
src/viewer/index.html
Added dark-mode theme (CSS vars + html[data-theme="dark"]), theme toggle button with localStorage persistence and helper functions (isDarkMode, applyTheme, toggleTheme), theme-aware canvas/grid colors, enhanced memories table with two-line previews, <mark> search-term highlighting, concept chips, and a "Token Savings" dashboard card using tokenBudget URL param.

Sequence Diagram(s)

sequenceDiagram
    participant User as CLI User
    participant CLI as agentmemory CLI
    participant Engine as REST Engine
    participant Health as /agentmemory/health
    participant Sessions as /agentmemory/sessions
    participant Graph as /agentmemory/graph/stats

    User->>CLI: npx agentmemory status
    CLI->>Engine: probe engine (isEngineRunning)
    alt Engine reachable
        par Concurrent requests
            CLI->>Health: GET /agentmemory/health (5s timeout)
            CLI->>Sessions: GET /agentmemory/sessions (5s timeout)
            CLI->>Graph: GET /agentmemory/graph/stats (5s timeout)
        and
            Health-->>CLI: health payload
            Sessions-->>CLI: sessions payload
            Graph-->>CLI: graph stats
        end
        CLI->>CLI: format status report
        CLI->>User: print report + viewer URL
    else Engine unreachable
        CLI->>User: print error and exit 1
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐇 In tunnels warm I nibble logs and strings,
I toggle dark, I watch the agent's things.
A status ping, a memory saved with care—
Tokens spared, the viewer shows them there. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the three main changes: dark mode UI, the status CLI command, and memory preview improvements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dx-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 313-316: The two new fenced code blocks that currently start with
You: "Add JWT auth to the Express API" and the similar block later (the one
showing You:/Agent lines) are missing a language tag and trigger markdownlint
MD040; update each fence to use the text language identifier (change ``` to
```text) so the rendered output is unchanged but the MD040 warning is resolved.

In `@src/cli.ts`:
- Around line 260-270: The sessions count is computed from sessionsRes as if it
were an array, but the endpoint returns an object with a sessions array; update
the sessions computation in src/cli.ts so it checks sessionsRes?.sessions and
uses its length when it is an array (e.g., replace Array.isArray(sessionsRes) ?
sessionsRes.length : 0 with Array.isArray(sessionsRes?.sessions) ?
sessionsRes.sessions.length : 0), leaving the surrounding Promise.all and
health/version logic (healthRes, graphRes, h, status, version, memories)
unchanged.

In `@src/viewer/index.html`:
- Around line 1021-1026: The token-savings calculation hardcodes 2000 per
session (estInjected) instead of using the configured TOKEN_BUDGET; update the
logic that computes estInjected and the displayed subtitle to use the
TOKEN_BUDGET value (falling back to 2000 if TOKEN_BUDGET is undefined/invalid)
so savings and the "~X vs ~Y full" text reflect the actual budget; modify the
variables used in the block (totalObs, estFull, estInjected, savings and the
HTML string generation) to reference TOKEN_BUDGET rather than the literal 2000.
- Around line 817-826: applyTheme currently always writes to localStorage which
causes an auto-detected theme to be saved as a manual override; change
applyTheme to accept a second optional parameter (e.g., persist = false) and
only call localStorage.setItem when persist is true, update window.toggleTheme
to call applyTheme(!isDarkMode(), true) so user toggles persist, and on startup
call applyTheme(true) only if savedTheme exists (otherwise call
applyTheme(true/false based on prefers-color-scheme) with persist=false) so
auto-detection does not get persisted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 310c6c4b-ce01-4ebf-8aaa-2774e0797dd5

📥 Commits

Reviewing files that changed from the base of the PR and between 8c1890e and 75a2d35.

📒 Files selected for processing (3)
  • README.md
  • src/cli.ts
  • src/viewer/index.html

Comment thread README.md Outdated
Comment thread src/cli.ts
Comment thread src/viewer/index.html Outdated
Comment thread src/viewer/index.html Outdated
- README: add `text` language tag to fenced code blocks (MD040)
- cli.ts: sessions endpoint returns {sessions: [...]}, not a raw array
- viewer: token budget from URL param instead of hardcoded 2000
- viewer: applyTheme takes persist param, auto-detection doesn't save to
  localStorage (prevents OS preference from being overridden on first load)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/viewer/index.html (1)

768-768: Consider extracting inline styles to a CSS class.

The theme toggle button uses inline styles. For consistency with the rest of the codebase, consider defining a CSS class for the toggle button styling.

♻️ Suggested refactor

Add to CSS:

.btn-theme-toggle {
  font-size: 9px;
  padding: 3px 10px;
  letter-spacing: 0.1em;
  margin-right: 8px;
}

Then update the button:

-<button id="theme-toggle" class="btn" style="font-size:9px;padding:3px 10px;letter-spacing:0.1em;margin-right:8px;" onclick="toggleTheme()">DARK</button>
+<button id="theme-toggle" class="btn btn-theme-toggle" onclick="toggleTheme()">DARK</button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/viewer/index.html` at line 768, The inline styles on the theme toggle
button should be moved into a CSS class for consistency: create a CSS class
(e.g., .btn-theme-toggle) with the rules font-size:9px; padding:3px 10px;
letter-spacing:0.1em; margin-right:8px;, add that class to the element with id
"theme-toggle" (keeping the existing "btn" class and onclick="toggleTheme()"),
and remove the inline style attribute so styling is centralized and
maintainable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/viewer/index.html`:
- Around line 1023-1029: The tokenBudget in the viewer is read only from URL
params (the parseInt(new URLSearchParams(...).get('tokenBudget') ...) logic) and
can diverge from the server's TOKEN_BUDGET; update the viewer to prefer a
server-injected value (e.g. window.__TOKEN_BUDGET__ or a data-token-budget
attribute on a root element) before falling back to the URL/default, and modify
the server to inject TOKEN_BUDGET into the served HTML (or add documentation
advising to append ?tokenBudget=VALUE); specifically change the tokenBudget
assignment to first check the injected global/data value, then URL, then 2000,
and ensure the server template inserts the environment TOKEN_BUDGET into
window.__TOKEN_BUDGET__ or data-token-budget.

---

Nitpick comments:
In `@src/viewer/index.html`:
- Line 768: The inline styles on the theme toggle button should be moved into a
CSS class for consistency: create a CSS class (e.g., .btn-theme-toggle) with the
rules font-size:9px; padding:3px 10px; letter-spacing:0.1em; margin-right:8px;,
add that class to the element with id "theme-toggle" (keeping the existing "btn"
class and onclick="toggleTheme()"), and remove the inline style attribute so
styling is centralized and maintainable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53737d8b-8ff7-4abe-860f-8605dfa8e1a5

📥 Commits

Reviewing files that changed from the base of the PR and between 75a2d35 and 4c1184b.

📒 Files selected for processing (3)
  • README.md
  • src/cli.ts
  • src/viewer/index.html
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.md
  • src/cli.ts

Comment thread src/viewer/index.html
Comment on lines +1023 to +1029
var totalObs = d.sessions.reduce(function(a, s) { return a + (s.observationCount || 0); }, 0);
var tokenBudget = parseInt(new URLSearchParams(window.location.search).get('tokenBudget') || '2000', 10) || 2000;
var estFull = totalObs * 80;
var estInjected = d.sessions.length * tokenBudget;
var savings = estFull > 0 ? Math.round((1 - estInjected / Math.max(estFull, 1)) * 100) : 0;
if (savings < 0) savings = 0;
html += '<div class="stat-card"><div class="label">Token Savings</div><div class="value">' + savings + '%</div><div class="sub">~' + estInjected.toLocaleString() + ' vs ~' + estFull.toLocaleString() + ' full (budget: ' + tokenBudget + ')</div></div>';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

How do single-page applications typically pass server-side configuration values to client-side JavaScript?

💡 Result:

Single-page apps typically get server-side config into client JavaScript using one (or a mix) of these patterns:

  1. Inline <script> that assigns a global

    • Server renders something like window.APP_CONFIG = {...} (JSON-serialized) so the SPA can read it immediately during bootstrap. This is a commonly recommended approach when the values are needed on initial load. [1], [2]
  2. JSON embedded in the HTML (non-executing)

    • Server renders a <script type="application/json" ...> containing JSON; client code reads the tag’s text and JSON.parses it. Many frameworks/libraries use this to declaratively provide initial configuration. [3]
  3. data-* attributes on a DOM element

    • Server places values on the root element (or a dedicated element) like <div id="app" data-api-base="...">; client reads them via element.dataset. [4], [5]
  4. Fetch config from an endpoint at runtime

    • SPA starts with minimal HTML/JS, then calls something like /config.json (or an API route) to obtain environment-specific settings—useful when config must vary at deploy/runtime. (Often paired with one of the above for a “config URL” pointer.) [2]

Sources:
[1] Stack Overflow – “Best practice for passing server-side variables to javascript?” (stackoverflow.com)
[2] javaspring.net – “Best Ways to Pass Server-Side Variables to Client-Side JavaScript…” (javaspring.net)
[3] UI5 Web Components – “Configuration” (JSON config via <script type="application/json">) (ui5.github.io)
[4] MDN – “Use data attributes” (developer.mozilla.org)
[5] MDN – HTMLElement.dataset (developer.mozilla.org)

Citations:


🏁 Script executed:

# Search for TOKEN_BUDGET references in the codebase
rg "TOKEN_BUDGET" --no-heading -n

Repository: rohitg00/agentmemory

Length of output: 172


🏁 Script executed:

# Check the viewer directory structure and nearby configuration files
fd . src/viewer --type f -x basename {} \; | head -20

Repository: rohitg00/agentmemory

Length of output: 84


🏁 Script executed:

# Look for any server/backend code that might have TOKEN_BUDGET config
rg "tokenBudget|token.*budget" --no-heading -n -i

Repository: rohitg00/agentmemory

Length of output: 2507


🏁 Script executed:

# Check README or documentation files for deployment/configuration info
fd -e md -e txt -e json | xargs grep -l "token\|budget\|config" -i | head -10

Repository: rohitg00/agentmemory

Length of output: 208


🏁 Script executed:

# Check how the viewer is served - look at server.ts
cat -n src/viewer/server.ts | head -100

Repository: rohitg00/agentmemory

Length of output: 3462


🏁 Script executed:

# Also check if viewer HTML is embedded or referenced
rg "index.html" src/ -B 2 -A 2

Repository: rohitg00/agentmemory

Length of output: 905


🏁 Script executed:

# Check more of server.ts to see if it modifies HTML before serving
sed -n '95,150p' src/viewer/server.ts

Repository: rohitg00/agentmemory

Length of output: 1704


🏁 Script executed:

# Look for any pattern where server might inject config into responses
rg "html|HTML" src/viewer/server.ts -B 2 -A 2

Repository: rohitg00/agentmemory

Length of output: 664


🏁 Script executed:

# Check README for deployment instructions
sed -n '700,750p' README.md

Repository: rohitg00/agentmemory

Length of output: 1377


🏁 Script executed:

# Look for viewer-related documentation
rg "viewer|TOKEN_BUDGET" README.md -B 2 -A 2 | head -40

Repository: rohitg00/agentmemory

Length of output: 1800


Token budget calculation requires manual synchronization with server configuration.

The viewer reads tokenBudget from URL parameters (defaulting to 2000), but the server's actual TOKEN_BUDGET environment variable (configured at deployment) is not automatically synced to the viewer. If a deployment uses TOKEN_BUDGET=5000, the token savings estimates will be incorrect unless the URL is manually appended with ?tokenBudget=5000.

The server serves the viewer HTML as a static file without injecting the configured budget value. To fix this misalignment, either:

  • Have the server inject TOKEN_BUDGET into the viewer HTML (e.g., as a <script> tag or data-* attribute) when serving it, or
  • Document prominently that tokenBudget must be appended to the viewer URL to match the deployment's TOKEN_BUDGET setting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/viewer/index.html` around lines 1023 - 1029, The tokenBudget in the
viewer is read only from URL params (the parseInt(new
URLSearchParams(...).get('tokenBudget') ...) logic) and can diverge from the
server's TOKEN_BUDGET; update the viewer to prefer a server-injected value (e.g.
window.__TOKEN_BUDGET__ or a data-token-budget attribute on a root element)
before falling back to the URL/default, and modify the server to inject
TOKEN_BUDGET into the served HTML (or add documentation advising to append
?tokenBudget=VALUE); specifically change the tokenBudget assignment to first
check the injected global/data value, then URL, then 2000, and ensure the server
template inserts the environment TOKEN_BUDGET into window.__TOKEN_BUDGET__ or
data-token-budget.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant