feat(viz): add evolve viz serve — browse entities and trajectories locally - #187
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 48 minutes and 24 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds an "Evolve Viz" feature: a new Changes
Sequence DiagramsequenceDiagram
participant Browser as Browser Client
participant Server as HTTP Server (VizHandler)
participant Data as Data Loader (altk_evolve.viz.data)
participant FS as File System (.evolve/)
Browser->>Server: GET /
Server-->>Browser: Embedded React HTML
Browser->>Server: GET /api/trajectories
Server->>Data: load_trajectories(evolve_dir, entities)
Data->>FS: Read trajectories/*.json
Data-->>Server: Trajectory list JSON
Server-->>Browser: JSON response
Browser->>Server: GET /api/entities
Server->>Data: load_entities(evolve_dir)
Data->>FS: Read entities/*.md
Data-->>Server: Entity list JSON
Server-->>Browser: JSON response
Browser->>Server: GET /api/trajectories/[file] or /api/entities/[slug]
Server->>Data: load_trajectory_detail(...) / load_entity_detail(...)
Data->>FS: Read specific file
Data-->>Server: Detail JSON or None
Server-->>Browser: JSON response or 404/400
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 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 unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
altk_evolve/viz/server.py (3)
88-91: Consider callingserver.server_close()for clean shutdown.After catching
KeyboardInterrupt, the server socket isn't explicitly closed. While Python's garbage collection will handle this, explicit cleanup is better practice.♻️ Proposed fix
try: server.serve_forever() except KeyboardInterrupt: print("\nStopped.") + finally: + server.server_close()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@altk_evolve/viz/server.py` around lines 88 - 91, After catching KeyboardInterrupt from server.serve_forever(), explicitly call server.server_close() to ensure the underlying socket and resources are released; modify the except block handling KeyboardInterrupt in server.serve_forever() to call server.server_close() (and optionally log or print a shutdown message) before exiting to perform a clean shutdown.
509-512: Silent fetch errors may hide connectivity issues.The initial data fetches silently swallow errors with
.catch(() => {}). Consider logging or showing user feedback when the API is unreachable.💡 Optional: Add error state handling
useEffect(() => { - fetch('/api/trajectories').then(r => r.json()).then(setTrajectories).catch(() => {}); - fetch('/api/entities').then(r => r.json()).then(setEntities).catch(() => {}); + fetch('/api/trajectories').then(r => r.json()).then(setTrajectories).catch(e => console.error('Failed to load trajectories:', e)); + fetch('/api/entities').then(r => r.json()).then(setEntities).catch(e => console.error('Failed to load entities:', e)); }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@altk_evolve/viz/server.py` around lines 509 - 512, The current useEffect silently swallows network errors for the two initial fetches; update the effect that calls fetch('/api/trajectories') and fetch('/api/entities') to handle failures by logging the error and surfacing an error state instead of using .catch(() => {}): capture the error (e.g., catch(err => ...)), call console.error or processLogger with context ("fetch trajectories" / "fetch entities"), and set a React state like fetchError via setFetchError so the component can render a user-visible message or retry UI; ensure you reference the existing setTrajectories and setEntities state setters and add/initialize setFetchError in the same component.
104-106: CDN dependencies require internet connectivity.The frontend loads React, ReactDOM, and Babel from
unpkg.com. This means the viz server requires internet access to function. Consider noting this in documentation or bundling for offline use in the future.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@altk_evolve/viz/server.py` around lines 104 - 106, The HTML template in the viz server currently references React, ReactDOM and Babel via CDN script tags (https://unpkg.com/react@18..., react-dom@18..., `@babel/standalone`...) which forces internet access; either document this requirement or remove the CDN dependency by vendoring those files into the repo and updating the template to load local static assets (e.g., add files under static/vendor/react/*.js and change the script srcs in the viz server HTML template to /static/vendor/...); also ensure the server (altk_evolve.viz.server) serves that static directory and add a brief README note describing the offline/online behavior and fallback.altk_evolve/viz/data.py (1)
64-70: Broad exception handling silently skips malformed files.While this prevents the server from crashing on bad data, it makes debugging difficult. Consider logging a warning when entity files fail to parse.
💡 Optional: Add warning logging
+import logging + +logger = logging.getLogger(__name__) + def load_entities(evolve_dir: Path) -> list[dict]: """Load all entity files from <evolve_dir>/entities/.""" entities_dir = evolve_dir / "entities" if not entities_dir.exists(): return [] entities = [] for md_file in sorted(entities_dir.rglob("*.md")): try: entities.append(_parse_entity_file(md_file)) - except Exception: - pass + except Exception as e: + logger.warning(f"Failed to parse entity file {md_file}: {e}") return entities🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@altk_evolve/viz/data.py` around lines 64 - 70, The loop that builds entities by iterating over entities_dir.rglob("*.md") silently swallows all exceptions when calling _parse_entity_file, making failures hard to debug; change the except block to catch Exception as e and call the module logger (or process/module-level logger) to emit a warning that includes the filename (md_file) and the exception details (e/traceback) before continuing so malformed files are visible in logs while preserving the current behavior.altk_evolve/cli/cli.py (1)
554-563: Consider validatingevolve_direxists before starting the server.The server will start successfully even if the directory doesn't exist (data loaders return empty lists), which may confuse users. A warning or early validation would improve the developer experience.
💡 Optional: Add directory existence check
`@viz_app.command`("serve") def serve_viz( evolve_dir: Annotated[Path, typer.Option("--evolve-dir", "-d", help="Path to .evolve directory")] = Path(".evolve"), port: Annotated[int, typer.Option("--port", "-p", help="Port to serve on")] = 7891, no_browser: Annotated[bool, typer.Option("--no-browser", help="Don't open browser automatically")] = False, ): """Serve the Evolve Viz web interface for browsing entities and trajectories.""" from altk_evolve.viz.server import serve + if not evolve_dir.exists(): + console.print(f"[yellow]Warning: Directory '{evolve_dir}' does not exist. Server will show no data.[/yellow]") + serve(evolve_dir=evolve_dir.resolve(), port=port, open_browser=not no_browser)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@altk_evolve/cli/cli.py` around lines 554 - 563, In serve_viz, validate the evolve_dir Path before calling serve: resolve evolve_dir, check evolve_dir.exists() and evolve_dir.is_dir(), and if it doesn't exist either print a clear error/warning and exit (e.g., raise typer.Exit or call typer.secho) or create it if that’s desired; update the serve_viz function (and the call to serve in altk_evolve.viz.server) to perform this early validation so users aren’t served an empty UI when the .evolve directory is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@altk_evolve/viz/server.py`:
- Around line 33-37: The trajectory filename from the URL is being used directly
(in the handler where path startswith "/api/trajectories/") and passed to
load_trajectory_detail, creating a path traversal risk; ensure you
validate/sanitize filename before calling load_trajectory_detail: reject or 400
any filename that contains path separators or parent-up tokens (e.g., "/" or "\"
or ".."), or resolve the candidate path (self.evolve_dir / "trajectories" /
filename) and verify its absolute/realpath is inside the
evolve_dir/"trajectories" directory, then only call
load_trajectory_detail(filename) and self._serve_json(detail, ...). Reference
symbols: the request handler branch using path, filename, self.evolve_dir,
load_trajectory_detail, and _serve_json.
- Around line 40-43: The slug extracted from the request (in the branch that
calls load_entity_detail) is not validated and may contain path traversal or
glob characters; update the request handling so after unquoting the slug
(variable slug in the /api/entities/ branch) you validate/sanitize it before
calling load_entity_detail: reject or normalize slugs that contain path
separators ('/', '\') or glob metacharacters ('*', '?', '[') and return an
appropriate 400/NotFound response via self._serve_json (or treat as detail is
None) instead of passing unsafe values into load_entity_detail/rglob; ensure the
check is done where slug is set so load_entity_detail only receives safe slugs.
In `@docs/guides/viz.md`:
- Line 69: The link in the sentence that references "../integrations/index.md"
is broken; update the link target to the correct Evolve Lite integration doc by
replacing "../integrations/index.md" with
"../integrations/claude/evolve-lite.md" in the sentence that mentions the
`trajectory` frontmatter field (the line containing "Entities are linked to
their source trajectory via the `trajectory` frontmatter field"), or
alternatively add a new `docs/integrations/index.md` overview file and point the
link there so it resolves correctly.
---
Nitpick comments:
In `@altk_evolve/cli/cli.py`:
- Around line 554-563: In serve_viz, validate the evolve_dir Path before calling
serve: resolve evolve_dir, check evolve_dir.exists() and evolve_dir.is_dir(),
and if it doesn't exist either print a clear error/warning and exit (e.g., raise
typer.Exit or call typer.secho) or create it if that’s desired; update the
serve_viz function (and the call to serve in altk_evolve.viz.server) to perform
this early validation so users aren’t served an empty UI when the .evolve
directory is missing.
In `@altk_evolve/viz/data.py`:
- Around line 64-70: The loop that builds entities by iterating over
entities_dir.rglob("*.md") silently swallows all exceptions when calling
_parse_entity_file, making failures hard to debug; change the except block to
catch Exception as e and call the module logger (or process/module-level logger)
to emit a warning that includes the filename (md_file) and the exception details
(e/traceback) before continuing so malformed files are visible in logs while
preserving the current behavior.
In `@altk_evolve/viz/server.py`:
- Around line 88-91: After catching KeyboardInterrupt from
server.serve_forever(), explicitly call server.server_close() to ensure the
underlying socket and resources are released; modify the except block handling
KeyboardInterrupt in server.serve_forever() to call server.server_close() (and
optionally log or print a shutdown message) before exiting to perform a clean
shutdown.
- Around line 509-512: The current useEffect silently swallows network errors
for the two initial fetches; update the effect that calls
fetch('/api/trajectories') and fetch('/api/entities') to handle failures by
logging the error and surfacing an error state instead of using .catch(() =>
{}): capture the error (e.g., catch(err => ...)), call console.error or
processLogger with context ("fetch trajectories" / "fetch entities"), and set a
React state like fetchError via setFetchError so the component can render a
user-visible message or retry UI; ensure you reference the existing
setTrajectories and setEntities state setters and add/initialize setFetchError
in the same component.
- Around line 104-106: The HTML template in the viz server currently references
React, ReactDOM and Babel via CDN script tags (https://unpkg.com/react@18...,
react-dom@18..., `@babel/standalone`...) which forces internet access; either
document this requirement or remove the CDN dependency by vendoring those files
into the repo and updating the template to load local static assets (e.g., add
files under static/vendor/react/*.js and change the script srcs in the viz
server HTML template to /static/vendor/...); also ensure the server
(altk_evolve.viz.server) serves that static directory and add a brief README
note describing the offline/online behavior and fallback.
🪄 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: 86442d8d-b645-469a-a2da-1872067e9d92
📒 Files selected for processing (6)
altk_evolve/cli/cli.pyaltk_evolve/viz/__init__.pyaltk_evolve/viz/data.pyaltk_evolve/viz/server.pydocs/guides/viz.mddocs/reference/cli.md
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@altk_evolve/viz/data.py`:
- Around line 140-145: The slug lookup is ambiguous because
entities_dir.rglob(f"{slug}.md") can return multiple matches; replace the
current loop with a deterministic check: collect matches =
list(entities_dir.rglob(f"{slug}.md")), if len(matches) == 1 call and return
_parse_entity_file(matches[0]), if len(matches) == 0 return None, and if
len(matches) > 1 fail closed (return None or raise an explicit error) to avoid
nondeterministic behavior for entities_dir.rglob, slug, and _parse_entity_file.
- Around line 40-42: The variable content is currently sliced at the first "\n##
" heading which drops sections before the "## Rationale" header; change the
logic to look specifically for "\n## Rationale" (use body.find or similar) and
set content = body[: index_of_rationale].strip() when that heading exists,
otherwise fall back to the whole body; keep rationale_match and rationale
assignment as-is so rationale still comes from the regex if present.
🪄 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: a6ccd303-daaa-4ae5-bd8f-d5a6bc2636ea
📒 Files selected for processing (3)
altk_evolve/viz/data.pyaltk_evolve/viz/server.pydocs/guides/viz.md
✅ Files skipped from review due to trivial changes (1)
- docs/guides/viz.md
🚧 Files skipped from review as they are similar to previous changes (1)
- altk_evolve/viz/server.py
|
There is already some frontend https://github.com/AgentToolkit/altk-evolve/tree/main/altk_evolve/frontend. Can you comment on how is this different? |
The existing one is tied to the MCP server. This PR uses the filesystem. Also this PR shows trajectories. Not sure how much work it is to combine the two. |
|
Can we create an issue to replicate the functionality under full mcp frontend. |
|
Ask AI to mark the difference between this approach and the frontend/UI approach. Documented in #204 |
…cally
Adds altk_evolve/viz/ package and a new CLI subcommand:
evolve viz serve --evolve-dir .evolve [--port 7891] [--no-browser]
Starts a local HTTP server with an embedded React frontend (no build step)
for exploring the .evolve/ directory:
- Left sidebar lists all trajectories and guidelines
- Click any item to open the full detail view on the right
- Trajectory view shows the full chat transcript with tool calls collapsible,
plus pills linking to any guidelines extracted from that session
- Guideline view shows content, rationale, trigger, and a link back to its
source trajectory
- Hash-based routing (#t/{file}, #e/{slug}) — URLs reflect the current view,
are bookmarkable, and support browser back/forward
- All nav links are real <a> tags — right-click → Open in New Tab works
Files added:
altk_evolve/viz/__init__.py — package init
altk_evolve/viz/data.py — load entities/trajectories from .evolve/,
cross-link via entity frontmatter trajectory field
altk_evolve/viz/server.py — stdlib HTTP server + embedded React/Babel app
altk_evolve/cli/cli.py — viz_app Typer sub-app with serve command
docs/guides/viz.md — guide covering layout, navigation, URL routing
docs/reference/cli.md — viz section with commands and options
- VizHandler.evolve_dir: ClassVar[Optional[Path]] = None (was Path = None, which pyright rejects as incompatible assignment) - ruff format data.py and server.py
Addresses CodeRabbit review finding: Path traversal vulnerability in trajectory filename handling Addresses CodeRabbit review finding: Entity slug should also be validated against path traversal and glob injection
Addresses CodeRabbit review finding: Fix broken documentation link on line 69
Addresses CodeRabbit review finding: `content` is cut at the first heading instead of `## Rationale`
Addresses CodeRabbit review finding: Slug lookup is ambiguous when duplicate `*.md` stems exist
|
@visahak Good question — the two web interfaces serve different purposes:
In short: Documented the full comparison in #204 for tracking consolidation decisions. |
For #180
Adds a local web server for exploring the
.evolve/directory — trajectories and the guidelines extracted from them.What's included
evolve viz serve— new CLI subcommand that starts a local HTTP server (stdlib only, no extra deps) with an embedded React frontend:UI features:
#t/{file},#e/{slug}) — bookmarkable URLs, browser back/forward, right-click → Open in New TabFiles added:
Relation to #180
This surfaces the provenance data that the
trajectoryfrontmatter field (added in #184) captures. The full #180 scope (provenance in the MCP API, richer lineage queries, etc.) is not addressed here.Summary by CodeRabbit
New Features
Documentation