-
Notifications
You must be signed in to change notification settings - Fork 284
feat: add knowledge files support for additional project context #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: add knowledge files support for additional project context #48
Conversation
Add ability to upload markdown files to provide additional context to the agent during development sessions. Backend changes: - Add API endpoints for knowledge file CRUD (list, get, upload, delete) - Add Pydantic schemas for knowledge file operations - Files stored in project's knowledge/ directory Prompt changes: - Update coding prompt to read knowledge files at session start - Update initializer prompt to read knowledge files before creating features Closes leonvanzyl#22 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a React component for managing knowledge files in the UI: - KnowledgeFilesModal with full CRUD operations (create, view, edit, delete) - API client functions for knowledge file endpoints - React Query hooks for data fetching and mutations - Keyboard shortcut 'K' to open knowledge files - BookOpen icon button in header when project is selected Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR implements a knowledge file management system for projects, enabling users to upload, view, edit, list, and delete markdown files within each project's knowledge directory. The feature includes backend endpoints, API layer, React Query hooks, and a full-featured modal UI with keyboard shortcuts. Changes
Sequence DiagramssequenceDiagram
actor User
participant App as App.tsx
participant Modal as KnowledgeFilesModal
participant Hooks as React Query Hooks
participant API as API Layer
participant Server as Backend Server
participant FS as File System
User->>App: Click Knowledge Files Button (or press K)
App->>Modal: Show Modal
Modal->>Hooks: useKnowledgeFiles(projectName)
Hooks->>API: listKnowledgeFiles()
API->>Server: GET /projects/{name}/knowledge
Server->>FS: Read knowledge/ directory
FS-->>Server: File list with metadata
Server-->>API: KnowledgeFileList
API-->>Hooks: Return file list
Hooks-->>Modal: Display files
User->>Modal: Click Edit on File
Modal->>Hooks: useKnowledgeFile(projectName, filename)
Hooks->>API: getKnowledgeFile()
API->>Server: GET /projects/{name}/knowledge/{filename}
Server->>FS: Read file content
FS-->>Server: File content
Server-->>API: KnowledgeFileContent
API-->>Hooks: Return content
Hooks-->>Modal: Load into editor
User->>Modal: Save Changes
Modal->>Hooks: useUploadKnowledgeFile()
Hooks->>API: uploadKnowledgeFile()
API->>Server: POST /projects/{name}/knowledge
Server->>FS: Write file
FS-->>Server: Success
Server-->>API: Updated file
API-->>Hooks: Confirm
Hooks-->>Modal: Refresh list
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @server/routers/projects.py:
- Around line 389-398: The import "from datetime import datetime" is inside the
loop that builds files from knowledge_dir.glob("*.md"), causing repeated import
overhead; move that import out of the loop (preferably to the module top with
other imports) and remove the in-loop import statement so the loop that appends
KnowledgeFile(name=filepath.name, size=stat.st_size,
modified=datetime.fromtimestamp(stat.st_mtime)) uses the already-imported
datetime.
In @ui/src/components/KnowledgeFilesModal.tsx:
- Around line 439-454: The modal uses aria-labelledby="knowledge-files-title"
but no element has that id; update the heading rendered by renderList to include
id="knowledge-files-title" so the dialog label reference resolves, and consider
assigning dynamic ids for headings in renderView and renderEdit (e.g.,
knowledge-files-title--view and knowledge-files-title--edit) and using those ids
when viewMode === "view" or "edit" to keep the aria-labelledby reference
accurate across modes; locate renderList, renderView, renderEdit and the modal
container to add the ids and switch the aria-labelledby value accordingly if you
implement dynamic ids.
🧹 Nitpick comments (3)
ui/src/components/KnowledgeFilesModal.tsx (3)
54-59: Consider guarding against overwriting in-progress edits.This effect syncs
fileContenttoeditContentwheneverfileContentchanges in edit mode. If the backend data updates while a user is editing (e.g., from another tab), their local changes would be silently overwritten. Consider tracking whether the user has made local edits to prevent this.
61-82: Potential duplicate Escape key handling with parent component.This component adds its own Escape handler while
App.tsxalso handles Escape. Since neither callse.stopPropagation(), pressing Escape in view/edit mode navigates back to list here, but may also trigger the parent's handler. Consider callinge.stopPropagation()after handling the key to prevent the event from propagating.♻️ Suggested fix
const handleEscape = (e: KeyboardEvent) => { if (e.key === "Escape") { + e.stopPropagation(); if (deleteConfirm) { setDeleteConfirm(null); } else if (viewMode !== "list") { setViewMode("list"); setSelectedFile(null); setNewFileName(""); setEditContent(""); } else { onClose(); } } };
231-253: Action buttons are hidden from keyboard users.The file action buttons (View, Edit, Delete) use
opacity-0 group-hover:opacity-100, making them invisible to keyboard-only users who can't trigger hover states. Consider keeping them visible but perhaps more subtle, or making them visible on focus-within.♻️ Suggested fix
- <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity"> + <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity">
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.claude/templates/coding_prompt.template.md.claude/templates/initializer_prompt.template.mdserver/routers/projects.pyserver/schemas.pyui/src/App.tsxui/src/components/KnowledgeFilesModal.tsxui/src/hooks/useProjects.tsui/src/lib/api.tsui/src/lib/types.ts
🧰 Additional context used
📓 Path-based instructions (4)
ui/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
ui/src/**/*.{ts,tsx}: Use TypeScript for React components in the UI (React 18 with TypeScript)
Use React Query (TanStack Query) for API calls and data fetching in the UI
Use Radix UI for component primitives in the React UI
Run ESLint to lint React UI code
Files:
ui/src/components/KnowledgeFilesModal.tsxui/src/App.tsxui/src/hooks/useProjects.tsui/src/lib/api.tsui/src/lib/types.ts
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use SQLite with SQLAlchemy ORM for database access and feature management
Files:
server/schemas.pyserver/routers/projects.py
.claude/templates/**/*.template.md
📄 CodeRabbit inference engine (CLAUDE.md)
Prompt templates should follow a fallback chain: project-specific in {project_dir}/prompts/{name}.md, then base template in .claude/templates/{name}.template.md
Files:
.claude/templates/initializer_prompt.template.md.claude/templates/coding_prompt.template.md
server/routers/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use FastAPI for REST API endpoints in the server/routers/ directory
Files:
server/routers/projects.py
🧠 Learnings (5)
📚 Learning: 2026-01-10T08:23:04.012Z
Learnt from: CR
Repo: leonvanzyl/autocoder PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T08:23:04.012Z
Learning: Two-agent pattern: Initializer Agent reads app spec and creates features in first session; Coding Agent implements features one by one in subsequent sessions
Applied to files:
ui/src/App.tsx
📚 Learning: 2026-01-10T08:23:04.012Z
Learnt from: CR
Repo: leonvanzyl/autocoder PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T08:23:04.012Z
Learning: Applies to .claude/templates/**/*.template.md : Prompt templates should follow a fallback chain: project-specific in {project_dir}/prompts/{name}.md, then base template in .claude/templates/{name}.template.md
Applied to files:
.claude/templates/initializer_prompt.template.md
📚 Learning: 2026-01-10T08:23:04.012Z
Learnt from: CR
Repo: leonvanzyl/autocoder PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T08:23:04.012Z
Learning: Applies to ui/src/**/*.{ts,tsx} : Use React Query (TanStack Query) for API calls and data fetching in the UI
Applied to files:
ui/src/hooks/useProjects.ts
📚 Learning: 2026-01-10T08:23:04.012Z
Learnt from: CR
Repo: leonvanzyl/autocoder PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T08:23:04.012Z
Learning: Applies to mcp_server/**/*.py : Use MCP (Model Context Protocol) servers for agent tools: feature_mcp.py for feature management, with tools: feature_get_stats, feature_get_next, feature_get_for_regression, feature_mark_passing, feature_skip, feature_create_bulk
Applied to files:
.claude/templates/coding_prompt.template.md
📚 Learning: 2026-01-10T08:23:04.012Z
Learnt from: CR
Repo: leonvanzyl/autocoder PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T08:23:04.012Z
Learning: Applies to server/routers/**/*.py : Use FastAPI for REST API endpoints in the server/routers/ directory
Applied to files:
server/routers/projects.py
🧬 Code graph analysis (4)
ui/src/components/KnowledgeFilesModal.tsx (2)
ui/src/hooks/useProjects.ts (4)
useKnowledgeFiles(304-310)useKnowledgeFile(312-321)useUploadKnowledgeFile(323-340)useDeleteKnowledgeFile(342-354)ui/src/lib/types.ts (1)
KnowledgeFile(367-371)
server/schemas.py (1)
ui/src/lib/types.ts (3)
KnowledgeFile(367-371)KnowledgeFileList(373-376)KnowledgeFileContent(378-381)
server/routers/projects.py (4)
ui/src/lib/types.ts (3)
KnowledgeFile(367-371)KnowledgeFileContent(378-381)KnowledgeFileList(373-376)server/schemas.py (4)
KnowledgeFile(279-283)KnowledgeFileContent(292-295)KnowledgeFileList(286-289)KnowledgeFileUpload(298-301)registry.py (1)
get_project_path(275-293)server/routers/agent.py (1)
validate_project_name(50-57)
ui/src/lib/types.ts (3)
server/schemas.py (15)
ProjectSummary(42-47)ProjectStats(34-39)ProjectDetail(50-56)DriveInfo(234-238)DirectoryEntry(241-248)DirectoryListResponse(251-256)PathValidationResponse(259-266)ProjectPrompts(59-63)FeatureListResponse(101-105)FeatureCreate(85-87)AgentStatus(138-144)AgentActionResponse(147-151)WSLogMessage(185-189)ImageAttachment(206-227)SettingsUpdate(329-339)api/database.py (1)
Feature(19-44)registry.py (1)
Settings(90-96)
🪛 LanguageTool
.claude/templates/initializer_prompt.template.md
[style] ~22-~22: Consider a different adjective to strengthen your wording.
Context: ...es, or reference materials that provide deeper understanding of the project. ```bash ...
(DEEP_PROFOUND)
🔇 Additional comments (27)
.claude/templates/initializer_prompt.template.md (1)
12-29: LGTM!The knowledge file discovery step is well-implemented:
- Gracefully handles missing
knowledge/directory with stderr redirect and fallback message- The shell loop correctly checks file existence before reading to handle the case where no
.mdfiles exist- Clear instructions for the agent to incorporate knowledge content into feature creation
.claude/templates/coding_prompt.template.md (2)
25-36: LGTM!The knowledge file discovery step is correctly integrated into the coding agent's orientation workflow. The shell commands are consistent with the initializer prompt template, providing a unified approach to reading knowledge files across agent sessions.
42-46: LGTM!Step numbering correctly updated to reflect the new knowledge file discovery step (now step 6), shifting subsequent MCP tool steps to 7 and 8.
ui/src/lib/types.ts (1)
363-381: LGTM!The new Knowledge File types are correctly defined and align with the corresponding Pydantic schemas in
server/schemas.py:
KnowledgeFile.modifiedis correctly typed asstringto match the JSON-serializeddatetimefrom PythonKnowledgeFileListandKnowledgeFileContentfields match their server counterpartsserver/schemas.py (1)
279-301: LGTM!The Knowledge File schemas are well-designed:
KnowledgeFilecaptures essential file metadataKnowledgeFileUploadincludes proper validation:
- The filename pattern
^[a-zA-Z0-9_\-\.]+\.md$provides effective path traversal protection by disallowing/,\, and..sequencesmin_length=1on content prevents empty file uploadsui/src/hooks/useProjects.ts (1)
304-354: LGTM!The new Knowledge Files hooks follow React Query best practices:
- Properly use array-based query keys for cache management
- Correctly guard queries with
enabledflags when dependencies are nullable- Mutations appropriately invalidate the list query on success
- Consistent with the existing hook patterns in the file
Based on learnings, these hooks correctly use React Query (TanStack Query) for API calls and data fetching.
ui/src/App.tsx (5)
1-24: LGTM on imports and setup.The new imports for
KnowledgeFilesModalandBookOpenicon are correctly added. Minor note: theSTORAGE_KEYconstant on line 8 sits between import blocks, which is unconventional but consistent with the existing pattern in this file.
136-140: LGTM on keyboard shortcut.The 'K' shortcut follows the same pattern as other project-specific shortcuts and correctly guards on
selectedProject.
143-159: LGTM on escape handling.The escape key handling correctly prioritizes closing the Knowledge Files modal before other modals, following the established pattern.
227-234: LGTM on header button.The Knowledge Files button is well-implemented with proper accessibility attributes (
title,aria-label) and consistent styling with the adjacent Settings button.
375-381: LGTM on modal rendering.The
KnowledgeFilesModalis correctly rendered with proper guards and props, following the established pattern for other modals in the application.ui/src/components/KnowledgeFilesModal.tsx (7)
41-52: LGTM on hooks integration.The React Query hooks are properly integrated with appropriate conditional fetching logic. The
useKnowledgeFilequery is correctly enabled only when in view or edit mode with a selected file.
100-120: LGTM on save logic.The save function correctly handles both create and edit modes, enforces the
.mdextension, and properly resets state on success.
122-132: LGTM on delete logic.The delete handler correctly resets the view state when the currently selected file is deleted.
134-148: LGTM on helper functions.The formatting functions for file size and date are correctly implemented using appropriate JavaScript APIs.
262-294: LGTM on delete confirmation dialog.The delete confirmation modal properly handles pending state, disables buttons during deletion, and shows appropriate loading feedback.
298-341: LGTM on view mode rendering.The view mode correctly handles loading states and displays markdown content with appropriate formatting.
343-437: LGTM on edit/create mode rendering.The edit view correctly handles both create and edit modes, with appropriate conditional UI, input validation, and error feedback.
server/routers/projects.py (4)
364-366: LGTM on knowledge directory helper.Simple and correct helper function for constructing the knowledge directory path.
421-429: LGTM on filename validation and path traversal protection.The regex
^[a-zA-Z0-9_\-\.]+\.md$effectively prevents path traversal by disallowing/and\characters. The validation is consistent with the schema definition inserver/schemas.py.
438-462: LGTM on upload endpoint.The upload endpoint correctly relies on Pydantic schema validation for the filename and properly creates the knowledge directory if it doesn't exist. The endpoint correctly returns the uploaded content.
465-494: LGTM on delete endpoint.The delete endpoint properly validates the filename, checks for file existence, and handles errors appropriately.
ui/src/lib/api.ts (5)
24-26: LGTM on type imports.The new Knowledge File types are correctly imported and will be used by the new API functions.
366-370: LGTM on list function.Correctly calls the knowledge files list endpoint with proper URL encoding.
372-379: LGTM on get function.Correctly encodes both the project name and filename in the URL path.
381-390: LGTM on upload function.Correctly posts the filename and content as JSON, matching the backend's
KnowledgeFileUploadschema.
392-402: LGTM on delete function.Correctly encodes path parameters and uses the DELETE method.
| files = [] | ||
| for filepath in knowledge_dir.glob("*.md"): | ||
| if filepath.is_file(): | ||
| stat = filepath.stat() | ||
| from datetime import datetime | ||
| files.append(KnowledgeFile( | ||
| name=filepath.name, | ||
| size=stat.st_size, | ||
| modified=datetime.fromtimestamp(stat.st_mtime) | ||
| )) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Move import outside the loop.
The from datetime import datetime import on line 393 is inside the loop, causing repeated import overhead. Move it to the top of the file or function.
♻️ Suggested fix
Move the import to the top of the file with other imports:
import re
import shutil
import sys
+from datetime import datetime
from pathlib import PathThen remove line 393.
🤖 Prompt for AI Agents
In @server/routers/projects.py around lines 389 - 398, The import "from datetime
import datetime" is inside the loop that builds files from
knowledge_dir.glob("*.md"), causing repeated import overhead; move that import
out of the loop (preferably to the module top with other imports) and remove the
in-loop import statement so the loop that appends
KnowledgeFile(name=filepath.name, size=stat.st_size,
modified=datetime.fromtimestamp(stat.st_mtime)) uses the already-imported
datetime.
| return ( | ||
| <div className="neo-modal-backdrop" onClick={onClose} role="presentation"> | ||
| <div | ||
| ref={modalRef} | ||
| className="neo-modal w-full max-w-2xl p-6" | ||
| onClick={(e) => e.stopPropagation()} | ||
| role="dialog" | ||
| aria-labelledby="knowledge-files-title" | ||
| aria-modal="true" | ||
| > | ||
| {viewMode === "list" && renderList()} | ||
| {viewMode === "view" && renderView()} | ||
| {(viewMode === "edit" || viewMode === "create") && renderEdit()} | ||
| </div> | ||
| </div> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing id for aria-labelledby reference.
The modal declares aria-labelledby="knowledge-files-title" but no element has this id. Add the id to the heading in renderList.
🔧 Suggested fix in renderList (line 154)
- <h2 className="font-display text-xl font-bold">Knowledge Files</h2>
+ <h2 id="knowledge-files-title" className="font-display text-xl font-bold">Knowledge Files</h2>Note: The headings in renderView and renderEdit would also benefit from dynamic id assignment if they should serve as the accessible label in those modes.
🤖 Prompt for AI Agents
In @ui/src/components/KnowledgeFilesModal.tsx around lines 439 - 454, The modal
uses aria-labelledby="knowledge-files-title" but no element has that id; update
the heading rendered by renderList to include id="knowledge-files-title" so the
dialog label reference resolves, and consider assigning dynamic ids for headings
in renderView and renderEdit (e.g., knowledge-files-title--view and
knowledge-files-title--edit) and using those ids when viewMode === "view" or
"edit" to keep the aria-labelledby reference accurate across modes; locate
renderList, renderView, renderEdit and the modal container to add the ids and
switch the aria-labelledby value accordingly if you implement dynamic ids.
…ure leonvanzyl#48 - Created useTheme hook with React Context for shared theme state - Added ThemeProvider to wrap app for shared state management - Added theme toggle button to Sidebar with sun/moon icons - Theme persists to localStorage as 'open-autocoder-theme' - Sidebar, main content, and HomePage all respond to theme changes - Supports system preference fallback when no user preference set Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
This PR adds the ability to upload markdown files to provide additional context to the agent during development sessions, addressing issue #22.
Changes
Backend (API):
server/routers/projects.py:GET /{name}/knowledge- List all knowledge filesGET /{name}/knowledge/{filename}- Get file contentPOST /{name}/knowledge- Upload a new markdown fileDELETE /{name}/knowledge/{filename}- Delete a fileserver/schemas.pyknowledge/directoryPrompt Updates:
coding_prompt.template.mdto instruct the agent to read knowledge files at the start of each sessioninitializer_prompt.template.mdto read knowledge files before creating featuresUsage
Users can upload markdown files (requirements docs, design specs, research notes, etc.) via the API. The agent will automatically read these files at the start of each session to better understand the project context.
Note
The UI component for uploading/managing knowledge files would be a separate enhancement - this PR adds the backend infrastructure and prompt integration.
Closes #22
🤖 Generated with Claude Code
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.