Development Guide
This page covers how to set up, run, and test Luminos. For a code-level walkthrough of how the AI pipeline actually works — the dir loop, the cache, the survey pass, where to add a tool — read Internals.
Setup
# One-time setup: creates ~/luminos-env and installs requirements.txt
./setup_env.sh
# Activate the venv in subsequent sessions
source ~/luminos-env/bin/activate
# Set your Anthropic API key
export ANTHROPIC_API_KEY=your-key-here
Or do it by hand:
python3 -m venv ~/luminos-env
source ~/luminos-env/bin/activate
pip install -r requirements.txt
The base scan also shells out to GNU coreutils (wc, file, grep, head,
tail, stat, du, find), so they need to be on $PATH.
Running Luminos
python3 luminos.py <target>
That is the whole interface. AI runs unconditionally on every invocation.
Common flags
python3 luminos.py --fresh <target> # ignore cached results
python3 luminos.py --clear-cache # wipe /tmp/luminos/
python3 luminos.py -x .git -x node_modules <target> # exclude dirs
python3 luminos.py -d 8 -a <target> # depth 8, include hidden
python3 luminos.py --json -o report.json <target> # JSON output
If ANTHROPIC_API_KEY is unset, luminos exits cleanly with a one-line hint.
Git Workflow
Every change starts on a branch. Nothing goes directly to main.
Branch naming
<type>/<short-description>
| Type | Use |
|---|---|
feat/ |
New feature or capability |
fix/ |
Bug fix |
refactor/ |
Restructure without behavior change |
chore/ |
Tooling, config, documentation |
test/ |
Tests |
Examples: feat/survey-pass, fix/cache-flush-on-error, refactor/synthesis-tiers
Commit messages
<type>: <short description>
Examples:
feat: add web_search tool to dir loop
fix: handle empty dir cache gracefully in synthesis
refactor: extract survey pass into _run_survey()
chore: update Architecture wiki page
One commit per logical unit of work, not one per file.
Merge procedure
PRs are merged via the Forgejo API or web UI, not local git merge. See
~/.claude/CLAUDE.md for the full branching discipline.
Testing
Running tests
python3 -m unittest discover -s tests/ -v
The test suite uses stdlib unittest only.
Test coverage
Tests live in tests/, one file per module (ai.py has its own pure-helper file):
| Test file | Module covered |
|---|---|
test_cache.py |
cache.py — entry validation, confidence fields, investigation IDs |
test_filetypes.py |
filetypes.py — extension classification, classify_files, summarize_categories |
test_code.py |
code.py — language detection, LOC counting, large file detection |
test_disk.py |
disk.py — disk usage parsing, _human_size, top_directories |
test_recency.py |
recency.py — recent file detection, output parsing |
test_tree.py |
tree.py — tree building, rendering, hidden/exclude logic |
test_report.py |
report.py — format_flags, format_report, all sections |
test_ai_pure.py |
ai.py (pure helpers) — _filter_dir_tools, _format_survey_block, _format_survey_signals, _default_survey, _should_skip_dir, _path_is_safe, _block_to_dict, _flush_partial_dir_entry |
Modules not covered (exempt from unit testing):
| Module | Reason |
|---|---|
ai.py (loops) |
End-to-end dir/synthesis/survey loops require a live Anthropic API. Pure helpers in ai.py are covered by test_ai_pure.py. |
ast_parser.py |
Imports tree-sitter grammars at module load |
prompts.py |
String templates with no logic |
Test requirements
- Every change to a covered module must include or update its tests
- All tests must pass before merging to main
- Subprocess-heavy functions (
wc,du,find,file) are tested viaunittest.mock— no real filesystem calls needed - Tests that require real filesystem interaction use
tempfile.mkdtemp()and clean up automatically
Adding tests for new modules
- Create
tests/test_<module>.py - Import from
luminos_lib.<module> - Use
unittest.TestCasesubclasses - Mock subprocess calls with
unittest.mock.patch("subprocess.run", ...) - Add the new file to the table above
Naming Conventions
| Context | Convention | Example |
|---|---|---|
| Functions / variables | snake_case | classify_files, dir_path |
| Classes | PascalCase | _TokenTracker, _CacheManager |
| Constants | UPPER_SNAKE_CASE | MAX_CONTEXT, CACHE_ROOT |
| Module files | snake_case | ast_parser.py, filetypes.py |
| CLI flags | kebab-case | --clear-cache, --fresh |
| Private functions | leading underscore | _run_synthesis, _build_dir_context |
Project Structure
luminos/
├── luminos.py entry point
├── requirements.txt anthropic, tree-sitter + grammars, python-magic
├── setup_env.sh venv + dependency setup script
├── luminos_lib/
│ ├── ai.py AI pipeline (heaviest module)
│ ├── ast_parser.py tree-sitter parsing
│ ├── cache.py investigation cache management (incl. clear_cache)
│ ├── code.py language + LOC detection
│ ├── disk.py disk usage
│ ├── filetypes.py file classification
│ ├── prompts.py AI system prompt templates
│ ├── recency.py recently modified files
│ ├── report.py terminal report formatter
│ └── tree.py directory tree
├── tests/
│ ├── test_ai_pure.py
│ ├── test_cache.py
│ ├── test_code.py
│ ├── test_disk.py
│ ├── test_filetypes.py
│ ├── test_recency.py
│ ├── test_report.py
│ └── test_tree.py
├── docs/wiki/ local clone of Forgejo wiki (gitignored)
├── CLAUDE.md Claude Code context (thin — points to wiki)
└── PLAN.md evolution plan and design notes
Wiki
Wiki lives at docs/wiki/ (gitignored — separate git repo).
# First time
git clone ssh://git@forgejo-claude/archeious/luminos.wiki.git docs/wiki/
# Returning
git -C docs/wiki pull
Wiki URL: https://forgejo.labbity.unbiasedgeek.com/archeious/luminos/wiki
When updating wiki pages:
cd docs/wiki
# edit pages
git add -A
git commit -m "wiki: <description>"
git push