pip install -e .
pip install pytest pytest-cov- Web server:
gangdanorgangdan --port 8080(default :5000) - CLI REPL:
gangdan cli - Programmatic:
python -m gangdan - Entry routing:
gangdan/cli.py:main()routes CLI subcommands tocli_app.py, web server toapp.py
Both GUI and CLI share these modules:
config.py- GlobalCONFIGobject loaded once at import timeollama_client.py- Ollama API wrapper (chat, embed, stream)chroma_manager.py- ChromaDB with auto-recovery on corruptionconversation.py- Chat history with auto-save threaddoc_manager.py- Documentation downloader/indexerweb_searcher.py- DuckDuckGo/SearXNG/Brave search
Self-contained Flask Blueprint with three features:
/question- Question generator (MCQ, short answer, etc.)/guide- Guided learning sessions/research- Multi-phase research reports
- Lazy imports for optional dependencies (inside functions)
- Environment variables must be set BEFORE importing modules that use them (especially
GANGDAN_DATA_DIR) - Global CONFIG is shared across modules; do not reinitialize
- Streaming responses use generators with
yield - Thread safety: locks for shared mutable state
- Language support: all UI strings use
TRANSLATIONSdict - No linting tools; follow existing code style
pytest # All tests
pytest -v # Verbose
pytest -k "test_config" # By name pattern
pytest --cov=gangdan # With coverage
pytest -x # Stop on first failurepytest tests/test_core_config.py::TestConfigDataclass::test_config_defaults -vtemp_data_dir- Isolated temp directory, setsGANGDAN_DATA_DIRmock_ollama_available/mock_ollama_unavailable- Mock Ollama APImock_chroma_client- Mock ChromaDB clientcli_runner- Helper to run CLI commands and capture output
- Set environment variables BEFORE importing gangdan modules
- All tests run offline with mocked external services
- 142 tests covering core modules and CLI
python -m build # Build sdist and wheel
python publish.py release # Prepare for upload
twine upload dist/* # Upload to PyPIimport json
from pathlib import Path
from typing import Any, Dict, List, Optional
import pytest
from flask import Flask
from gangdan.core.config import CONFIG- Required on all function signatures
- Use
str | None(Python 3.10+) butOptional[str]for compatibility - Use
List[str],Dict[str, Any]fromtyping
- Classes:
PascalCase - Functions:
snake_case - Constants:
UPPER_CASE - Private methods:
_leading_underscore - Test classes:
Test<Feature> - Test functions:
test_<behavior>
- Google-style or reStructuredText
- Include Parameters, Returns, Raises sections
- Module docstrings at top of each file
- Line length: 120 characters
- f-strings for formatting
- LF line endings (
.batfiles use CRLF) - Final newline required
try/exceptfor external API calls (Ollama, file I/O)- Return
ToolResult(success=False, error=str(e))for API functions - Raise exceptions for invalid arguments in internal functions
- Log errors to
sys.stderrwith context prefix - Never silently swallow exceptions
@dataclass
class ToolResult:
success: bool
data: Any = None
error: Optional[str] = None
metadata: dict = field(default_factory=dict)- Commit messages: imperative mood ("Add feature", "Fix bug")
- Atomic commits
- Run
pytest -xbefore committing - No direct commits to main without review