Add Agents tab to dashboard#2
Conversation
- Collect agents from ~/.claude/agents/ (user-level) and .claude/agents/ (project-level) with YAML frontmatter parsing - Display agent metadata: name, description, model, color, memory - New Agents view tab between Skills and MCP Servers - Expandable agent items showing full prompt body - Search across agent names, descriptions, and content - 9 new tests for agent collection and UI integration (130 total) - Update README with agents feature and screenshot Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
📝 WalkthroughWalkthroughAgent support added: Markdown agent files with optional YAML frontmatter are parsed and aggregated from user and project agent directories via Changes
Sequence DiagramsequenceDiagram
participant Client
participant Server
participant DataModule as Data Module
participant FileSystem as File System
Client->>Server: GET /api/data
Server->>DataModule: collect_all_agents()
DataModule->>FileSystem: scan ~/.claude/agents
FileSystem-->>DataModule: list .md files
loop for each user agent file
DataModule->>FileSystem: read file
FileSystem-->>DataModule: file contents
DataModule->>DataModule: _read_agent_file() parse frontmatter/body
end
DataModule->>FileSystem: scan projects/*/.claude/agents
FileSystem-->>DataModule: list project .md files
loop for each project agent file
DataModule->>FileSystem: read file
FileSystem-->>DataModule: file contents
DataModule->>DataModule: _read_agent_file() parse frontmatter/body
end
DataModule->>DataModule: aggregate & deduplicate -> {user, projects}
DataModule-->>Server: return agents payload
Server->>Server: cache agents_json in DashboardState
Server-->>Client: respond with {version, data, skills, agents, mcp}
Client->>Client: populate AGENTS and render Agents view
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
tests/test_server.py (1)
393-393: Clean up unused tuple elements in test unpacking.Line 393 and Line 1872 unpack variables that are never used; replace unused names with
_-prefixed placeholders to keep lint output clean.Also applies to: 1872-1872
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_server.py` at line 393, The tuple unpacking of s.get() assigns variables that are not used (data_json, skills_json, agents_json, mcp_json, version); update those unpackings to use underscore-prefixed placeholders for unused elements (e.g., _data_json, _skills_json, _agents_json, _mcp_json, _version) wherever s.get() is unpacked so linters stop reporting unused-variable warnings (also apply the same change to the other occurrence of s.get() unpacking).src/claude_dashboard/data.py (1)
206-207: Narrow the exception type in agent file parsing.Line 206 swallows all exceptions, which can hide parser bugs. Catch expected read/OS errors only.
Proposed fix
def _read_agent_file(filepath): """Read an agent .md file and return its metadata from YAML frontmatter.""" try: content = filepath.read_text(errors="replace")[:5000] meta = {"name": filepath.stem, "content": content} @@ return meta - except Exception: + except OSError: return None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/claude_dashboard/data.py` around lines 206 - 207, Replace the broad "except Exception: return None" in the agent file parsing block with a narrow catch for expected I/O/parse errors (for example: except (OSError, IOError, FileNotFoundError, UnicodeDecodeError) as e:) so only filesystem or decoding issues return None; let unexpected exceptions propagate (or re-raise) so parser bugs surface. Keep the return None behavior for those expected errors and optionally log the caught error (include the exception variable e) for debugging.
🤖 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/claude_dashboard/server.py`:
- Around line 60-66: The agents cache is not covered by the directory
fingerprint so edits to ~/.claude/agents/*.md or .claude/agents/*.md won't
trigger refresh; update the fingerprinting logic (used by the watcher that
compares get_dir_fingerprint()) to include both user and project agent
directories and/or agent file globs, and ensure collect_all_agents() is
re-invoked when that fingerprint changes so self.agents_json (set inside the
with self.lock block) is refreshed automatically; reference
get_dir_fingerprint(), collect_all_agents(), and the self.agents_json assignment
to locate where to add those agent paths to the watched fingerprint set.
In `@src/claude_dashboard/ui.py`:
- Around line 1148-1159: Search currently only checks a.body for agent prompt
text so agents without frontmatter (which store text in a.content) are excluded;
update both places that build filtered (the userAgents filter and the
projectAgents p.agents filter) to include searchMatch(a.content || '', q) in the
predicate alongside a.body and a.description so renderable prompts in a.content
are matched by search.
---
Nitpick comments:
In `@src/claude_dashboard/data.py`:
- Around line 206-207: Replace the broad "except Exception: return None" in the
agent file parsing block with a narrow catch for expected I/O/parse errors (for
example: except (OSError, IOError, FileNotFoundError, UnicodeDecodeError) as e:)
so only filesystem or decoding issues return None; let unexpected exceptions
propagate (or re-raise) so parser bugs surface. Keep the return None behavior
for those expected errors and optionally log the caught error (include the
exception variable e) for debugging.
In `@tests/test_server.py`:
- Line 393: The tuple unpacking of s.get() assigns variables that are not used
(data_json, skills_json, agents_json, mcp_json, version); update those
unpackings to use underscore-prefixed placeholders for unused elements (e.g.,
_data_json, _skills_json, _agents_json, _mcp_json, _version) wherever s.get() is
unpacked so linters stop reporting unused-variable warnings (also apply the same
change to the other occurrence of s.get() unpacking).
🪄 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: 49c8b9ce-cb4f-47a3-980f-81ea5664febc
⛔ Files ignored due to path filters (1)
docs/agents.pngis excluded by!**/*.png
📒 Files selected for processing (5)
README.mdsrc/claude_dashboard/data.pysrc/claude_dashboard/server.pysrc/claude_dashboard/ui.pytests/test_server.py
…eptions - Add agent directories to get_dir_fingerprint() for auto-refresh - Fix agent search to include a.content for agents without frontmatter - Narrow except Exception to except OSError in _read_agent_file - Use _-prefixed names for unused tuple elements in tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/claude_dashboard/data.py (1)
406-407: Avoid blanketexcept Exception: passin new fingerprint branches.Catching all exceptions here can silently hide non-filesystem bugs. Prefer narrowing to expected filesystem errors (
OSError) and optionally logging at debug level.🔧 Proposed fix
- except Exception: + except OSError: pass @@ - except Exception: + except OSError: passAlso applies to: 422-423
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/claude_dashboard/data.py` around lines 406 - 407, Replace the blanket "except Exception: pass" in the new fingerprint branches with a narrow catch for filesystem errors (e.g., OSError) and log the exception at debug level, and let all other unexpected exceptions bubble up (or re-raise them); specifically locate the two try/except blocks that currently use "except Exception: pass" (the occurrences around lines 406-407 and 422-423 in src/claude_dashboard/data.py) and change them to "except OSError as e: logger.debug(...)" (or the module logger) while removing the silent swallow of non-filesystem errors.
🤖 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/claude_dashboard/data.py`:
- Around line 410-415: The fingerprint path is reconstructed incorrectly using
string ops on project_dir.name which can diverge from dirname_to_path(...) and
cause missed agent updates; in the loop over PROJECTS_DIR.iterdir() (variables
project_dir, real_path, agents_dir) replace the manual "/" +
project_dir.name.lstrip("-").replace("-", "/") logic with a call to the
canonical dirname_to_path(project_dir.name) (or the existing dirname_to_path
function used elsewhere) and ensure it returns the same leading slash/format
expected by agents_dir so that agents_dir =
Path(dirname_to_path(project_dir.name)) / ".claude" / "agents" correctly detects
changes.
In `@tests/test_server.py`:
- Line 381: The tuple unpacking assigns unused names which triggers lint
warnings; change the unpack of s.get() so intentionally-unused elements use
underscore placeholders (e.g., replace names like skills_json, agents_json,
mcp_json, version with _ or _<n> as appropriate) while keeping the used variable
data_json; update the assignment at the call site of s.get() to only bind
data_json and use underscores for other tuple positions to match the style used
later at line 393.
---
Nitpick comments:
In `@src/claude_dashboard/data.py`:
- Around line 406-407: Replace the blanket "except Exception: pass" in the new
fingerprint branches with a narrow catch for filesystem errors (e.g., OSError)
and log the exception at debug level, and let all other unexpected exceptions
bubble up (or re-raise them); specifically locate the two try/except blocks that
currently use "except Exception: pass" (the occurrences around lines 406-407 and
422-423 in src/claude_dashboard/data.py) and change them to "except OSError as
e: logger.debug(...)" (or the module logger) while removing the silent swallow
of non-filesystem errors.
🪄 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: 7b4fd4d7-8722-443e-bcdc-2ebfaa726654
📒 Files selected for processing (3)
src/claude_dashboard/data.pysrc/claude_dashboard/ui.pytests/test_server.py
✅ Files skipped from review due to trivial changes (1)
- src/claude_dashboard/ui.py
- Use dirname_to_path() instead of manual string replacement for consistent project path derivation in fingerprint - Prefix unused tuple elements with _ in test_dashboard_state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
tests/test_server.py (1)
1837-1856: Add fingerprint regression tests for agent file mutationsGood coverage for
collect_all_agents(), but the PR also adds fingerprint-driven refresh behavior for agent files (src/claude_dashboard/data.pyLine 396-423). A focused test for user/project agent file create/update would protect the watcher refresh gate from regressions.🧪 Suggested test additions
+def test_get_dir_fingerprint_detects_user_agent_change(tmp_path, monkeypatch): + claude_dir = tmp_path / "claude" + agents_dir = claude_dir / "agents" + agents_dir.mkdir(parents=True) + monkeypatch.setattr("claude_dashboard.data.CLAUDE_DIR", claude_dir) + monkeypatch.setattr("claude_dashboard.data.PROJECTS_DIR", tmp_path / "projects") + + fp1 = get_dir_fingerprint() + (agents_dir / "a.md").write_text("---\nname: a\n---\nPrompt") + fp2 = get_dir_fingerprint() + assert fp1 != fp2
🤖 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/claude_dashboard/data.py`:
- Around line 400-401: The loops that iterate user_agents_dir.iterdir() are
non-deterministic; change both iterations (the one at user_agents_dir.iterdir()
around the fingerprint/hash logic and the later loop at lines ~416-417) to
iterate over a deterministic, sorted list (e.g.,
sorted(user_agents_dir.iterdir(), key=lambda p: p.name or str(p))) so files are
processed in a stable order before hashing/processing; update references in
src/claude_dashboard/data.py where user_agents_dir.iterdir() is used (the two
occurrences) to use the sorted iterator instead.
- Around line 397-407: The current fingerprint-gathering block in
src/claude_dashboard/data.py silently swallows all exceptions (broad except
Exception: pass), which can hide scan failures and prevent watcher_thread() in
src/claude_dashboard/server.py from detecting changes; replace the broad excepts
around the directory scan with targeted exception handling (e.g., catch and
handle OSError, PermissionError) and/or log unexpected exceptions with
logger.exception (do not only pass), so failures are visible and the code
continues safely; ensure the logic around user_agents_dir, CLAUDE_DIR, and the
f.stat() call still appends valid entries but surfaces any unexpected errors
instead of suppressing them.
🪄 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: 36c0f973-754a-4b94-9b48-ff9e41da5134
📒 Files selected for processing (2)
src/claude_dashboard/data.pytests/test_server.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/claude_dashboard/data.py (1)
396-423:⚠️ Potential issue | 🟠 MajorSilent exception swallowing can stall agent refresh detection.
The broad
except Exception: passblocks (lines 406-407, 422-423) hide all scan failures. Becausewatcher_thread()only refreshes when the fingerprint changes (perserver.py:84-96), silently skipped scans can leave stale agent data indefinitely.🔧 Proposed fix
+import logging + +logger = logging.getLogger(__name__) + def get_dir_fingerprint(): """Get a hash of mtimes of all relevant files to detect changes.""" parts = [] ... # Track user-level agent files try: user_agents_dir = CLAUDE_DIR / "agents" if user_agents_dir.is_dir(): for f in sorted(user_agents_dir.iterdir()): if f.is_file() and f.suffix == ".md": try: parts.append(f"{f}:{f.stat().st_mtime}") except OSError: pass - except Exception: - pass + except OSError as e: + logger.debug("Skipping user agent fingerprint scan: %s", e) + # Track project-level agent files try: for project_dir in sorted(PROJECTS_DIR.iterdir()): if not project_dir.is_dir(): continue project_path = dirname_to_path(project_dir.name) agents_dir = Path(project_path) / ".claude" / "agents" if agents_dir.is_dir(): for f in sorted(agents_dir.iterdir()): if f.is_file() and f.suffix == ".md": try: parts.append(f"{f}:{f.stat().st_mtime}") except OSError: pass - except Exception: - pass + except OSError as e: + logger.debug("Skipping project agent fingerprint scan: %s", e) + return hashlib.md5("|".join(parts).encode()).hexdigest()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/claude_dashboard/data.py` around lines 396 - 423, The code currently swallows all exceptions in the user/global agent scan blocks (around user_agents_dir and PROJECTS_DIR loops), which can hide failures and prevent watcher_thread() from detecting changes; replace the broad "except Exception: pass" with specific exception handling (e.g., catch OSError, FileNotFoundError, PermissionError) and log the exception so failures are visible, and ensure the loops continue scanning other entries after an error (keep the inner try/except for f.stat() but log on failure and do not suppress unexpected errors silently); refer to user_agents_dir, PROJECTS_DIR, dirname_to_path, parts, and watcher_thread when making these changes.
🤖 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/claude_dashboard/data.py`:
- Around line 186-208: The YAML frontmatter parsing in _read_agent_file is
fragile; replace the manual line-by-line partitioning with a proper YAML parse:
import yaml (pyyaml) and call yaml.safe_load(frontmatter) to get a dict, then
map allowed keys ("name","description","model","color","memory") into meta and
set meta["body"] = body[:3000]; handle yaml.YAMLError by logging/returning None
or falling back to the current basic parse, and keep the existing OSError
handling; ensure you add pyyaml as a dependency and sanitize/truncate values as
before.
---
Duplicate comments:
In `@src/claude_dashboard/data.py`:
- Around line 396-423: The code currently swallows all exceptions in the
user/global agent scan blocks (around user_agents_dir and PROJECTS_DIR loops),
which can hide failures and prevent watcher_thread() from detecting changes;
replace the broad "except Exception: pass" with specific exception handling
(e.g., catch OSError, FileNotFoundError, PermissionError) and log the exception
so failures are visible, and ensure the loops continue scanning other entries
after an error (keep the inner try/except for f.stat() but log on failure and do
not suppress unexpected errors silently); refer to user_agents_dir,
PROJECTS_DIR, dirname_to_path, parts, and watcher_thread when making these
changes.
🪄 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: c9b377d8-c892-4ea9-bb20-0a03983a2753
📒 Files selected for processing (1)
src/claude_dashboard/data.py
Summary
~/.claude/agents/(user-level) and.claude/agents/(project-level)Test plan
~/.claude/agents/are listeduv run pytest— all 130 tests pass🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests