Are we tiny?#
gptme is intended to be small and simple, and focus on doing the right thing in the right way, rather than all the things in all the ways.
The benefits of this approach are many:
It is easier to understand and maintain.
It is easier to contribute to.
It is easier to learn.
It is easier to extend.
It is more fun to work on.
Being aggressive about keeping things small and simple is a way to keep the project maintainable and fun to work on. The fastest way to kill a project is to make it too big and complex, and suffer burnout as a result.
Another major benefit of keeping things small and simple is that it makes it easier for AI to understand and work with the codebase. This is a major goal of the project, and it is important to keep in mind that the simpler the codebase is, the easier it will be for AI to work with it:
“The simpler your API is, the more effectively the AI can harness it when generating code.”
—Kenneth Reitz (and many others)
To that end, in this document we will present some statistics about the current state of the project, trying to be mindful to keep an eye on this page and make sure we are not growing too much.
Startup time#
$ make bench-import
make[2]: Entering directory '/home/runner/work/gptme/gptme'
Benchmarking import time for gptme
time poetry run python -X importtime -m gptme --model openai --non-interactive 2>&1 | grep "import time" | cut -d'|' -f 2- | sort -n | tail -n 10
272895 | gptme.mcp.client
273917 | gptme.mcp
273953 | gptme.mcp.client
274212 | gptme.tools.mcp_adapter
295964 | openai
326525 | gptme.llm
368611 | gptme.commands
376831 | gptme.chat
813885 | gptme.cli
866907 | gptme
real 0m1.862s
user 0m1.625s
sys 0m0.253s
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
$ make bench-startup
make[2]: Entering directory '/home/runner/work/gptme/gptme'
Benchmarking startup time for gptme
hyperfine "poetry run gptme '/exit'" -M 5 || poetry run gptme '/exit' || exit 1
Benchmark 1: poetry run gptme '/exit'
Time (mean ± σ): 1.836 s ± 0.021 s [User: 1.619 s, System: 0.207 s]
Range (min … max): 1.819 s … 1.873 s 5 runs
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
Lines of code#
LoC Core#
$ make cloc-core
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/*.py gptme/llm/*.py gptme/util/*.py gptme/tools/__init__.py gptme/tools/base.py --by-file
github.com/AlDanial/cloc v 1.98 T=0.11 s (498.9 files/s, 158090.4 lines/s)
-----------------------------------------------------------------------------------
File blank comment code
-----------------------------------------------------------------------------------
gptme/config.py 185 166 652
gptme/llm/llm_openai.py 140 100 615
gptme/llm/models.py 95 89 584
gptme/commands.py 145 94 557
gptme/llm/llm_anthropic.py 125 128 542
gptme/util/cli.py 142 73 498
gptme/tools/base.py 125 126 496
gptme/setup.py 113 59 478
gptme/prompts.py 118 140 415
gptme/logmanager.py 107 101 409
gptme/cli.py 67 57 393
gptme/chat.py 72 81 366
gptme/telemetry.py 85 54 342
gptme/llm/__init__.py 79 77 340
gptme/util/_telemetry.py 87 97 326
gptme/util/context.py 85 129 324
gptme/util/prompt.py 81 109 309
gptme/util/gh.py 55 66 284
gptme/message.py 62 78 281
gptme/ncurses.py 39 5 238
gptme/tools/__init__.py 63 44 216
gptme/util/_sound_sounddevice.py 52 52 208
gptme/util/ask_execute.py 53 46 203
gptme/util/sound.py 65 72 200
gptme/llm/validate.py 29 27 173
gptme/llm/llm_openai_models.py 2 11 169
gptme/codeblock.py 34 81 148
gptme/util/__init__.py 31 22 139
gptme/util/auto_naming.py 47 44 130
gptme/util/cost_tracker.py 44 62 112
gptme/llm/utils.py 38 48 103
gptme/init.py 21 14 94
gptme/util/tree.py 21 13 91
gptme/util/export.py 17 25 86
gptme/util/reduce.py 24 35 76
gptme/util/generate_name.py 5 6 69
gptme/__version__.py 15 11 64
gptme/util/_sound_cmd.py 22 17 64
gptme/util/output_storage.py 26 36 58
gptme/dirs.py 27 14 55
gptme/util/tokens.py 22 16 44
gptme/util/cost.py 12 20 43
gptme/util/file_storage.py 30 47 40
gptme/util/clipboard.py 8 2 35
gptme/util/terminal.py 23 21 34
gptme/util/install.py 13 24 31
gptme/wut.py 13 12 31
gptme/util/content.py 18 24 29
gptme/util/useredit.py 12 13 21
gptme/util/interrupt.py 13 14 20
gptme/constants.py 9 11 15
gptme/__init__.py 1 1 8
gptme/__main__.py 1 0 3
-----------------------------------------------------------------------------------
SUM: 2818 2714 11261
-----------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC LLM#
$ make cloc-llm
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/llm/*.py --by-file
github.com/AlDanial/cloc v 1.98 T=0.03 s (267.7 files/s, 134399.5 lines/s)
---------------------------------------------------------------------------------
File blank comment code
---------------------------------------------------------------------------------
gptme/llm/llm_openai.py 140 100 615
gptme/llm/models.py 95 89 584
gptme/llm/llm_anthropic.py 125 128 542
gptme/llm/__init__.py 79 77 340
gptme/llm/validate.py 29 27 173
gptme/llm/llm_openai_models.py 2 11 169
gptme/llm/utils.py 38 48 103
---------------------------------------------------------------------------------
SUM: 508 480 2526
---------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC Tools#
$ make cloc-tools
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/tools/*.py --by-file
github.com/AlDanial/cloc v 1.98 T=0.08 s (444.2 files/s, 158883.0 lines/s)
-------------------------------------------------------------------------------------
File blank comment code
-------------------------------------------------------------------------------------
gptme/tools/shell.py 264 319 1078
gptme/tools/base.py 125 126 496
gptme/tools/computer.py 150 218 436
gptme/tools/autocompact.py 147 189 434
gptme/tools/gh.py 85 93 349
gptme/tools/tmux.py 85 141 307
gptme/tools/subagent.py 89 125 300
gptme/tools/mcp_adapter.py 89 84 290
gptme/tools/tts.py 119 132 284
gptme/tools/_browser_playwright.py 89 33 271
gptme/tools/save.py 55 53 253
gptme/tools/patch.py 57 78 234
gptme/tools/__init__.py 63 44 216
gptme/tools/todo.py 85 95 211
gptme/tools/precommit.py 64 87 189
gptme/tools/lessons.py 71 87 184
gptme/tools/mcp.py 55 44 179
gptme/tools/morph.py 43 42 178
gptme/tools/python.py 56 49 172
gptme/tools/_browser_thread.py 27 12 157
gptme/tools/form.py 38 43 147
gptme/tools/rag.py 62 74 145
gptme/tools/chats.py 43 49 142
gptme/tools/choice.py 31 25 105
gptme/tools/complete.py 34 41 104
gptme/tools/restart.py 44 68 96
gptme/tools/_browser_perplexity.py 25 22 85
gptme/tools/browser.py 40 87 84
gptme/tools/autocommit.py 37 59 75
gptme/tools/vision.py 19 12 53
gptme/tools/screenshot.py 14 12 44
gptme/tools/_browser_lynx.py 9 13 30
gptme/tools/youtube.py 10 1 26
gptme/tools/read.py 6 8 13
-------------------------------------------------------------------------------------
SUM: 2230 2565 7367
-------------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC Server#
$ make cloc-server
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/server --by-file
github.com/AlDanial/cloc v 1.98 T=0.04 s (519.2 files/s, 154105.2 lines/s)
------------------------------------------------------------------------------------------
File blank comment code
------------------------------------------------------------------------------------------
gptme/server/api_v2_sessions.py 152 131 636
gptme/server/tasks_api.py 171 110 580
gptme/server/openapi_docs.py 177 140 455
gptme/server/api.py 86 80 348
gptme/server/api_v2.py 69 45 316
gptme/server/static/main.js 35 45 316
gptme/server/server-api-improvements.md 40 0 202
gptme/server/workspace_api.py 57 55 170
gptme/server/api_v2_agents.py 38 28 149
gptme/server/static/index.html 11 15 148
gptme/server/static/style.css 27 4 143
gptme/server/client.py 60 78 139
gptme/server/cli.py 26 17 137
gptme/server/auth.py 45 69 121
gptme/server/static/computer.html 1 1 90
gptme/server/api_v2_common.py 48 24 69
gptme/server/__init__.py 2 3 3
gptme/server/__main__.py 1 0 3
gptme/server/exceptions.py 5 8 2
gptme/server/constants.py 1 3 1
------------------------------------------------------------------------------------------
SUM: 1052 856 4028
------------------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC Tests#
$ make cloc-tests
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc tests --by-file
github.com/AlDanial/cloc v 1.98 T=0.14 s (652.1 files/s, 152526.4 lines/s)
---------------------------------------------------------------------------------------------
File blank comment code
---------------------------------------------------------------------------------------------
tests/test_tools_shell.py 235 375 680
tests/test_llm_openai.py 110 55 467
tests/test_config.py 109 212 413
tests/test_util_gh_mocked.py 63 47 405
tests/context/test_task_analyzer.py 119 58 389
tests/test_util_cli_mcp.py 89 45 380
tests/test_mcp_discovery.py 128 37 351
tests/test_lessons_parser.py 152 176 338
tests/test_codeblock.py 214 489 331
tests/test_integration_phase4.py 66 54 331
tests/test_auto_compact.py 150 134 324
tests/test_cli.py 82 55 297
tests/test_lessons_commands.py 98 44 255
tests/test_context_selector.py 83 45 254
tests/test_lessons_integration.py 91 59 242
tests/conftest.py 75 57 240
tests/test_server_v2.py 69 34 229
tests/test_llm_anthropic.py 26 0 221
tests/test_dspy_reasoning_program.py 62 53 217
tests/test_plugins.py 82 70 203
tests/test_lessons_tool.py 55 26 194
tests/test_mcp_adapter.py 65 37 191
tests/test_hooks.py 90 24 184
tests/test_server_v2_hooks.py 71 52 181
tests/test_dspy_hybrid.py 65 45 179
tests/test_lessons_index.py 68 50 174
tests/test_lessons_matcher.py 46 21 166
tests/test_tools_subagent.py 72 44 164
tests/test_mcp.py 41 31 162
tests/test_message.py 60 60 157
tests/test_tools_time_awareness.py 52 34 155
tests/test_cost_tracker.py 21 24 154
tests/test_context.py 72 48 152
tests/test_file_selector_integration.py 50 23 145
tests/test_tree.py 54 29 142
tests/test_tool_use.py 12 19 140
tests/test_dspy_integration.py 54 32 139
tests/test_lesson_selector_integration.py 45 25 138
tests/test_tools_tmux.py 64 60 138
tests/test_dspy_basic.py 49 31 132
tests/benchmark_context_selector.py 32 26 130
tests/test_tools_token_awareness.py 59 47 126
tests/test_prompt.py 36 36 120
tests/test_complete.py 29 19 117
tests/test_tools_todo.py 53 46 117
tests/test_lessons_status.py 67 96 113
tests/test_auto_naming.py 37 23 106
tests/test_util_cli.py 35 28 105
tests/test_tools_tts.py 50 58 101
tests/test_tools_patch.py 58 139 93
tests/test_tools_computer.py 36 27 91
tests/test_util_gh.py 39 28 91
tests/test_llm_validate.py 25 19 90
tests/test_server_v2_auto_stepping.py 20 22 87
tests/test_server.py 27 10 85
tests/test_server_auth.py 40 19 84
tests/test_prompt_tools.py 5 4 77
tests/test_tools.py 45 6 76
tests/test_llm_models.py 27 14 75
tests/test_markdown_validation.py 43 34 75
tests/test_shell_issue729.py 50 52 75
tests/test_shell_issue772.py 48 47 73
tests/test_hooks_form_autodetect.py 22 34 68
tests/test_tools_form.py 22 19 67
tests/test_tools_save.py 15 10 65
tests/test_server_v2_tool_confirmation.py 20 21 60
tests/test_shell_output_mixing_issue408.py 25 29 60
tests/test_server_client.py 33 26 59
tests/test_chat_history.py 14 12 56
tests/test_server_v2_sse.py 15 13 50
tests/test_custom_providers.py 23 32 49
tests/test_eval.py 9 9 49
tests/test-integration.sh 22 36 43
tests/test_browser.py 20 15 43
tests/test_dspy_gepa.py 18 9 39
tests/test_reduce.py 11 2 39
tests/test_tools_python.py 28 3 38
tests/test_util.py 28 51 37
tests/test_message_command.py 13 12 35
tests/test_tools_rag.py 15 8 34
tests/test_hybrid_lessons.py 14 8 33
tests/test_shell_for_loop_issue724.py 16 24 33
tests/test_chat.py 16 28 28
tests/test_telemetry.py 20 15 28
tests/test_xml_format.py 10 31 27
tests/test_chat_config.py 8 7 26
tests/data/example-patch-codeblock.txt 4 0 25
tests/data/example-interrupted.txt 8 0 24
tests/test_tool_loading_duplicate.py 16 15 24
tests/test_prompts.py 14 7 21
tests/test_tools_shell_multiline.py 7 19 19
tests/test_logmanager.py 8 5 18
tests/test_tools_chats.py 2 0 15
---------------------------------------------------------------------------------------------
SUM: 4566 4114 13073
---------------------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC Eval#
$ make cloc-eval
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/eval/**.py --by-file
github.com/AlDanial/cloc v 1.98 T=0.02 s (564.0 files/s, 91876.7 lines/s)
-------------------------------------------------------------------------------------
File blank comment code
-------------------------------------------------------------------------------------
gptme/eval/main.py 68 40 429
gptme/eval/run.py 55 39 324
gptme/eval/execenv.py 27 33 189
gptme/eval/agents.py 16 6 83
gptme/eval/types.py 15 12 40
gptme/eval/filestore.py 5 2 32
gptme/eval/cost.py 12 24 6
gptme/eval/__init__.py 1 0 4
gptme/eval/__main__.py 1 0 3
-------------------------------------------------------------------------------------
SUM: 200 156 1110
-------------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
LoC Total#
$ make cloc-total
make[2]: Entering directory '/home/runner/work/gptme/gptme'
cloc gptme/eval/cost.py gptme/eval/types.py gptme/eval/suites/basic.py gptme/eval/suites/browser.py gptme/eval/suites/__init__.py gptme/eval/suites/init_projects.py gptme/eval/execenv.py gptme/eval/main.py gptme/eval/filestore.py gptme/eval/agents.py gptme/eval/dspy/metrics.py gptme/eval/dspy/prompt_optimizer.py gptme/eval/dspy/signatures.py gptme/eval/dspy/hybrid_optimizer.py gptme/eval/dspy/cli.py gptme/eval/dspy/tasks.py gptme/eval/dspy/experiments.py gptme/eval/dspy/reasoning_program.py gptme/eval/dspy/__main__.py gptme/eval/dspy/__init__.py gptme/eval/__main__.py gptme/eval/__init__.py gptme/eval/run.py gptme/mcp/client.py gptme/mcp/registry.py gptme/mcp/__init__.py gptme/setup.py gptme/llm/utils.py gptme/llm/llm_openai.py gptme/llm/validate.py gptme/llm/llm_anthropic.py gptme/llm/llm_openai_models.py gptme/llm/__init__.py gptme/llm/models.py gptme/commands.py gptme/wut.py gptme/init.py gptme/server/api_v2_sessions.py gptme/server/auth.py gptme/server/workspace_api.py gptme/server/openapi_docs.py gptme/server/cli.py gptme/server/constants.py gptme/server/tasks_api.py gptme/server/api_v2_common.py gptme/server/exceptions.py gptme/server/client.py gptme/server/api_v2_agents.py gptme/server/api_v2.py gptme/server/api.py gptme/server/__main__.py gptme/server/__init__.py gptme/ncurses.py gptme/cli.py gptme/constants.py gptme/chat.py gptme/codeblock.py gptme/prompts.py gptme/lessons/selector_integration.py gptme/lessons/matcher_enhanced.py gptme/lessons/commands.py gptme/lessons/selector_config.py gptme/lessons/matcher.py gptme/lessons/auto_include.py gptme/lessons/hybrid_matcher.py gptme/lessons/parser.py gptme/lessons/__init__.py gptme/lessons/skills/python-repl/python_helpers.py gptme/lessons/index.py gptme/context/task_analyzer.py gptme/context/selector/hybrid.py gptme/context/selector/file_selector.py gptme/context/selector/llm_based.py gptme/context/selector/file_config.py gptme/context/selector/file_integration.py gptme/context/selector/config.py gptme/context/selector/rule_based.py gptme/context/selector/__init__.py gptme/context/selector/base.py gptme/context/compress.py gptme/context/config.py gptme/context/__init__.py gptme/tools/subagent.py gptme/tools/save.py gptme/tools/_browser_playwright.py gptme/tools/patch.py gptme/tools/_browser_thread.py gptme/tools/todo.py gptme/tools/autocompact.py gptme/tools/_browser_perplexity.py gptme/tools/tts.py gptme/tools/youtube.py gptme/tools/morph.py gptme/tools/tmux.py gptme/tools/chats.py gptme/tools/rag.py gptme/tools/python.py gptme/tools/computer.py gptme/tools/mcp_adapter.py gptme/tools/restart.py gptme/tools/complete.py gptme/tools/choice.py gptme/tools/gh.py gptme/tools/autocommit.py gptme/tools/mcp.py gptme/tools/vision.py gptme/tools/shell.py gptme/tools/browser.py gptme/tools/read.py gptme/tools/_browser_lynx.py gptme/tools/form.py gptme/tools/__init__.py gptme/tools/lessons.py gptme/tools/precommit.py gptme/tools/screenshot.py gptme/tools/base.py gptme/hooks/test.py gptme/hooks/markdown_validation.py gptme/hooks/time_awareness.py gptme/hooks/cwd_tracking.py gptme/hooks/cost_awareness.py gptme/hooks/token_awareness.py gptme/hooks/form_autodetect.py gptme/hooks/active_context.py gptme/hooks/__init__.py gptme/__version__.py gptme/message.py gptme/telemetry.py gptme/plugins/__init__.py gptme/__main__.py gptme/logmanager.py gptme/config.py gptme/dirs.py gptme/__init__.py gptme/util/context.py gptme/util/terminal.py gptme/util/interrupt.py gptme/util/cost.py gptme/util/export.py gptme/util/cost_tracker.py gptme/util/ask_execute.py gptme/util/output_storage.py gptme/util/_telemetry.py gptme/util/cli.py gptme/util/generate_name.py gptme/util/useredit.py gptme/util/reduce.py gptme/util/tokens.py gptme/util/_sound_cmd.py gptme/util/prompt.py gptme/util/auto_naming.py gptme/util/tree.py gptme/util/sound.py gptme/util/clipboard.py gptme/util/file_storage.py gptme/util/install.py gptme/util/gh.py gptme/util/_sound_sounddevice.py gptme/util/content.py gptme/util/__init__.py tests/test_tools_rag.py tests/test_shell_issue729.py tests/test_tools.py tests/test_tool_loading_duplicate.py tests/test_lessons_index.py tests/test_dspy_gepa.py tests/test_shell_issue772.py tests/test_eval.py tests/test_llm_models.py tests/test_cli.py tests/test_lessons_tool.py tests/test_xml_format.py tests/test_lesson_selector_integration.py tests/test_auto_compact.py tests/test_cost_tracker.py tests/test_tool_use.py tests/test_complete.py tests/test_server_v2_tool_confirmation.py tests/test_llm_anthropic.py tests/test_shell_for_loop_issue724.py tests/test_util_gh_mocked.py tests/test_lessons_status.py tests/test_mcp_adapter.py tests/test_file_selector_integration.py tests/test_dspy_reasoning_program.py tests/test_context_selector.py tests/test_util_cli_mcp.py tests/test_chat_config.py tests/test_tools_computer.py tests/test_prompt.py tests/benchmark_context_selector.py tests/context/test_task_analyzer.py tests/test_server_v2_auto_stepping.py tests/test_server_v2_sse.py tests/test_server.py tests/test_telemetry.py tests/test_server_auth.py tests/test_markdown_validation.py tests/test_util_cli.py tests/test_lessons_commands.py tests/test_auto_naming.py tests/test_codeblock.py tests/test_mcp_discovery.py tests/test_browser.py tests/test_hooks_form_autodetect.py tests/test_logmanager.py tests/test_plugins.py tests/test_tools_form.py tests/test_tools_token_awareness.py tests/test_util_gh.py tests/test_tools_chats.py tests/test_server_client.py tests/test_config.py tests/test_lessons_integration.py tests/test_tools_shell_multiline.py tests/test_lessons_parser.py tests/test_integration_phase4.py tests/test_prompts.py tests/test_llm_validate.py tests/test_reduce.py tests/test_tools_shell.py tests/test_llm_openai.py tests/test_lessons_matcher.py tests/test_dspy_hybrid.py tests/test_tools_save.py tests/test_tools_tts.py tests/test_tools_subagent.py tests/test_tools_python.py tests/test_hybrid_lessons.py tests/test_shell_output_mixing_issue408.py tests/test_message_command.py tests/test_dspy_integration.py tests/test_server_v2_hooks.py tests/test_tools_tmux.py tests/test_hooks.py tests/test_context.py tests/test_tools_todo.py tests/test_tree.py tests/test_mcp.py tests/test_server_v2.py tests/conftest.py tests/test_message.py tests/test_chat.py tests/test_custom_providers.py tests/test_prompt_tools.py tests/test_tools_time_awareness.py tests/test_util.py tests/test_dspy_basic.py tests/test_chat_history.py tests/test_tools_patch.py scripts/convert_convo.py scripts/auto_rename_logs.py scripts/analyze_compression.py scripts/list_user_messages.py scripts/check_rst_formatting.py scripts/gh-pr-view-with-pr-comments.py scripts/train/collect.py scripts/treeofthoughts.py scripts/gpt_todoer.py scripts/summarize_project.py scripts/reduce_context.py scripts/describe_api.py scripts/shorten_details.py scripts/github_bot.py --by-file
github.com/AlDanial/cloc v 1.98 T=0.43 s (610.7 files/s, 162249.1 lines/s)
-----------------------------------------------------------------------------------------------------
File blank comment code
-----------------------------------------------------------------------------------------------------
gptme/tools/shell.py 264 319 1078
tests/test_tools_shell.py 235 375 680
gptme/config.py 185 166 652
gptme/eval/dspy/tasks.py 170 374 639
gptme/server/api_v2_sessions.py 152 131 636
gptme/llm/llm_openai.py 140 100 615
gptme/llm/models.py 95 89 584
gptme/server/tasks_api.py 171 110 580
gptme/commands.py 145 94 557
gptme/llm/llm_anthropic.py 125 128 542
gptme/util/cli.py 142 73 498
gptme/tools/base.py 125 126 496
gptme/setup.py 113 59 478
tests/test_llm_openai.py 110 55 467
gptme/server/openapi_docs.py 177 140 455
scripts/analyze_compression.py 103 68 446
gptme/tools/computer.py 150 218 436
gptme/tools/autocompact.py 147 189 434
gptme/eval/main.py 68 40 429
gptme/prompts.py 118 140 415
gptme/hooks/__init__.py 134 120 413
tests/test_config.py 109 212 413
gptme/logmanager.py 107 101 409
scripts/github_bot.py 84 79 409
gptme/eval/dspy/prompt_optimizer.py 109 112 407
tests/test_util_gh_mocked.py 63 47 405
gptme/cli.py 67 57 393
tests/context/test_task_analyzer.py 119 58 389
tests/test_util_cli_mcp.py 89 45 380
gptme/chat.py 72 81 366
gptme/eval/dspy/cli.py 73 57 355
gptme/eval/dspy/experiments.py 94 60 352
tests/test_mcp_discovery.py 128 37 351
gptme/tools/gh.py 85 93 349
gptme/server/api.py 86 80 348
gptme/eval/dspy/metrics.py 98 98 344
gptme/telemetry.py 85 54 342
gptme/llm/__init__.py 79 77 340
tests/test_lessons_parser.py 152 176 338
tests/test_codeblock.py 214 489 331
tests/test_integration_phase4.py 66 54 331
gptme/util/_telemetry.py 87 97 326
gptme/eval/run.py 55 39 324
gptme/util/context.py 85 129 324
tests/test_auto_compact.py 150 134 324
gptme/server/api_v2.py 69 45 316
gptme/util/prompt.py 81 109 309
gptme/tools/tmux.py 85 141 307
gptme/tools/subagent.py 89 125 300
scripts/gh-pr-view-with-pr-comments.py 55 36 298
tests/test_cli.py 82 55 297
gptme/tools/mcp_adapter.py 89 84 290
gptme/eval/dspy/hybrid_optimizer.py 141 344 286
gptme/tools/tts.py 119 132 284
gptme/util/gh.py 55 66 284
gptme/message.py 62 78 281
gptme/tools/_browser_playwright.py 89 33 271
tests/test_lessons_commands.py 98 44 255
tests/test_context_selector.py 83 45 254
gptme/tools/save.py 55 53 253
gptme/plugins/__init__.py 83 116 248
tests/test_lessons_integration.py 91 59 242
tests/conftest.py 75 57 240
gptme/ncurses.py 39 5 238
gptme/context/task_analyzer.py 100 124 237
gptme/tools/patch.py 57 78 234
tests/test_server_v2.py 69 34 229
tests/test_llm_anthropic.py 26 0 221
tests/test_dspy_reasoning_program.py 62 53 217
gptme/mcp/registry.py 59 70 216
gptme/tools/__init__.py 63 44 216
gptme/tools/todo.py 85 95 211
gptme/util/_sound_sounddevice.py 52 52 208
gptme/util/ask_execute.py 53 46 203
tests/test_plugins.py 82 70 203
gptme/util/sound.py 65 72 200
tests/test_lessons_tool.py 55 26 194
tests/test_mcp_adapter.py 65 37 191
gptme/eval/dspy/reasoning_program.py 57 73 190
gptme/eval/execenv.py 27 33 189
gptme/tools/precommit.py 64 87 189
gptme/tools/lessons.py 71 87 184
tests/test_hooks.py 90 24 184
gptme/lessons/index.py 71 94 182
gptme/context/selector/file_selector.py 51 69 181
tests/test_server_v2_hooks.py 71 52 181
gptme/tools/mcp.py 55 44 179
tests/test_dspy_hybrid.py 65 45 179
gptme/lessons/parser.py 68 105 178
gptme/tools/morph.py 43 42 178
scripts/reduce_context.py 59 72 177
tests/test_lessons_index.py 68 50 174
gptme/llm/validate.py 29 27 173
gptme/tools/python.py 56 49 172
gptme/server/workspace_api.py 57 55 170
gptme/llm/llm_openai_models.py 2 11 169
gptme/mcp/client.py 39 26 168
tests/test_lessons_matcher.py 46 21 166
tests/test_tools_subagent.py 72 44 164
tests/test_mcp.py 41 31 162
gptme/tools/_browser_thread.py 27 12 157
tests/test_message.py 60 60 157
tests/test_tools_time_awareness.py 52 34 155
tests/test_cost_tracker.py 21 24 154
tests/test_context.py 72 48 152
gptme/server/api_v2_agents.py 38 28 149
gptme/codeblock.py 34 81 148
gptme/tools/form.py 38 43 147
scripts/check_rst_formatting.py 41 52 147
gptme/tools/rag.py 62 74 145
tests/test_file_selector_integration.py 50 23 145
gptme/tools/chats.py 43 49 142
tests/test_tree.py 54 29 142
gptme/hooks/token_awareness.py 44 51 141
tests/test_tool_use.py 12 19 140
gptme/server/client.py 60 78 139
gptme/util/__init__.py 31 22 139
tests/test_dspy_integration.py 54 32 139
tests/test_lesson_selector_integration.py 45 25 138
tests/test_tools_tmux.py 64 60 138
gptme/server/cli.py 26 17 137
gptme/lessons/hybrid_matcher.py 52 76 132
tests/test_dspy_basic.py 49 31 132
gptme/util/auto_naming.py 47 44 130
tests/benchmark_context_selector.py 32 26 130
gptme/hooks/form_autodetect.py 48 65 126
tests/test_tools_token_awareness.py 59 47 126
gptme/server/auth.py 45 69 121
tests/test_prompt.py 36 36 120
tests/test_complete.py 29 19 117
tests/test_tools_todo.py 53 46 117
gptme/lessons/commands.py 49 23 115
scripts/auto_rename_logs.py 34 23 115
tests/test_lessons_status.py 67 96 113
gptme/util/cost_tracker.py 44 62 112
scripts/gpt_todoer.py 47 25 107
scripts/train/collect.py 35 52 107
tests/test_auto_naming.py 37 23 106
gptme/tools/choice.py 31 25 105
tests/test_util_cli.py 35 28 105
gptme/tools/complete.py 34 41 104
gptme/llm/utils.py 38 48 103
tests/test_tools_tts.py 50 58 101
gptme/tools/restart.py 44 68 96
gptme/init.py 21 14 94
tests/test_tools_patch.py 58 139 93
gptme/util/tree.py 21 13 91
tests/test_tools_computer.py 36 27 91
tests/test_util_gh.py 39 28 91
tests/test_llm_validate.py 25 19 90
gptme/lessons/matcher_enhanced.py 26 40 87
tests/test_server_v2_auto_stepping.py 20 22 87
gptme/util/export.py 17 25 86
gptme/tools/_browser_perplexity.py 25 22 85
scripts/treeofthoughts.py 28 28 85
tests/test_server.py 27 10 85
gptme/tools/browser.py 40 87 84
tests/test_server_auth.py 40 19 84
gptme/eval/agents.py 16 6 83
gptme/hooks/time_awareness.py 29 31 83
scripts/convert_convo.py 34 54 82
gptme/lessons/auto_include.py 31 26 79
tests/test_prompt_tools.py 5 4 77
gptme/context/compress.py 63 131 76
gptme/util/reduce.py 24 35 76
tests/test_tools.py 45 6 76
gptme/tools/autocommit.py 37 59 75
tests/test_llm_models.py 27 14 75
tests/test_markdown_validation.py 43 34 75
tests/test_shell_issue729.py 50 52 75
gptme/hooks/cost_awareness.py 21 30 74
tests/test_shell_issue772.py 48 47 73
gptme/context/selector/llm_based.py 32 38 69
gptme/eval/suites/basic.py 17 0 69
gptme/server/api_v2_common.py 48 24 69
gptme/util/generate_name.py 5 6 69
tests/test_hooks_form_autodetect.py 22 34 68
tests/test_tools_form.py 22 19 67
tests/test_tools_save.py 15 10 65
gptme/__version__.py 15 11 64
gptme/util/_sound_cmd.py 22 17 64
gptme/lessons/skills/python-repl/python_helpers.py 28 26 63
gptme/eval/suites/init_projects.py 21 1 62
gptme/hooks/active_context.py 21 22 61
tests/test_server_v2_tool_confirmation.py 20 21 60
tests/test_shell_output_mixing_issue408.py 25 29 60
tests/test_server_client.py 33 26 59
gptme/util/output_storage.py 26 36 58
gptme/eval/dspy/signatures.py 19 21 56
tests/test_chat_history.py 14 12 56
gptme/context/selector/file_integration.py 13 10 55
gptme/dirs.py 27 14 55
scripts/describe_api.py 28 25 54
gptme/tools/vision.py 19 12 53
gptme/hooks/cwd_tracking.py 18 25 51
gptme/hooks/markdown_validation.py 36 41 51
gptme/lessons/matcher.py 26 24 51
tests/test_server_v2_sse.py 15 13 50
tests/test_custom_providers.py 23 32 49
tests/test_eval.py 9 9 49
gptme/context/selector/rule_based.py 18 12 47
gptme/tools/screenshot.py 14 12 44
gptme/util/tokens.py 22 16 44
gptme/util/cost.py 12 20 43
tests/test_browser.py 20 15 43
gptme/context/selector/file_config.py 13 11 42
gptme/eval/types.py 15 12 40
gptme/lessons/selector_config.py 18 20 40
gptme/util/file_storage.py 30 47 40
gptme/context/selector/hybrid.py 14 16 39
gptme/lessons/selector_integration.py 12 11 39
tests/test_dspy_gepa.py 18 9 39
tests/test_reduce.py 11 2 39
tests/test_tools_python.py 28 3 38
tests/test_util.py 28 51 37
gptme/util/clipboard.py 8 2 35
tests/test_message_command.py 13 12 35
gptme/util/terminal.py 23 21 34
tests/test_tools_rag.py 15 8 34
gptme/hooks/test.py 12 5 33
scripts/shorten_details.py 11 6 33
tests/test_hybrid_lessons.py 14 8 33
tests/test_shell_for_loop_issue724.py 16 24 33
gptme/eval/filestore.py 5 2 32
scripts/list_user_messages.py 10 9 32
gptme/util/install.py 13 24 31
gptme/wut.py 13 12 31
gptme/tools/_browser_lynx.py 9 13 30
gptme/util/content.py 18 24 29
tests/test_chat.py 16 28 28
tests/test_telemetry.py 20 15 28
gptme/context/selector/base.py 14 23 27
tests/test_xml_format.py 10 31 27
gptme/tools/youtube.py 10 1 26
scripts/summarize_project.py 12 1 26
tests/test_chat_config.py 8 7 26
gptme/lessons/__init__.py 7 15 24
tests/test_tool_loading_duplicate.py 16 15 24
gptme/context/config.py 12 26 21
gptme/context/selector/config.py 8 8 21
gptme/util/useredit.py 12 13 21
tests/test_prompts.py 14 7 21
gptme/util/interrupt.py 13 14 20
gptme/context/selector/__init__.py 6 13 19
gptme/eval/suites/__init__.py 3 0 19
tests/test_tools_shell_multiline.py 7 19 19
tests/test_logmanager.py 8 5 18
gptme/eval/suites/browser.py 5 0 17
gptme/constants.py 9 11 15
tests/test_tools_chats.py 2 0 15
gptme/mcp/__init__.py 1 0 14
gptme/tools/read.py 6 8 13
gptme/__init__.py 1 1 8
gptme/eval/dspy/__init__.py 6 6 7
gptme/eval/cost.py 12 24 6
gptme/context/__init__.py 3 6 4
gptme/eval/__init__.py 1 0 4
gptme/__main__.py 1 0 3
gptme/eval/__main__.py 1 0 3
gptme/eval/dspy/__main__.py 3 5 3
gptme/server/__init__.py 2 3 3
gptme/server/__main__.py 1 0 3
gptme/server/exceptions.py 5 8 2
gptme/server/constants.py 1 3 1
-----------------------------------------------------------------------------------------------------
SUM: 13207 13364 43567
-----------------------------------------------------------------------------------------------------
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
Code Metrics#
$ make metrics
make[2]: Entering directory '/home/runner/work/gptme/gptme'
=== Code Metrics Summary ===
Project Overview:
Files: 268
Total blocks: 2648
Average complexity: 4.437311178247734
Most Complex Functions (D+):
gptme/eval/main.py
F 285:0 main - D
gptme/eval/dspy/hybrid_optimizer.py
C 239:0 TaskComplexity - D
M 283:4 TaskComplexity.analyze - D
gptme/llm/llm_openai.py
F 115:0 init - D
F 353:0 stream - D
gptme/llm/llm_anthropic.py
F 393:0 stream - E
F 687:0 _prepare_messages_for_api - D
gptme/llm/__init__.py
F 258:0 _reply_stream - D
gptme/llm/models.py
F 477:0 get_model - D
gptme/commands.py
F 519:0 cmd_plugin - E
gptme/server/api_v2_sessions.py
F 220:0 step - E
gptme/server/openapi_docs.py
F 522:0 _convert_to_openapi_nullable - D
gptme/server/tasks_api.py
F 357:0 get_git_status - D
gptme/server/api_v2_agents.py
F 59:0 api_agents_put - D
gptme/cli.py
gptme/codeblock.py
F 71:0 _extract_codeblocks - E
gptme/prompts.py
F 526:0 prompt_chat_history - E
F 367:0 prompt_workspace - D
gptme/context/selector/file_selector.py
gptme/tools/autocompact.py
F 185:0 auto_compact_log - D
gptme/tools/tmux.py
F 324:0 execute_tmux - D
gptme/tools/computer.py
F 433:0 computer - D
gptme/tools/gh.py
F 57:0 _wait_for_checks - D
gptme/tools/shell.py
F 1446:0 _shorten_stdout - D
gptme/tools/lessons.py
F 159:0 auto_include_lessons_hook - D
gptme/hooks/token_awareness.py
F 88:0 add_token_usage_warning - D
gptme/telemetry.py
F 286:0 record_llm_request - E
gptme/plugins/__init__.py
F 141:0 _load_plugin - D
gptme/config.py
F 878:0 setup_config_from_cli - E
M 750:4 Config.mcp - D
gptme/util/context.py
F 434:0 _resource_to_codeblock - D
gptme/util/ask_execute.py
F 87:0 ask_execute - D
F 206:0 execute_with_confirmation - D
gptme/util/gh.py
tests/test_server_v2_auto_stepping.py
F 16:0 test_auto_stepping - E
tests/test_config.py
F 532:0 test_project_config_loaded_from_toml - D
F 560:0 test_project_config_loaded_from_json - D
scripts/auto_rename_logs.py
F 32:0 auto_rename_logs - D
scripts/check_rst_formatting.py
F 26:0 check_file - E
scripts/gh-pr-view-with-pr-comments.py
M 175:4 PRViewer.get_comments - D
Largest Files (>300 SLOC):
1158 gptme/tools/shell.py
947 gptme/eval/dspy/tasks.py
888 tests/test_tools_shell.py
654 gptme/config.py
636 gptme/server/api_v2_sessions.py
616 gptme/llm/llm_openai.py
610 tests/test_codeblock.py
596 gptme/llm/models.py
589 tests/test_config.py
580 gptme/server/tasks_api.py
560 gptme/commands.py
544 gptme/llm/llm_anthropic.py
502 gptme/tools/base.py
500 gptme/util/cli.py
492 gptme/tools/computer.py
487 gptme/setup.py
479 gptme/server/openapi_docs.py
469 tests/test_llm_openai.py
463 gptme/prompts.py
448 tests/test_lessons_parser.py
445 scripts/analyze_compression.py
439 gptme/tools/autocompact.py
432 gptme/eval/main.py
418 scripts/github_bot.py
413 gptme/hooks/__init__.py
412 gptme/logmanager.py
410 gptme/tools/gh.py
408 gptme/eval/dspy/prompt_optimizer.py
405 tests/test_util_gh_mocked.py
399 gptme/cli.py
389 tests/context/test_task_analyzer.py
380 tests/test_util_cli_mcp.py
374 gptme/tools/tmux.py
366 gptme/chat.py
357 gptme/eval/dspy/experiments.py
355 gptme/eval/dspy/cli.py
351 tests/test_mcp_discovery.py
349 gptme/server/api.py
349 gptme/eval/dspy/metrics.py
342 gptme/telemetry.py
340 gptme/llm/__init__.py
339 tests/test_auto_compact.py
339 gptme/util/context.py
335 gptme/tools/subagent.py
331 tests/test_integration_phase4.py
329 gptme/util/prompt.py
326 gptme/util/_telemetry.py
325 gptme/eval/run.py
316 gptme/server/api_v2.py
306 tests/test_cli.py
301 gptme/util/gh.py
make[3]: Entering directory '/home/runner/work/gptme/gptme'
Most Duplicated Files:
npm warn exec The following package was not found and will be installed: jscpd@4.0.5
Clone found (python):
- gptme/util/_sound_sounddevice.py [95:5 - 106:67] (11 lines, 101 tokens)
gptme/util/_sound_sounddevice.py [55:5 - 66:27]
Clone found (python):
- gptme/tools/gh.py [368:9 - 379:30] (11 lines, 92 tokens)
gptme/tools/gh.py [229:9 - 240:12]
Clone found (python):
- gptme/server/api.py [176:5 - 186:43] (10 lines, 83 tokens)
gptme/server/api_v2.py [162:5 - 172:4]
Clone found (python):
- gptme/server/api.py [187:5 - 193:2] (6 lines, 90 tokens)
gptme/server/api_v2.py [172:5 - 178:2]
Clone found (python):
- gptme/plugins/__init__.py [399:5 - 424:25] (25 lines, 183 tokens)
gptme/util/install.py [14:5 - 39:28]
Clone found (python):
- gptme/mcp/client.py [156:13 - 163:3] (7 lines, 75 tokens)
gptme/mcp/client.py [122:13 - 127:21]
Clone found (python):
- gptme/llm/validate.py [199:37 - 214:14] (15 lines, 103 tokens)
gptme/llm/validate.py [181:40 - 196:19]
Clone found (python):
- gptme/llm/validate.py [217:29 - 229:45] (12 lines, 97 tokens)
gptme/llm/validate.py [181:40 - 193:45]
Clone found (python):
- gptme/llm/llm_anthropic.py [405:5 - 437:54] (32 lines, 240 tokens)
gptme/llm/llm_anthropic.py [323:5 - 355:16]
Clone found (python):
- gptme/llm/llm_anthropic.py [441:7 - 454:2] (13 lines, 110 tokens)
gptme/llm/llm_anthropic.py [358:7 - 371:69]
Clone found (python):
- gptme/eval/dspy/cli.py [310:31 - 325:49] (15 lines, 104 tokens)
gptme/eval/dspy/cli.py [78:1 - 93:7]
Clone found (python):
- gptme/eval/dspy/cli.py [417:12 - 433:46] (16 lines, 93 tokens)
gptme/eval/dspy/cli.py [160:9 - 176:41]
Clone found (python):
- gptme/eval/dspy/cli.py [444:13 - 450:15] (6 lines, 84 tokens)
gptme/eval/dspy/cli.py [187:13 - 192:17]
Clone found (python):
- gptme/eval/execenv.py [167:9 - 189:50] (22 lines, 229 tokens)
gptme/eval/execenv.py [58:8 - 79:6]
Clone found (python):
- gptme/eval/execenv.py [208:2 - 218:64] (10 lines, 114 tokens)
gptme/eval/filestore.py [18:2 - 28:6]
Clone found (python):
- scripts/generate_sounds.py [165:2 - 173:13] (8 lines, 81 tokens)
scripts/generate_sounds.py [91:2 - 99:11]
Clone found (python):
- scripts/analyze_compression.py [152:43 - 164:2] (12 lines, 97 tokens)
scripts/analyze_compression.py [55:71 - 67:3]
Clone found (python):
- scripts/analyze_compression.py [220:9 - 231:24] (11 lines, 97 tokens)
scripts/analyze_compression.py [116:9 - 127:20]
Clone found (python):
- gptme/telemetry.py [57:2 - 80:4] (23 lines, 106 tokens)
gptme/util/_telemetry.py [235:5 - 258:7]
Clone found (python):
- gptme/telemetry.py [445:5 - 456:11] (11 lines, 90 tokens)
gptme/telemetry.py [110:9 - 121:10]
Clone found (python):
- gptme/commands.py [595:9 - 604:7] (9 lines, 90 tokens)
gptme/commands.py [546:9 - 555:6]
┌────────────┬────────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬───────────────────┐
│ Format │ Files analyzed │ Total lines │ Total tokens │ Clones found │ Duplicated lines │ Duplicated tokens │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ python │ 174 │ 45834 │ 296934 │ 21 │ 285 (0.62%) │ 2359 (0.79%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ css │ 1 │ 173 │ 1045 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ javascript │ 1 │ 395 │ 3314 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ markup │ 2 │ 264 │ 2183 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ markdown │ 6 │ 1237 │ 7952 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ bash │ 9 │ 335 │ 1587 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ url │ 1 │ 2 │ 16 │ 0 │ 0 (0%) │ 0 (0%) │
├────────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 194 │ 48240 │ 313031 │ 21 │ 285 (0.59%) │ 2359 (0.75%) │
└────────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 21 clones.
Detection time:: 3.082s
make[3]: Leaving directory '/home/runner/work/gptme/gptme'
make[2]: Leaving directory '/home/runner/work/gptme/gptme'
The metrics above show:
Project Overview: Basic stats about the codebase size and complexity
Complex Functions: Functions rated D+ (high complexity, should be refactored)
Large Files: Files over 300 SLOC (should be split into smaller modules)
Duplicated Files: Using jscpd to find duplicated code
We should aim to:
Keep average complexity below 4.0
Have no E-rated functions (extremely complex)
Have few D-rated functions (very complex)
Keep files under 300 SLOC where possible