5 DevelopmentGuide
Jeff Smith edited this page 2026-04-11 10:25:19 -06:00

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.pyformat_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 via unittest.mock — no real filesystem calls needed
  • Tests that require real filesystem interaction use tempfile.mkdtemp() and clean up automatically

Adding tests for new modules

  1. Create tests/test_<module>.py
  2. Import from luminos_lib.<module>
  3. Use unittest.TestCase subclasses
  4. Mock subprocess calls with unittest.mock.patch("subprocess.run", ...)
  5. 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