learnx-cli 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- learnx_cli-0.3.0/.claude/agents/README.md +32 -0
- learnx_cli-0.3.0/.claude/agents/implementation.md +17 -0
- learnx_cli-0.3.0/.claude/agents/product_check.md +111 -0
- learnx_cli-0.3.0/.claude/agents/quality.md +15 -0
- learnx_cli-0.3.0/.claude/agents/regression_check.md +22 -0
- learnx_cli-0.3.0/.claude/agents/simplification.md +15 -0
- learnx_cli-0.3.0/.claude/agents/testing.md +15 -0
- learnx_cli-0.3.0/.claude/agents/verify_fixes.md +20 -0
- learnx_cli-0.3.0/.claude/settings.assisted.json +27 -0
- learnx_cli-0.3.0/.claude/settings.json +26 -0
- learnx_cli-0.3.0/.dockerignore +19 -0
- learnx_cli-0.3.0/.github/workflows/ci.yml +80 -0
- learnx_cli-0.3.0/.gitignore +71 -0
- learnx_cli-0.3.0/.pre-commit-config.yaml +7 -0
- learnx_cli-0.3.0/CLAUDE.md +144 -0
- learnx_cli-0.3.0/DEVLOOP.md +214 -0
- learnx_cli-0.3.0/Dockerfile +45 -0
- learnx_cli-0.3.0/PKG-INFO +240 -0
- learnx_cli-0.3.0/README.md +215 -0
- learnx_cli-0.3.0/README_v1.md +438 -0
- learnx_cli-0.3.0/agile.png +0 -0
- learnx_cli-0.3.0/dev_setup/README.md +48 -0
- learnx_cli-0.3.0/dev_setup/autonomy_plan.md +285 -0
- learnx_cli-0.3.0/dev_setup/container_plan.md +105 -0
- learnx_cli-0.3.0/dev_setup/context_hygiene_plan.md +266 -0
- learnx_cli-0.3.0/dev_setup/handoff_template.md +297 -0
- learnx_cli-0.3.0/dev_setup/run_example.md +272 -0
- learnx_cli-0.3.0/dev_setup/sandbox_plan.md +311 -0
- learnx_cli-0.3.0/dev_setup/spec-driven_plan.md +277 -0
- learnx_cli-0.3.0/devloop.toml +47 -0
- learnx_cli-0.3.0/fixes/fix001.md +41 -0
- learnx_cli-0.3.0/fixes/fix002.md +52 -0
- learnx_cli-0.3.0/fixes/fix003.md +42 -0
- learnx_cli-0.3.0/fixes/fix004.md +31 -0
- learnx_cli-0.3.0/fixes/fix005.md +35 -0
- learnx_cli-0.3.0/fixes/fix006.md +36 -0
- learnx_cli-0.3.0/fixes/fix007.md +44 -0
- learnx_cli-0.3.0/fixes/fix008.md +35 -0
- learnx_cli-0.3.0/fixes/fix009.md +45 -0
- learnx_cli-0.3.0/fixes/fix010.md +36 -0
- learnx_cli-0.3.0/fixes/fix011.md +37 -0
- learnx_cli-0.3.0/fixes/fix012.md +40 -0
- learnx_cli-0.3.0/fixes/fix013.md +82 -0
- learnx_cli-0.3.0/fixes/fix014.md +48 -0
- learnx_cli-0.3.0/fixes/fix015.md +36 -0
- learnx_cli-0.3.0/fixes/fix016.md +73 -0
- learnx_cli-0.3.0/fixes/fix017.md +77 -0
- learnx_cli-0.3.0/fixes/fix018.md +90 -0
- learnx_cli-0.3.0/fixes/fix019.md +110 -0
- learnx_cli-0.3.0/fixes/fix020.md +73 -0
- learnx_cli-0.3.0/fixes/fix021.md +69 -0
- learnx_cli-0.3.0/fixes/fix022.md +56 -0
- learnx_cli-0.3.0/fixes/fix023.md +68 -0
- learnx_cli-0.3.0/fixes/fix024.md +61 -0
- learnx_cli-0.3.0/fixes/fix025.md +58 -0
- learnx_cli-0.3.0/fixes/fix026.md +47 -0
- learnx_cli-0.3.0/fixes/fix027.md +40 -0
- learnx_cli-0.3.0/fixes/fix028.md +51 -0
- learnx_cli-0.3.0/fixes/fix029.md +58 -0
- learnx_cli-0.3.0/fixes/fix030.md +53 -0
- learnx_cli-0.3.0/fixes/fix031.md +58 -0
- learnx_cli-0.3.0/fixes/fix032.md +52 -0
- learnx_cli-0.3.0/fixes/fix033.md +46 -0
- learnx_cli-0.3.0/fixes/fix034.md +59 -0
- learnx_cli-0.3.0/fixes/fix035.md +72 -0
- learnx_cli-0.3.0/fixes/fix036.md +87 -0
- learnx_cli-0.3.0/fixes/fix037.md +58 -0
- learnx_cli-0.3.0/fixes/fix038.md +88 -0
- learnx_cli-0.3.0/fixes/fix039.md +71 -0
- learnx_cli-0.3.0/fixes/fix040.md +67 -0
- learnx_cli-0.3.0/fixes/fix041.md +74 -0
- learnx_cli-0.3.0/learnX.png +0 -0
- learnx_cli-0.3.0/learning/javaConcept.md +117 -0
- learnx_cli-0.3.0/plan/devloop_cli_plan.md +284 -0
- learnx_cli-0.3.0/plan/devloop_packaging_plan.md +209 -0
- learnx_cli-0.3.0/plan/v0_plan.md +179 -0
- learnx_cli-0.3.0/plan/v10_plan.md +112 -0
- learnx_cli-0.3.0/plan/v11_plan.md +118 -0
- learnx_cli-0.3.0/plan/v12_plan.md +134 -0
- learnx_cli-0.3.0/plan/v1_plan.md +1961 -0
- learnx_cli-0.3.0/plan/v2_plan.md +454 -0
- learnx_cli-0.3.0/plan/v3_plan.md +1132 -0
- learnx_cli-0.3.0/plan/v4_architecture.md +252 -0
- learnx_cli-0.3.0/plan/v4_plan.md +137 -0
- learnx_cli-0.3.0/plan/v4_update_plan.md +187 -0
- learnx_cli-0.3.0/plan/v5_plan.md +125 -0
- learnx_cli-0.3.0/plan/v6_plan.md +120 -0
- learnx_cli-0.3.0/plan/v7_plan.md +151 -0
- learnx_cli-0.3.0/plan/v8_plan.md +115 -0
- learnx_cli-0.3.0/plan/v9_plan.md +115 -0
- learnx_cli-0.3.0/pyproject.toml +67 -0
- learnx_cli-0.3.0/scripts/__init__.py +0 -0
- learnx_cli-0.3.0/scripts/devloop.py +206 -0
- learnx_cli-0.3.0/scripts/dk/__init__.py +0 -0
- learnx_cli-0.3.0/scripts/dk/config.py +69 -0
- learnx_cli-0.3.0/scripts/dk/dashboard.py +190 -0
- learnx_cli-0.3.0/scripts/dk/docker.py +96 -0
- learnx_cli-0.3.0/scripts/dk/notifier.py +127 -0
- learnx_cli-0.3.0/scripts/dk/process.py +95 -0
- learnx_cli-0.3.0/scripts/dk/runners.py +315 -0
- learnx_cli-0.3.0/scripts/run_review.py +315 -0
- learnx_cli-0.3.0/scripts/test_openrouter_models.py +221 -0
- learnx_cli-0.3.0/scripts/tests/__init__.py +0 -0
- learnx_cli-0.3.0/scripts/tests/conftest.py +10 -0
- learnx_cli-0.3.0/scripts/tests/test_cli.py +145 -0
- learnx_cli-0.3.0/scripts/tests/test_devloop.py +215 -0
- learnx_cli-0.3.0/scripts/tests/test_docker_commands.py +173 -0
- learnx_cli-0.3.0/scripts/tests/test_notifier.py +271 -0
- learnx_cli-0.3.0/scripts/tests/test_review_agents.py +263 -0
- learnx_cli-0.3.0/scripts/tests/test_version_runner.py +176 -0
- learnx_cli-0.3.0/specs/v0/day0.md +207 -0
- learnx_cli-0.3.0/specs/v0/day1.md +123 -0
- learnx_cli-0.3.0/specs/v0/day2.md +176 -0
- learnx_cli-0.3.0/specs/v0/day3.md +266 -0
- learnx_cli-0.3.0/specs/v1/day1.md +588 -0
- learnx_cli-0.3.0/specs/v1/day2.md +339 -0
- learnx_cli-0.3.0/specs/v1/day3.md +488 -0
- learnx_cli-0.3.0/specs/v1/day4.md +490 -0
- learnx_cli-0.3.0/specs/v1/day5.md +463 -0
- learnx_cli-0.3.0/specs/v1/day6.md +426 -0
- learnx_cli-0.3.0/specs/v1/day7.md +822 -0
- learnx_cli-0.3.0/specs/v1/explain-mode.md +225 -0
- learnx_cli-0.3.0/specs/v10/day28.md +363 -0
- learnx_cli-0.3.0/specs/v10/day29.md +236 -0
- learnx_cli-0.3.0/specs/v11/day30.md +411 -0
- learnx_cli-0.3.0/specs/v11/day31.md +311 -0
- learnx_cli-0.3.0/specs/v12/day1.md +578 -0
- learnx_cli-0.3.0/specs/v12/day2.md +486 -0
- learnx_cli-0.3.0/specs/v12/day3.md +350 -0
- learnx_cli-0.3.0/specs/v12/day4.md +355 -0
- learnx_cli-0.3.0/specs/v2/day10.md +380 -0
- learnx_cli-0.3.0/specs/v2/day11.md +334 -0
- learnx_cli-0.3.0/specs/v2/day12.md +370 -0
- learnx_cli-0.3.0/specs/v2/day8.md +253 -0
- learnx_cli-0.3.0/specs/v2/day9.md +222 -0
- learnx_cli-0.3.0/specs/v3/day13.md +242 -0
- learnx_cli-0.3.0/specs/v3/day14.md +364 -0
- learnx_cli-0.3.0/specs/v3/day15.md +396 -0
- learnx_cli-0.3.0/specs/v3/day16.md +363 -0
- learnx_cli-0.3.0/specs/v3/day16_extra.md +355 -0
- learnx_cli-0.3.0/specs/v4/day17.md +175 -0
- learnx_cli-0.3.0/specs/v4-workflow/day0.md +138 -0
- learnx_cli-0.3.0/specs/v4-workflow/day1.md +157 -0
- learnx_cli-0.3.0/specs/v4-workflow/day1_preparation.md +83 -0
- learnx_cli-0.3.0/specs/v4-workflow/day2.md +207 -0
- learnx_cli-0.3.0/specs/v4-workflow/day2b.md +428 -0
- learnx_cli-0.3.0/specs/v4-workflow/day3.md +488 -0
- learnx_cli-0.3.0/specs/v4-workflow/day4.md +228 -0
- learnx_cli-0.3.0/specs/v4-workflow/day5.md +248 -0
- learnx_cli-0.3.0/specs/v4-workflow/day6.md +182 -0
- learnx_cli-0.3.0/specs/v4-workflow/day7.md +231 -0
- learnx_cli-0.3.0/specs/v5/day18.md +224 -0
- learnx_cli-0.3.0/specs/v5/day19.md +248 -0
- learnx_cli-0.3.0/specs/v6/day20.md +424 -0
- learnx_cli-0.3.0/specs/v6/day21.md +163 -0
- learnx_cli-0.3.0/specs/v7/day22.md +303 -0
- learnx_cli-0.3.0/specs/v7/day23.md +320 -0
- learnx_cli-0.3.0/specs/v8/day24.md +443 -0
- learnx_cli-0.3.0/specs/v8/day25.md +235 -0
- learnx_cli-0.3.0/specs/v9/day26.md +345 -0
- learnx_cli-0.3.0/specs/v9/day27.md +230 -0
- learnx_cli-0.3.0/tutor/.env copy.example +4 -0
- learnx_cli-0.3.0/tutor/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/__main__.py +4 -0
- learnx_cli-0.3.0/tutor/assets/__init__.py +5 -0
- learnx_cli-0.3.0/tutor/assets/html/fonts/Inter-Bold.woff2 +0 -0
- learnx_cli-0.3.0/tutor/assets/html/fonts/Inter-Regular.woff2 +0 -0
- learnx_cli-0.3.0/tutor/assets/html/fonts/Inter-SemiBold.woff2 +0 -0
- learnx_cli-0.3.0/tutor/assets/html/fonts/JetBrainsMono-Regular.woff2 +0 -0
- learnx_cli-0.3.0/tutor/assets/html/highlight-java.min.js +2 -0
- learnx_cli-0.3.0/tutor/assets/html/highlight-javascript.min.js +2 -0
- learnx_cli-0.3.0/tutor/assets/html/highlight-python.min.js +2 -0
- learnx_cli-0.3.0/tutor/assets/html/highlight.min.js +17 -0
- learnx_cli-0.3.0/tutor/assets/html/mermaid.min.js +31 -0
- learnx_cli-0.3.0/tutor/assets/html/slide_base.css +464 -0
- learnx_cli-0.3.0/tutor/assets/html/theme-learnx-dark.css +12 -0
- learnx_cli-0.3.0/tutor/audio/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/audio/audio_builder.py +143 -0
- learnx_cli-0.3.0/tutor/audio/sanitizer.py +9 -0
- learnx_cli-0.3.0/tutor/audio/tts_renderer.py +54 -0
- learnx_cli-0.3.0/tutor/cli/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/cli/commands.py +391 -0
- learnx_cli-0.3.0/tutor/cli/logo.py +21 -0
- learnx_cli-0.3.0/tutor/cli/playback_commands.py +239 -0
- learnx_cli-0.3.0/tutor/cli/shell.py +91 -0
- learnx_cli-0.3.0/tutor/cli/shell_context.py +18 -0
- learnx_cli-0.3.0/tutor/cli/theme.py +39 -0
- learnx_cli-0.3.0/tutor/cli/video_commands.py +123 -0
- learnx_cli-0.3.0/tutor/config.py +122 -0
- learnx_cli-0.3.0/tutor/conftest.py +5 -0
- learnx_cli-0.3.0/tutor/constants.py +82 -0
- learnx_cli-0.3.0/tutor/exceptions.py +26 -0
- learnx_cli-0.3.0/tutor/generation/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/generation/assembler.py +81 -0
- learnx_cli-0.3.0/tutor/generation/curriculum.py +97 -0
- learnx_cli-0.3.0/tutor/generation/dialogue.py +172 -0
- learnx_cli-0.3.0/tutor/generation/narrator.py +122 -0
- learnx_cli-0.3.0/tutor/generation/segment_parser.py +223 -0
- learnx_cli-0.3.0/tutor/generation/segment_planner.py +200 -0
- learnx_cli-0.3.0/tutor/generation/visual_planner.py +205 -0
- learnx_cli-0.3.0/tutor/infra/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/infra/llm.py +152 -0
- learnx_cli-0.3.0/tutor/ingestion/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/ingestion/chunker.py +171 -0
- learnx_cli-0.3.0/tutor/ingestion/doc_analyzer.py +41 -0
- learnx_cli-0.3.0/tutor/ingestion/parse_content.py +19 -0
- learnx_cli-0.3.0/tutor/ingestion/summarizer.py +51 -0
- learnx_cli-0.3.0/tutor/inspector.py +117 -0
- learnx_cli-0.3.0/tutor/llm_config.toml +58 -0
- learnx_cli-0.3.0/tutor/models.py +147 -0
- learnx_cli-0.3.0/tutor/player/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/player/input_handler.py +45 -0
- learnx_cli-0.3.0/tutor/player/player.py +308 -0
- learnx_cli-0.3.0/tutor/player/player_display.py +117 -0
- learnx_cli-0.3.0/tutor/prompts/curriculum.txt +67 -0
- learnx_cli-0.3.0/tutor/prompts/dialogue.txt +62 -0
- learnx_cli-0.3.0/tutor/prompts/narrate.txt +34 -0
- learnx_cli-0.3.0/tutor/prompts/qa.txt +17 -0
- learnx_cli-0.3.0/tutor/prompts/summarize.txt +9 -0
- learnx_cli-0.3.0/tutor/prompts/visual.txt +60 -0
- learnx_cli-0.3.0/tutor/prompts/visual_v3.txt +91 -0
- learnx_cli-0.3.0/tutor/qa/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/qa/qa.py +105 -0
- learnx_cli-0.3.0/tutor/requirements-dev.txt +2 -0
- learnx_cli-0.3.0/tutor/requirements.txt +12 -0
- learnx_cli-0.3.0/tutor/sample_docs/headingless_large.md +1 -0
- learnx_cli-0.3.0/tutor/sample_docs/headingless_test.md +1 -0
- learnx_cli-0.3.0/tutor/sample_docs/java-basics.md +78 -0
- learnx_cli-0.3.0/tutor/tests/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/audio/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/audio/test_audio_builder.py +106 -0
- learnx_cli-0.3.0/tutor/tests/audio/test_sanitizer.py +41 -0
- learnx_cli-0.3.0/tutor/tests/cli/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/cli/test_commands.py +67 -0
- learnx_cli-0.3.0/tutor/tests/cli/test_video_commands.py +190 -0
- learnx_cli-0.3.0/tutor/tests/e2e/README.md +61 -0
- learnx_cli-0.3.0/tutor/tests/e2e/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/e2e/conftest.py +117 -0
- learnx_cli-0.3.0/tutor/tests/e2e/fixtures/README.md +17 -0
- learnx_cli-0.3.0/tutor/tests/e2e/fixtures/sample.md +13 -0
- learnx_cli-0.3.0/tutor/tests/e2e/test_audio_quality.py +40 -0
- learnx_cli-0.3.0/tutor/tests/e2e/test_av_sync.py +56 -0
- learnx_cli-0.3.0/tutor/tests/e2e/test_pipeline_smoke.py +37 -0
- learnx_cli-0.3.0/tutor/tests/e2e/test_slide_render.py +72 -0
- learnx_cli-0.3.0/tutor/tests/e2e/test_video_streams.py +104 -0
- learnx_cli-0.3.0/tutor/tests/generation/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/generation/conftest.py +134 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_assembler.py +64 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_curriculum.py +107 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_narrator.py +165 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_segment_edge_cases.py +280 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_segment_planner.py +324 -0
- learnx_cli-0.3.0/tutor/tests/generation/test_visual_planner.py +319 -0
- learnx_cli-0.3.0/tutor/tests/ingestion/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/ingestion/test_chunker.py +94 -0
- learnx_cli-0.3.0/tutor/tests/ingestion/test_doc_analyzer.py +51 -0
- learnx_cli-0.3.0/tutor/tests/player/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/player/test_player_states.py +88 -0
- learnx_cli-0.3.0/tutor/tests/test_assets.py +39 -0
- learnx_cli-0.3.0/tutor/tests/test_models_visual.py +180 -0
- learnx_cli-0.3.0/tutor/tests/visual/__init__.py +0 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_beat_timer.py +321 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_pipeline_integration.py +178 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_slide_renderer.py +298 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_subtitle_writer.py +165 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_video_assembler.py +108 -0
- learnx_cli-0.3.0/tutor/tests/visual/test_visual_pipeline.py +270 -0
- learnx_cli-0.3.0/tutor/tutor.py +365 -0
- learnx_cli-0.3.0/tutor/visual/__init__.py +213 -0
- learnx_cli-0.3.0/tutor/visual/beat_timer.py +222 -0
- learnx_cli-0.3.0/tutor/visual/slide_renderer.py +236 -0
- learnx_cli-0.3.0/tutor/visual/subtitle_writer.py +187 -0
- learnx_cli-0.3.0/tutor/visual/templates/_base.html.j2 +40 -0
- learnx_cli-0.3.0/tutor/visual/templates/analogy.html.j2 +21 -0
- learnx_cli-0.3.0/tutor/visual/templates/callout.html.j2 +10 -0
- learnx_cli-0.3.0/tutor/visual/templates/code_example.html.j2 +12 -0
- learnx_cli-0.3.0/tutor/visual/templates/comparison.html.j2 +28 -0
- learnx_cli-0.3.0/tutor/visual/templates/decision_guide.html.j2 +37 -0
- learnx_cli-0.3.0/tutor/visual/templates/definition.html.j2 +13 -0
- learnx_cli-0.3.0/tutor/visual/templates/diagram.html.j2 +11 -0
- learnx_cli-0.3.0/tutor/visual/templates/hook_question.html.j2 +17 -0
- learnx_cli-0.3.0/tutor/visual/templates/key_insight.html.j2 +9 -0
- learnx_cli-0.3.0/tutor/visual/templates/memory_hook.html.j2 +7 -0
- learnx_cli-0.3.0/tutor/visual/templates/outro.html.j2 +16 -0
- learnx_cli-0.3.0/tutor/visual/templates/question_prompt.html.j2 +13 -0
- learnx_cli-0.3.0/tutor/visual/templates/step_sequence.html.j2 +14 -0
- learnx_cli-0.3.0/tutor/visual/templates/title_card.html.j2 +12 -0
- learnx_cli-0.3.0/tutor/visual/video_assembler.py +299 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Review Agents
|
|
2
|
+
|
|
3
|
+
Each `.md` file in this directory is a Claude sub-agent invoked during pre-merge review.
|
|
4
|
+
|
|
5
|
+
## Agents
|
|
6
|
+
|
|
7
|
+
| File | Role |
|
|
8
|
+
|------|------|
|
|
9
|
+
| quality.md | Bugs, security, logic errors |
|
|
10
|
+
| implementation.md | Does the code match the spec's acceptance criteria? |
|
|
11
|
+
| testing.md | Test coverage and quality |
|
|
12
|
+
| simplification.md | Over-engineering and dead code |
|
|
13
|
+
| product_check.md | Runs the real pipeline, checks output quality with ffprobe/pydub/Playwright |
|
|
14
|
+
|
|
15
|
+
## How to add an agent
|
|
16
|
+
|
|
17
|
+
1. Create `.claude/agents/<name>.md`
|
|
18
|
+
2. Add YAML frontmatter with `name` (must match filename) and `description`
|
|
19
|
+
3. Write the review instructions in the body
|
|
20
|
+
4. Add the agent name to the parallel launch list in `REVIEW_PROMPT_TEMPLATE` in `scripts/run_review.py`
|
|
21
|
+
|
|
22
|
+
## The fixes/ convention
|
|
23
|
+
|
|
24
|
+
Agents do NOT write to `fixes/`. The `fixes/` directory is human-curated institutional
|
|
25
|
+
memory for surprises that are not derivable from reading the code.
|
|
26
|
+
|
|
27
|
+
Each agent's output includes a **Suggested Fix Notes** section. If an agent encountered
|
|
28
|
+
a novel env quirk, API edge case, or tool gotcha during review, it flags it there.
|
|
29
|
+
The human reads those flags and decides whether to write a permanent `fixes/fixNNN.md`.
|
|
30
|
+
|
|
31
|
+
Rule: if removing the fix note would confuse a future agent reading the codebase cold,
|
|
32
|
+
it belongs in `fixes/`. If the code or a test already explains it, it does not.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implementation
|
|
3
|
+
description: Verifies that the implementation matches the spec's acceptance criteria
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You will be given a git diff and the acceptance criteria from the spec that drove
|
|
7
|
+
these changes. Check each criterion against the diff.
|
|
8
|
+
|
|
9
|
+
For each criterion:
|
|
10
|
+
- PASS: the diff clearly satisfies it
|
|
11
|
+
- FAIL: the diff does not satisfy it — explain what is missing
|
|
12
|
+
- PARTIAL: the diff partially satisfies it — explain what remains
|
|
13
|
+
|
|
14
|
+
List spec criteria in order. End with a one-line summary: "N/M criteria satisfied."
|
|
15
|
+
|
|
16
|
+
If no spec file is provided, verify that the implementation is internally consistent
|
|
17
|
+
and that all stated goals in commit messages or comments are actually achieved.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: product_check
|
|
3
|
+
description: Runs the LearnX pipeline on the test fixture and verifies audio, video, and slide output quality
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are checking whether the product works, not whether the code looks right.
|
|
7
|
+
Run the following steps in order and report the result of each.
|
|
8
|
+
|
|
9
|
+
## Step 1 — Run the pipeline on the test fixture
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m tutor generate tutor/tests/e2e/fixtures/sample.md --output /tmp/learnx_check
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Expected: exits 0, output directory contains tutorial.mp3, tutorial.mp4 (or slides).
|
|
16
|
+
If it crashes: paste the traceback. STOP — do not proceed to further steps.
|
|
17
|
+
|
|
18
|
+
## Step 2 — Verify audio stream in video
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
ffprobe -v error \
|
|
22
|
+
-select_streams a:0 \
|
|
23
|
+
-show_entries stream=codec_type,duration,bit_rate \
|
|
24
|
+
-of json /tmp/learnx_check/tutorial.mp4
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Expected: `codec_type` is `audio`, `duration` > 0.
|
|
28
|
+
FAIL if: no audio stream returned, or duration is 0 or null.
|
|
29
|
+
|
|
30
|
+
## Step 3 — Check audio is not silent
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from pydub import AudioSegment
|
|
34
|
+
audio = AudioSegment.from_mp3("/tmp/learnx_check/tutorial.mp3")
|
|
35
|
+
db_level = audio.dBFS
|
|
36
|
+
print(f"Audio level: {db_level:.1f} dBFS")
|
|
37
|
+
# Anything above -60 dBFS is audible
|
|
38
|
+
assert db_level > -60, f"Audio appears silent: {db_level:.1f} dBFS"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Expected: dBFS above -60.
|
|
42
|
+
FAIL if: dBFS is -inf or below -60 (silent or near-silent track).
|
|
43
|
+
|
|
44
|
+
## Step 4 — Screenshot HTML slides (if slides were generated)
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from playwright.sync_api import sync_playwright
|
|
48
|
+
import pathlib
|
|
49
|
+
|
|
50
|
+
slide_dir = pathlib.Path("/tmp/learnx_check/slides")
|
|
51
|
+
if slide_dir.exists():
|
|
52
|
+
html_files = list(slide_dir.glob("*.html"))
|
|
53
|
+
with sync_playwright() as p:
|
|
54
|
+
browser = p.chromium.launch()
|
|
55
|
+
page = browser.new_page(viewport={"width": 1280, "height": 720})
|
|
56
|
+
for html in html_files[:3]: # first 3 slides max
|
|
57
|
+
page.goto(f"file://{html}")
|
|
58
|
+
page.wait_for_load_state("networkidle")
|
|
59
|
+
screenshot = f"/tmp/learnx_check/screenshot_{html.stem}.png"
|
|
60
|
+
page.screenshot(path=screenshot)
|
|
61
|
+
print(f"Screenshot saved: {screenshot}")
|
|
62
|
+
browser.close()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
After running: describe what the screenshots look like. Are slides blank? Is text visible?
|
|
66
|
+
Are there any error messages or broken layout?
|
|
67
|
+
|
|
68
|
+
## Step 5 — Check A/V sync (timing.json vs audio duration)
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import json
|
|
72
|
+
from pydub import AudioSegment
|
|
73
|
+
import pathlib
|
|
74
|
+
|
|
75
|
+
timing = json.loads(
|
|
76
|
+
pathlib.Path("/tmp/learnx_check/tutorial.timing.json").read_text()
|
|
77
|
+
)
|
|
78
|
+
audio = AudioSegment.from_mp3("/tmp/learnx_check/tutorial.mp3")
|
|
79
|
+
|
|
80
|
+
last_unit = max(int(k) for k in timing["units"])
|
|
81
|
+
last_entry = timing["units"][str(last_unit)][-1]
|
|
82
|
+
timing_end_ms = last_entry["end_ms"]
|
|
83
|
+
audio_duration_ms = len(audio)
|
|
84
|
+
drift_ms = abs(audio_duration_ms - timing_end_ms)
|
|
85
|
+
|
|
86
|
+
print(f"Audio duration: {audio_duration_ms}ms")
|
|
87
|
+
print(f"Timing end: {timing_end_ms}ms")
|
|
88
|
+
print(f"Drift: {drift_ms}ms")
|
|
89
|
+
assert drift_ms < 500, f"A/V drift too large: {drift_ms}ms"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Expected: drift < 500ms.
|
|
93
|
+
FAIL if: drift >= 500ms (slides and audio will be noticeably out of sync).
|
|
94
|
+
|
|
95
|
+
## Report format
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
PIPELINE RUN: PASS / FAIL
|
|
99
|
+
AUDIO STREAM: PRESENT (Xs) / MISSING
|
|
100
|
+
SILENCE CHECK: {dBFS value} — PASS / FAIL
|
|
101
|
+
SLIDE SCREENSHOTS: [describe what you see for each slide]
|
|
102
|
+
A/V SYNC: {drift}ms — PASS / FAIL
|
|
103
|
+
|
|
104
|
+
OVERALL: PRODUCT WORKING / PRODUCT BROKEN
|
|
105
|
+
Blocking issues: [list or "none"]
|
|
106
|
+
|
|
107
|
+
Suggested fix notes:
|
|
108
|
+
[List any novel pipeline surprises — env issues, tool edge cases, encoding quirks —
|
|
109
|
+
that are NOT obvious from reading the code. Write "none" if nothing surprising happened.
|
|
110
|
+
Do NOT write to fixes/ — this is for the human to decide.]
|
|
111
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quality
|
|
3
|
+
description: Reviews code for bugs, security issues, and logic errors
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Review the git diff for the following. Report each finding as:
|
|
7
|
+
FILE:LINE — severity (critical/major/minor) — description
|
|
8
|
+
|
|
9
|
+
1. Logic errors: off-by-one, wrong condition, silent failure paths
|
|
10
|
+
2. Security: hardcoded secrets, path traversal, injection vulnerabilities
|
|
11
|
+
3. Resource leaks: unclosed files, unreleased locks, unbounded loops
|
|
12
|
+
4. Error handling: exceptions swallowed silently, wrong exception types caught
|
|
13
|
+
|
|
14
|
+
Output "NO ISSUES FOUND" if the diff is clean. Do not suggest style improvements
|
|
15
|
+
— that is the simplification agent's job.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: regression_check
|
|
3
|
+
description: Check that phase 1 fix commits did not introduce new problems
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are running Phase 2 of a two-phase review. Examine only the changes introduced
|
|
7
|
+
by the phase 1 fix commits — not the original implementation diff.
|
|
8
|
+
|
|
9
|
+
Run `git log --oneline main..HEAD` to list all commits. Identify which commits are
|
|
10
|
+
fix commits (typically the most recent ones, added after the original spec work).
|
|
11
|
+
Run `git show <hash>` on each fix commit.
|
|
12
|
+
|
|
13
|
+
Look for:
|
|
14
|
+
1. New logic errors or off-by-ones introduced by the fix
|
|
15
|
+
2. New security issues or resource leaks
|
|
16
|
+
3. Broken or removed tests
|
|
17
|
+
4. Unrelated changes bundled into the fix commit
|
|
18
|
+
|
|
19
|
+
End with a single verdict line:
|
|
20
|
+
CLEAN — no regressions detected
|
|
21
|
+
or
|
|
22
|
+
REGRESSION FOUND — <one-sentence description>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: simplification
|
|
3
|
+
description: Detects over-engineering, unnecessary abstraction, and dead code
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Review the diff for complexity that is not justified by the spec.
|
|
7
|
+
|
|
8
|
+
1. Abstractions: classes or functions created for a single use case
|
|
9
|
+
2. Premature generalisation: parameters, config, or interfaces for hypothetical callers
|
|
10
|
+
3. Dead code: code that is added but never called
|
|
11
|
+
4. Over-indirection: wrapper functions that just call one other function
|
|
12
|
+
5. Unnecessary comments: comments that restate what the code already says
|
|
13
|
+
|
|
14
|
+
Rate overall complexity: LOW / MEDIUM / HIGH.
|
|
15
|
+
List specific findings only. Do not suggest refactors not related to over-engineering.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing
|
|
3
|
+
description: Reviews test coverage and test quality for the changed code
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Review the test changes in the diff.
|
|
7
|
+
|
|
8
|
+
1. Coverage: are all new code paths exercised by at least one test?
|
|
9
|
+
2. Assertions: do tests assert specific values, or do they just assert no exception?
|
|
10
|
+
3. Isolation: do tests depend on external state (filesystem, network, other tests)?
|
|
11
|
+
4. Names: do test names describe what they verify (not just "test_function_x")?
|
|
12
|
+
5. Missing tests: list any new public functions or edge cases with no test at all.
|
|
13
|
+
|
|
14
|
+
Format: FILE — finding description
|
|
15
|
+
Output "TESTS LOOK GOOD" if no issues found.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verify_fixes
|
|
3
|
+
description: Verify that each phase 1 review finding was fully resolved
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are running Phase 2 of a two-phase review. You will be given the phase 1
|
|
7
|
+
findings report and must determine whether each finding was addressed.
|
|
8
|
+
|
|
9
|
+
Run `git log --oneline main..HEAD` to list all commits, including any fix commits
|
|
10
|
+
added after phase 1. Run `git show <hash>` on any fix commit to see what changed.
|
|
11
|
+
|
|
12
|
+
For each finding from the phase 1 report, produce one line:
|
|
13
|
+
RESOLVED — the fix is present and correct
|
|
14
|
+
PARTIAL — something changed but the finding is not fully addressed
|
|
15
|
+
UNRESOLVED — no change addresses this finding
|
|
16
|
+
|
|
17
|
+
End with a summary line:
|
|
18
|
+
VERIFIED (N/N findings resolved)
|
|
19
|
+
or
|
|
20
|
+
STILL FAILING (N/M unresolved: <short list>)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": [
|
|
3
|
+
"Assisted mode reference. NOT loaded directly by Claude Code.",
|
|
4
|
+
"The wrapper writes this content to .claude/settings.local.json at session start",
|
|
5
|
+
"and deletes it on exit. settings.local.json is gitignored.",
|
|
6
|
+
"Deny rules removed — local git ops happen without prompts.",
|
|
7
|
+
"git push and git merge to main still require approval (no allow rule for them)."
|
|
8
|
+
],
|
|
9
|
+
"permissions": {
|
|
10
|
+
"allow": [
|
|
11
|
+
"Bash(py -m pytest*)",
|
|
12
|
+
"Bash(py -m ruff*)",
|
|
13
|
+
"Bash(python*)",
|
|
14
|
+
"Bash(git status*)",
|
|
15
|
+
"Bash(git diff*)",
|
|
16
|
+
"Bash(git log*)",
|
|
17
|
+
"Bash(git add*)",
|
|
18
|
+
"Bash(git commit*)",
|
|
19
|
+
"Bash(git checkout*)",
|
|
20
|
+
"Bash(git branch*)",
|
|
21
|
+
"Bash(git stash*)",
|
|
22
|
+
"Read(*)",
|
|
23
|
+
"Edit(*)",
|
|
24
|
+
"Write(*)"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": [
|
|
3
|
+
"Supervised mode — the committed host default.",
|
|
4
|
+
"Use python scripts/learnx_dk.py --mode to select a different mode.",
|
|
5
|
+
"Container modes (container, yolo) ignore this file entirely."
|
|
6
|
+
],
|
|
7
|
+
"permissions": {
|
|
8
|
+
"allow": [
|
|
9
|
+
"Bash(py -m pytest*)",
|
|
10
|
+
"Bash(py -m ruff check*)",
|
|
11
|
+
"Bash(py -m ruff format*)",
|
|
12
|
+
"Bash(git status*)",
|
|
13
|
+
"Bash(git diff*)",
|
|
14
|
+
"Bash(git log*)",
|
|
15
|
+
"Bash(git checkout main)",
|
|
16
|
+
"Bash(git checkout -b sandbox/*)",
|
|
17
|
+
"Bash(git branch*)"
|
|
18
|
+
],
|
|
19
|
+
"deny": [
|
|
20
|
+
"Bash(git push*)",
|
|
21
|
+
"Bash(git merge*)",
|
|
22
|
+
"Bash(git reset*)",
|
|
23
|
+
"Bash(git branch -D*)"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Large generated directories — not needed in build context
|
|
2
|
+
audio/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.pyc
|
|
5
|
+
*.pyo
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
|
|
9
|
+
# Version control
|
|
10
|
+
.git/
|
|
11
|
+
.gitignore
|
|
12
|
+
|
|
13
|
+
# Dev environment
|
|
14
|
+
.venv/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
|
|
17
|
+
# OS noise
|
|
18
|
+
.DS_Store
|
|
19
|
+
Thumbs.db
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main", "v*-*"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Install ruff
|
|
21
|
+
run: pip install "ruff>=0.4"
|
|
22
|
+
|
|
23
|
+
- name: Check style
|
|
24
|
+
run: ruff check tutor/
|
|
25
|
+
|
|
26
|
+
- name: Check formatting
|
|
27
|
+
run: ruff format --check tutor/
|
|
28
|
+
|
|
29
|
+
unit-tests:
|
|
30
|
+
name: Unit Tests
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
needs: lint
|
|
33
|
+
if: false # change to false to skip unit tests
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.12"
|
|
40
|
+
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: |
|
|
43
|
+
grep -v 'audioop-lts' tutor/requirements.txt > /tmp/requirements-filtered.txt
|
|
44
|
+
pip install -r /tmp/requirements-filtered.txt
|
|
45
|
+
pip install -r tutor/requirements-dev.txt
|
|
46
|
+
|
|
47
|
+
- name: Run unit tests
|
|
48
|
+
run: python -m pytest tutor/tests/ --ignore=tutor/tests/e2e/ -m "not slow" -v
|
|
49
|
+
|
|
50
|
+
e2e-tests:
|
|
51
|
+
name: E2E Smoke Tests
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
needs: unit-tests
|
|
54
|
+
if: false # change to false to skip e2e tests
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v4
|
|
57
|
+
|
|
58
|
+
- uses: actions/setup-python@v5
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.12"
|
|
61
|
+
|
|
62
|
+
- name: Install system dependencies
|
|
63
|
+
run: |
|
|
64
|
+
sudo apt-get update
|
|
65
|
+
sudo apt-get install -y ffmpeg
|
|
66
|
+
|
|
67
|
+
- name: Install Python dependencies
|
|
68
|
+
run: |
|
|
69
|
+
grep -v 'audioop-lts' tutor/requirements.txt > /tmp/requirements-filtered.txt
|
|
70
|
+
pip install -r /tmp/requirements-filtered.txt
|
|
71
|
+
pip install -r tutor/requirements-dev.txt
|
|
72
|
+
|
|
73
|
+
- name: Install Playwright browsers
|
|
74
|
+
run: python -m playwright install chromium --with-deps
|
|
75
|
+
|
|
76
|
+
- name: Run E2E smoke tests
|
|
77
|
+
run: python -m pytest tutor/tests/e2e/ -v
|
|
78
|
+
env:
|
|
79
|
+
# LLM calls are mocked in conftest.py — no real key needed
|
|
80
|
+
ANTHROPIC_API_KEY: "test-key-not-used"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Folders excluded from this repo
|
|
2
|
+
week1/
|
|
3
|
+
week2/
|
|
4
|
+
systemDesign/
|
|
5
|
+
|
|
6
|
+
# Generated output directories (root-level only — not tutor/audio/ source)
|
|
7
|
+
/audio/
|
|
8
|
+
/video/
|
|
9
|
+
|
|
10
|
+
# Generated audio output
|
|
11
|
+
*.mp3
|
|
12
|
+
*.script.txt
|
|
13
|
+
*.units.json
|
|
14
|
+
*.session.json
|
|
15
|
+
*.chunks.json
|
|
16
|
+
*.meta.json
|
|
17
|
+
*.visuals.json
|
|
18
|
+
tutorial_units/
|
|
19
|
+
|
|
20
|
+
# TTS temp files
|
|
21
|
+
.tts_tmp/
|
|
22
|
+
|
|
23
|
+
# LLM cache (regenerated on demand)
|
|
24
|
+
.tutor_cache/
|
|
25
|
+
|
|
26
|
+
# Secrets — never commit
|
|
27
|
+
tutor/.env
|
|
28
|
+
|
|
29
|
+
# Python
|
|
30
|
+
__pycache__/
|
|
31
|
+
*.py[cod]
|
|
32
|
+
*.pyo
|
|
33
|
+
.mypy_cache/
|
|
34
|
+
.ruff_cache/
|
|
35
|
+
|
|
36
|
+
# Virtual environments
|
|
37
|
+
.venv/
|
|
38
|
+
venv/
|
|
39
|
+
env/
|
|
40
|
+
|
|
41
|
+
# Logs
|
|
42
|
+
tutor.log
|
|
43
|
+
*.log
|
|
44
|
+
|
|
45
|
+
# Editor / OS
|
|
46
|
+
.vscode/
|
|
47
|
+
.idea/
|
|
48
|
+
*.swp
|
|
49
|
+
.DS_Store
|
|
50
|
+
Thumbs.db
|
|
51
|
+
|
|
52
|
+
# Reference repos — cloned locally for reading, not part of this project
|
|
53
|
+
ralphex/
|
|
54
|
+
|
|
55
|
+
# Docker build artifacts
|
|
56
|
+
.docker/
|
|
57
|
+
*.dockerignore.bak
|
|
58
|
+
|
|
59
|
+
# Dev workflow scripts output
|
|
60
|
+
scripts/__pycache__/
|
|
61
|
+
|
|
62
|
+
# Assisted mode runtime settings override — written and deleted by learnx_dk.py
|
|
63
|
+
.claude/settings.local.json
|
|
64
|
+
|
|
65
|
+
# sandbox/ prototype scripts — tracked selectively; outputs are not
|
|
66
|
+
sandbox/*.log
|
|
67
|
+
sandbox/*.json
|
|
68
|
+
sandbox/*.mp3
|
|
69
|
+
|
|
70
|
+
problems/
|
|
71
|
+
week3/
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# LearnX CLI — Product Context
|
|
2
|
+
|
|
3
|
+
> For DevLoop workflow instructions (spec days, implementation loop, commands) see **DEVLOOP.md**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What This Project Is
|
|
8
|
+
|
|
9
|
+
LearnX is a Python CLI that converts a Markdown document into an audio-first tutorial
|
|
10
|
+
with optional video. The pipeline is:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Document → chunk → LLM summarise → LLM curriculum → LLM dialogue
|
|
14
|
+
→ TTS render → assemble audio (+ timing.json)
|
|
15
|
+
→ (optional) LLM visual plan → render slides → subtitle → mp4
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Entry point: `tutor/__main__.py`. CLI commands live in `tutor/cli/`.
|
|
19
|
+
Primary platform: Windows / PowerShell. Python 3.12+.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Two Layers in This Repo
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
tutor/ LearnX CLI — the product. Audio tutorial generator.
|
|
27
|
+
scripts/ DevLoop — the build system. Runs Claude in Docker, manages review pipeline.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
These are independent concerns that share one repository. `scripts/` is never imported
|
|
31
|
+
by `tutor/`. A user of LearnX CLI never touches `scripts/`.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Product Layout
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
tutor/ the Python package
|
|
39
|
+
__main__.py CLI entry point
|
|
40
|
+
models.py all dataclasses — start here to understand data shapes
|
|
41
|
+
constants.py silence gap constants, limits
|
|
42
|
+
config.py LLM provider / model config
|
|
43
|
+
audio/ audio pipeline (audio_builder.py, tts_renderer.py)
|
|
44
|
+
generation/ LLM pipeline (curriculum, dialogue, narrator, visual_planner)
|
|
45
|
+
ingestion/ document processing (chunker, doc_analyzer)
|
|
46
|
+
visual/ video pipeline (beat_timer, slide_compositor, subtitle_writer…)
|
|
47
|
+
player/ interactive playback
|
|
48
|
+
cli/ CLI commands and shell
|
|
49
|
+
tests/ pytest unit suite — mirrors tutor/ structure
|
|
50
|
+
tests/e2e/ E2E smoke tests — run real pipeline, check output quality
|
|
51
|
+
infra/ LLM client wrapper
|
|
52
|
+
|
|
53
|
+
specs/ versioned spec files — source of truth for all tutor/ code
|
|
54
|
+
v0/ … v3/ completed versions (regression reference)
|
|
55
|
+
v4-workflow/ DevLoop upgrade specs (archived)
|
|
56
|
+
v5/ … v11/ active versions
|
|
57
|
+
|
|
58
|
+
plan/ version-level design and architecture docs
|
|
59
|
+
v0_plan.md … v11_plan.md
|
|
60
|
+
v4_update_plan.md DevLoop v4 upgrade rationale
|
|
61
|
+
v4_architecture.md DevLoop component map
|
|
62
|
+
|
|
63
|
+
fixes/ post-mortem notes (fix001.md … )
|
|
64
|
+
read these before starting — they contain env/API gotchas
|
|
65
|
+
|
|
66
|
+
dev_setup/ developer process documentation
|
|
67
|
+
spec-driven_plan.md what SDD means and how to write specs
|
|
68
|
+
context_hygiene_plan.md how to manage session context
|
|
69
|
+
sandbox_plan.md git branch + test isolation strategy
|
|
70
|
+
autonomy_plan.md how to run the implement→test→fix loop (Level 1–4)
|
|
71
|
+
handoff_template.md copy-paste prompt for starting each spec day
|
|
72
|
+
container_plan.md how to run Claude inside Docker (Level 4 workflow)
|
|
73
|
+
|
|
74
|
+
scripts/ DevLoop tooling (NOT imported by tutor/)
|
|
75
|
+
devloop.py launcher — runs Claude inside Docker
|
|
76
|
+
run_review.py triggers 5-agent code + product review
|
|
77
|
+
dk/ devloop submodules (config, docker, dashboard, runners…)
|
|
78
|
+
tests/ pytest tests for scripts/
|
|
79
|
+
|
|
80
|
+
sandbox/ throwaway prototype scripts — NOT imported by tutor/
|
|
81
|
+
|
|
82
|
+
.claude/
|
|
83
|
+
settings.json allow list only (deny rules removed — Docker is the sandbox)
|
|
84
|
+
agents/ review + product check agent definitions
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Code Quality Rules
|
|
90
|
+
|
|
91
|
+
These rules apply to every file touched during a spec day or refactoring session.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
MAX 400 LOC PER FILE — if a file exceeds 400 lines, split it before committing.
|
|
95
|
+
Extract by cohesion: group things that change together and depend on each other.
|
|
96
|
+
Keep the public interface in the original file; move implementation to submodules.
|
|
97
|
+
|
|
98
|
+
CLEAN CODE
|
|
99
|
+
Functions do one thing. Name them for what they do, not how.
|
|
100
|
+
No functions longer than 40 lines. No nesting deeper than 3 levels.
|
|
101
|
+
No magic numbers — use named constants.
|
|
102
|
+
No dead code, no commented-out blocks, no TODO left in committed code.
|
|
103
|
+
Never hardcode a parameter value inside a function body when the caller
|
|
104
|
+
passed that value as an argument — always forward the parameter.
|
|
105
|
+
|
|
106
|
+
MAINTAINABILITY
|
|
107
|
+
Every module has a single clear responsibility (SRP).
|
|
108
|
+
Avoid deep coupling: pass what a function needs, don't let it reach into globals.
|
|
109
|
+
Prefer explicit imports over star imports.
|
|
110
|
+
Update imports everywhere when you move code.
|
|
111
|
+
|
|
112
|
+
SCALABILITY
|
|
113
|
+
New behaviour should be addable without modifying existing logic (OCP).
|
|
114
|
+
Favour composition over inheritance for extending behaviour.
|
|
115
|
+
Config goes in devloop.toml / llm_config.toml, not hardcoded in source.
|
|
116
|
+
|
|
117
|
+
REUSABILITY
|
|
118
|
+
Pure functions (no side effects) are easier to test and reuse — prefer them.
|
|
119
|
+
Separate I/O (file reads, subprocess calls, network) from logic.
|
|
120
|
+
If two files share a helper, extract it to a shared module; never duplicate.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Where to Find Things
|
|
126
|
+
|
|
127
|
+
| Question | Where to look |
|
|
128
|
+
|---|---|
|
|
129
|
+
| What does this feature do? | `specs/vN/dayN.md` |
|
|
130
|
+
| Why was this approach chosen? | `plan/vN_plan.md` |
|
|
131
|
+
| Why does this edge case exist? | `fixes/fix0NN.md` |
|
|
132
|
+
| What dataclasses exist? | `tutor/models.py` |
|
|
133
|
+
| What silence constants are used? | `tutor/constants.py` |
|
|
134
|
+
| How is the LLM called? | `tutor/infra/llm.py` |
|
|
135
|
+
| How to start a new spec day? | `dev_setup/handoff_template.md` |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Read Before Starting Any v3 Day
|
|
140
|
+
|
|
141
|
+
1. `fixes/fix001.md` — ffmpeg is not always on PATH on Windows; pydub needs the binary patched in at startup.
|
|
142
|
+
2. `fixes/fix013.md` — timing inflation root cause: `compute_slide_timings()` was using estimated beat offsets instead of actual MP3 durations.
|
|
143
|
+
3. `fixes/fix009.md` — per-unit loudnorm breaks audio duration with image-based concat video; volume boost is applied at encode time instead.
|
|
144
|
+
4. `plan/v3_plan.md` — the architectural rationale for the whole v3 approach.
|