Skip to content

Commit fd91d12

Browse files
committed
docs: refine AGENTS.md with comprehensive project documentation
1 parent c4b606d commit fd91d12

File tree

1 file changed

+284
-51
lines changed

1 file changed

+284
-51
lines changed

AGENTS.md

Lines changed: 284 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,302 @@
11
# Agent Guidelines for vxcore
22

3+
## Project Overview
4+
5+
vxcore is a cross-platform C/C++ library providing notebook management functionality for VNote. It offers a stable C ABI for embedding in desktop (Qt), iOS (Swift), and Android (Kotlin) applications.
6+
7+
**Key Features**: Notebook management, folder/file operations, tag system, full-text search, JSON-based configuration.
8+
39
## Build Commands
4-
- **Configure**: `cmake -B build -DVXCORE_BUILD_TESTS=ON`
5-
- **Build**: `cmake --build build`
6-
- **Run all tests**: `ctest --test-dir build -C Debug` (Windows) or `ctest --test-dir build` (Unix)
7-
- **Run single module**: `ctest --test-dir build -C Debug -R test_core` or `test_notebook`
8-
- **Run with verbose**: `ctest --test-dir build -C Debug -V`
10+
11+
```bash
12+
# Configure
13+
cmake -B build -DVXCORE_BUILD_TESTS=ON
14+
15+
# Build
16+
cmake --build build
17+
18+
# Run all tests
19+
ctest --test-dir build -C Debug # Windows
20+
ctest --test-dir build # Unix
21+
22+
# Run single test module
23+
ctest --test-dir build -C Debug -R test_core
24+
ctest --test-dir build -C Debug -R test_notebook
25+
ctest --test-dir build -C Debug -R test_folder
26+
ctest --test-dir build -C Debug -R test_search
27+
ctest --test-dir build -C Debug -R test_db
28+
29+
# Run with verbose output
30+
ctest --test-dir build -C Debug -V
31+
```
932

1033
## Test Structure
11-
- Each module (core, notebook) has its own test executable
12-
- Individual test cases are tracked within each module's main()
13-
- Add new test cases to existing test_*.cpp files or create new modules as needed
34+
35+
- Each module has its own test executable: `test_core`, `test_notebook`, `test_folder`, `test_search`, `test_db`, etc.
36+
- Individual test cases tracked within each module's `main()`
37+
- Test macros defined in `tests/test_utils.h`: `ASSERT`, `ASSERT_EQ`, `ASSERT_NE`, `ASSERT_TRUE`, `ASSERT_FALSE`, `ASSERT_NULL`, `ASSERT_NOT_NULL`, `RUN_TEST`
1438
- **Test Mode**: All tests call `vxcore_set_test_mode(1)` to isolate test data
1539
- Enabled: Uses `%TEMP%\vxcore_test` (Windows) or `/tmp/vxcore_test` (Unix)
1640
- Disabled: Uses real AppData paths (`%APPDATA%\VNote`, `%LOCALAPPDATA%\VNote`)
1741
- CLI tools do NOT enable test mode (use production paths)
1842

1943
## Code Style
44+
2045
- **Language**: C++17 with C ABI for public API
2146
- **Formatting**: Use `.clang-format` based on Google style (indent 2 spaces, 100 col limit, pointer alignment right)
2247
- **Headers**: Sort includes; public API in `include/vxcore/`, implementation in `src/`
23-
- **Naming** (following Google C++ Style Guide):
24-
- **C API**: `snake_case` (e.g., `vxcore_context_create`)
25-
- **Types** (classes/structs/enums): `PascalCase` (e.g., `NotebookManager`, `VxCoreError`)
26-
- **Functions/Methods**: `PascalCase` (e.g., `GetNotebook()`, `CreateContext()`)
27-
- **Variables** (local/global): `snake_case` (e.g., `notebook_id`, `root_folder`)
28-
- **Class data members**: `snake_case_` with trailing underscore (e.g., `config_`, `notebooks_`)
29-
- **Struct data members**: `snake_case` without trailing underscore (e.g., `assets_folder`, `last_opened_timestamp`)
30-
- **Constants**: `kPascalCase` with leading k (e.g., `kMaxPathLength`, `kDefaultTimeout`)
31-
- **Enumerators**: `kPascalCase` with leading k (e.g., `kSuccess`, `kErrorInvalidArgument`)
32-
- **Macros**: `UPPER_CASE` (e.g., `VXCORE_API`, `RUN_TEST`)
33-
- **Namespaces**: `snake_case` (e.g., `vxcore`)
34-
- **Types**: Opaque handles (`VxCoreContextHandle`), enums for errors (`VxCoreError`)
35-
- **Error handling**: Return `VxCoreError` codes; check null pointers; use `(void)param` for unused
36-
- **Memory**: Caller frees strings with `vxcore_string_free()`; context owns handles
37-
- **Platform**: Use `VXCORE_API` macro for exports; Windows DLL-safe; no Qt dependencies
38-
- **JSON**: Communication boundary uses JSON over C ABI for cross-platform stability
39-
- **JSON keys**: Always use `camelCase` (e.g., `createdUtc`, `modifiedUtc`, `assetsFolder`)
40-
- **C++ struct members**: Use `snake_case` (e.g., `created_utc`, `modified_utc`, `assets_folder`)
41-
- **Rationale**: User-facing files (config.json, vx.json) follow JavaScript conventions
42-
- **Namespaces**: C++ code in `namespace vxcore`; close with `// namespace vxcore`
43-
- **File Format**: Use Unix line ending
48+
- **File Format**: Unix line endings
49+
50+
### Naming Conventions (Google C++ Style Guide)
51+
52+
| Element | Convention | Examples |
53+
|---------|------------|----------|
54+
| C API functions | `snake_case` | `vxcore_context_create`, `vxcore_notebook_open` |
55+
| Types (classes/structs/enums) | `PascalCase` | `NotebookManager`, `VxCoreError`, `FolderConfig` |
56+
| Functions/Methods | `PascalCase` | `GetNotebook()`, `CreateFolder()`, `ToJson()` |
57+
| Variables (local/global) | `snake_case` | `notebook_id`, `root_folder`, `out_config_json` |
58+
| Class data members | `snake_case_` (trailing underscore) | `config_`, `notebooks_`, `folder_manager_` |
59+
| Struct data members | `snake_case` (no trailing underscore) | `assets_folder`, `created_utc`, `parent_id` |
60+
| Constants | `kPascalCase` | `kMaxPathLength`, `kConfigFileName` |
61+
| Enumerators | `kPascalCase` | `kSuccess`, `kTrace`, `kDebug` |
62+
| Macros | `UPPER_CASE` | `VXCORE_API`, `RUN_TEST`, `VXCORE_LOG_INFO` |
63+
| Namespaces | `snake_case` | `vxcore`, `vxcore::db` |
64+
65+
### JSON Conventions
66+
67+
- **JSON keys**: Always use `camelCase` (e.g., `createdUtc`, `modifiedUtc`, `assetsFolder`, `rootFolder`)
68+
- **C++ struct members**: Use `snake_case` (e.g., `created_utc`, `modified_utc`, `assets_folder`)
69+
- **Rationale**: User-facing files (config.json, session.json) follow JavaScript conventions
70+
71+
### Error Handling
72+
73+
- Return `VxCoreError` codes from C API functions
74+
- Check null pointers; use `(void)param` for unused parameters
75+
- Caller frees strings with `vxcore_string_free()`
76+
- Context owns handles; destroy context to free all resources
77+
78+
### Platform
79+
80+
- Use `VXCORE_API` macro for exports; Windows DLL-safe
81+
- No Qt dependencies in core library
82+
- Namespaces: C++ code in `namespace vxcore`; close with `// namespace vxcore`
4483

4584
## Folder Structure
46-
- **`include/vxcore/`**: Public C API headers (`vxcore.h`, `vxcore_types.h`, `vxcore_events.h`)
47-
- **`src/api/`**: C API implementation (`vxcore_api.cpp`, `vxcore_*_api.cpp`, `error_handler.h`, `handle_manager.h`)
48-
- **`src/core/`**: Core C++ logic (`context.h`, `config_manager.h`, `notebook_manager.h`, `notebook.h`)
49-
- **Notebook Implementation**: `notebook.h` contains `NotebookConfig`, `NotebookRecord`, and `Notebook` class
50-
- `NotebookConfig`: Persistent configuration (id, name, description, folders, metadata)
51-
- `NotebookRecord`: Session metadata (id, root_folder, type)
52-
- `Notebook`: Represents a single notebook instance (bundled or raw type)
53-
- **NotebookManager**: Thread-safe manager for notebook lifecycle (create, open, close, list)
54-
- Uses `std::mutex` for thread-safety across all public methods
55-
- Manages in-memory notebook instances (`std::unordered_map<std::string, std::unique_ptr<Notebook>>`)
56-
- Syncs notebook records with session config via `session_config_updater_` callback
57-
- Bundled notebooks store config in `<root>/vx_notebook/config.json`
58-
- Raw notebooks store config in session config only
59-
- **`src/platform/`**: Platform-specific utilities (`path_provider.h`)
60-
- **`src/utils/`**: General utilities (`utils.h`)
61-
- **`cli/`**: CLI tool implementation (`main.cpp`, `notebook_cmd.h`, `json_helpers.h`)
62-
- **`tests/`**: Test executables (`test_core.cpp`, `test_notebook.cpp`)
63-
- **`third_party/`**: External dependencies (`nlohmann/json.hpp`)
85+
86+
```
87+
vxcore/
88+
├── include/vxcore/ # Public C API headers
89+
│ ├── vxcore.h # Main API (context, notebook, folder, file, tag, search)
90+
│ ├── vxcore_types.h # Error codes, handles, version struct
91+
│ ├── vxcore_events.h # Event types and callbacks
92+
│ └── vxcore_log.h # Logging API
93+
94+
├── src/
95+
│ ├── api/ # C API implementation layer
96+
│ │ ├── vxcore_api.cpp # Context, version, test mode
97+
│ │ ├── vxcore_notebook_api.cpp # Notebook operations
98+
│ │ ├── vxcore_folder_api.cpp # Folder/file operations
99+
│ │ ├── vxcore_tag_api.cpp # Tag operations
100+
│ │ ├── vxcore_search_api.cpp # Search operations
101+
│ │ ├── api_utils.h # API helper utilities
102+
│ │ ├── error_handler.h/.cpp # Error handling utilities
103+
│ │ └── handle_manager.h/.cpp # Handle management
104+
│ │
105+
│ ├── core/ # Core C++ business logic
106+
│ │ ├── context.h # VxCoreContext: owns ConfigManager + NotebookManager
107+
│ │ ├── config_manager.h/.cpp # VxCoreConfig + VxCoreSessionConfig management
108+
│ │ ├── vxcore_config.h/.cpp # Application config (vxcore.json)
109+
│ │ ├── vxcore_session_config.h/.cpp # Session config (session.json)
110+
│ │ ├── notebook_manager.h/.cpp # Notebook lifecycle (create, open, close, list)
111+
│ │ ├── notebook.h/.cpp # Notebook base class, NotebookConfig, NotebookRecord, TagNode
112+
│ │ ├── bundled_notebook.h/.cpp # Bundled notebook (config in vx_notebook/config.json)
113+
│ │ ├── raw_notebook.h/.cpp # Raw notebook (config in session only)
114+
│ │ ├── folder_manager.h # Abstract folder/file operations interface
115+
│ │ ├── bundled_folder_manager.h/.cpp # Folder ops for bundled notebooks
116+
│ │ ├── raw_folder_manager.h/.cpp # Folder ops for raw notebooks
117+
│ │ └── folder.h/.cpp # FolderConfig, FolderRecord, FileRecord
118+
│ │
119+
│ ├── db/ # SQLite database layer
120+
│ │ ├── db_manager.h/.cpp # Database lifecycle, schema, transactions
121+
│ │ ├── db_schema.h # Schema definitions (tables, indexes, FTS5)
122+
│ │ ├── file_db.h/.cpp # File/folder CRUD operations
123+
│ │ ├── tag_db.h/.cpp # Tag CRUD and queries
124+
│ │ └── sync_manager.h/.cpp # Filesystem ↔ database synchronization
125+
│ │
126+
│ ├── search/ # Search subsystem
127+
│ │ ├── search_manager.h/.cpp # Search orchestration
128+
│ │ ├── search_backend.h # ISearchBackend interface
129+
│ │ ├── simple_search_backend.h/.cpp # Built-in search implementation
130+
│ │ ├── rg_search_backend.h/.cpp # Ripgrep integration
131+
│ │ ├── search_query.h/.cpp # SearchQuery, SearchScope, SearchOption
132+
│ │ └── search_file_info.h/.cpp # SearchFileInfo struct
133+
│ │
134+
│ ├── platform/ # Platform-specific code
135+
│ │ ├── path_provider.h/.cpp # AppData, LocalData paths per platform
136+
│ │ └── process_utils.h/.cpp # External process execution (for rg)
137+
│ │
138+
│ └── utils/ # General utilities
139+
│ ├── utils.h/.cpp # GenerateUUID(), GetCurrentTimestampMillis(), HasFlag()
140+
│ ├── file_utils.h/.cpp # CleanPath(), ConcatenatePaths(), LoadJsonFile()
141+
│ ├── string_utils.h/.cpp # ToLowerString(), MatchesPattern(), exclude patterns
142+
│ └── logger.h/.cpp # VXCORE_LOG_* macros, Logger singleton
143+
144+
├── cli/ # Command-line interface
145+
│ ├── main.cpp # Entry point, command dispatch
146+
│ ├── args.h/.cpp # Argument parsing
147+
│ ├── notebook_cmd.h/.cpp # notebook subcommand
148+
│ ├── tag_cmd.h/.cpp # tag subcommand
149+
│ ├── config_cmd.h/.cpp # config subcommand
150+
│ └── json_helpers.h/.cpp # JSON formatting utilities
151+
152+
├── tests/ # Test executables
153+
│ ├── test_utils.h # Test macros and helpers
154+
│ ├── test_core.cpp # Context, config tests
155+
│ ├── test_notebook.cpp # Notebook CRUD tests
156+
│ ├── test_folder.cpp # Folder/file operation tests
157+
│ ├── test_search.cpp # Search tests
158+
│ ├── test_db.cpp # Database layer tests
159+
│ └── ...
160+
161+
├── third_party/ # External dependencies (DO NOT MODIFY)
162+
│ ├── nlohmann/json.hpp # JSON library
163+
│ └── sqlite/ # SQLite amalgamation
164+
165+
└── data/
166+
└── vxcore.json # Default configuration template
167+
```
64168

65169
## Architecture Notes
66-
- C ABI for cross-platform embedding (desktop/iOS/Android)
67-
- File-based notes with SQLite metadata (WAL + FTS5)
68-
- Event-driven with typed JSON notifications
69-
- Core plugins: Lua (logic); UI plugins: Python (Qt customization)
170+
171+
### Layered Architecture
172+
173+
```
174+
┌─────────────────────────────────────────────────┐
175+
│ C API Layer (include/vxcore/, src/api/) │ ← Stable ABI for FFI
176+
├─────────────────────────────────────────────────┤
177+
│ Core Layer (src/core/) │ ← Business logic
178+
├─────────────────────────────────────────────────┤
179+
│ Database Layer (src/db/) │ ← SQLite metadata
180+
├──────────────────────┬──────────────────────────┤
181+
│ Platform (src/platform/) │ Utils (src/utils/)│ ← Cross-cutting concerns
182+
└──────────────────────┴──────────────────────────┘
183+
```
184+
185+
### Key Design Patterns
186+
187+
1. **Context-based API**: All operations go through `VxCoreContextHandle`
188+
2. **Opaque handles**: C API uses opaque pointers for type safety
189+
3. **JSON boundaries**: All complex data crosses C ABI as JSON strings
190+
4. **Two notebook types**:
191+
- **Bundled**: Config stored in `<root>/vx_notebook/config.json`, metadata in `<root>/vx_notebook/`
192+
- **Raw**: Config stored in session config only, metadata in local data folder
193+
5. **FolderManager abstraction**: `BundledFolderManager` and `RawFolderManager` implement different storage strategies
194+
6. **Search backends**: Pluggable via `ISearchBackend` interface (ripgrep, simple built-in)
195+
196+
### Thread Safety
197+
198+
- `NotebookManager` operations are NOT thread-safe; caller must synchronize
199+
- `DbManager`, `FileDb`, `TagDb` are NOT thread-safe; designed for single-threaded use per notebook
200+
- `Logger` is thread-safe (uses mutex)
201+
202+
### Data Flow
203+
204+
```
205+
User Code
206+
207+
208+
C API (vxcore_*)
209+
210+
211+
VxCoreContext
212+
├── ConfigManager (VxCoreConfig, VxCoreSessionConfig)
213+
└── NotebookManager
214+
└── Notebook (Bundled/Raw)
215+
├── NotebookConfig (id, name, tags, metadata)
216+
├── FolderManager (folder/file operations)
217+
│ └── DbManager + FileDb + TagDb
218+
└── SearchManager (search operations)
219+
└── ISearchBackend (rg/simple)
220+
```
221+
222+
## Important Implementation Details
223+
224+
### Notebook Types
225+
226+
| Aspect | Bundled | Raw |
227+
|--------|---------|-----|
228+
| Config location | `<root>/vx_notebook/config.json` | Session config only |
229+
| Metadata folder | `<root>/vx_notebook/` | `<local_data>/notebooks/<id>/` |
230+
| Database location | `<metadata_folder>/metadata.db` | `<metadata_folder>/metadata.db` |
231+
| Portable | Yes (self-contained) | No (external metadata) |
232+
233+
### Path Handling
234+
235+
- Always use `CleanPath()` or `CleanFsPath()` to normalize paths
236+
- Paths use forward slashes internally (even on Windows)
237+
- Relative paths within notebook are relative to notebook root
238+
- Use `ConcatenatePaths()` to join path components
239+
240+
### Utility Functions (check before implementing)
241+
242+
- `src/utils/utils.h`: `GenerateUUID()`, `GetCurrentTimestampMillis()`, `HasFlag()`
243+
- `src/utils/file_utils.h`: `CleanPath()`, `LoadJsonFile()`, `ConcatenatePaths()`, `SplitPath()`, `RelativePath()`
244+
- `src/utils/string_utils.h`: `ToLowerString()`, `MatchesPattern()`, `MatchesPatterns()`
245+
- `src/utils/logger.h`: `VXCORE_LOG_TRACE/DEBUG/INFO/WARN/ERROR/FATAL`
246+
247+
### Logging
248+
249+
```cpp
250+
#include "utils/logger.h"
251+
252+
VXCORE_LOG_INFO("Opening notebook: %s", path.c_str());
253+
VXCORE_LOG_ERROR("Failed to open database: %s", db_path.c_str());
254+
```
255+
256+
## Common Patterns
257+
258+
### Adding a New C API Function
259+
260+
1. Declare in `include/vxcore/vxcore.h`
261+
2. Implement in appropriate `src/api/vxcore_*_api.cpp`
262+
3. Add tests in `tests/test_*.cpp`
263+
264+
### Adding a New Core Feature
265+
266+
1. Implement in `src/core/`
267+
2. Expose through existing managers or create new manager
268+
3. Add C API wrapper in `src/api/`
269+
4. Add tests
270+
271+
### Working with JSON
272+
273+
```cpp
274+
#include <nlohmann/json.hpp>
275+
276+
// Parsing
277+
nlohmann::json j = nlohmann::json::parse(json_string);
278+
auto config = NotebookConfig::FromJson(j);
279+
280+
// Serializing
281+
nlohmann::json j = config.ToJson();
282+
std::string json_string = j.dump();
283+
```
284+
285+
### Error Handling Pattern
286+
287+
```cpp
288+
VxCoreError MyFunction(const char* input, char** output) {
289+
if (!input || !output) {
290+
return VXCORE_ERR_NULL_POINTER;
291+
}
292+
293+
try {
294+
// ... implementation ...
295+
*output = strdup(result.c_str());
296+
return VXCORE_OK;
297+
} catch (const std::exception& e) {
298+
VXCORE_LOG_ERROR("MyFunction failed: %s", e.what());
299+
return VXCORE_ERR_UNKNOWN;
300+
}
301+
}
302+
```

0 commit comments

Comments
 (0)