Access large language models from the command-line
This report summarizes scanner evidence for simonw/llm, a Python project with 12,604 GitHub stars. SynthScan examined 52,319 lines of code across 111 source files, recording 848 pattern matches distributed across 14 syntactic categories. The legacy adjusted pattern signal is 15.0 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 787 finding(s).
Are imports declared and package/API names verified? 36 finding(s).
Are wrappers, guards, and repeated structures necessary? 753 finding(s).
Which changes need focused human review? 848 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 848 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | llm/hookspecs.py | 18 | def register_embedding_models(register): | CODE |
| LOW⚡ | llm/hookspecs.py | 23 | def register_template_loaders(register): | CODE |
| LOW⚡ | llm/hookspecs.py | 28 | def register_fragment_loaders(register): | CODE |
| LOW | llm/models.py | 260 | def _get_arguments_input_schema(function, name): | CODE |
| LOW | llm/models.py | 289 | def _implementation_arguments(tool: "Tool", tool_call: "ToolCall") -> dict: | CODE |
| LOW | llm/models.py | 2736 | def _append_tool_results_to_chain(chain, tool_results, attachments) -> list[Any]: | CODE |
| LOW | llm/models.py | 2789 | def _trailing_pending_tool_calls(messages) -> list[ToolCall]: | CODE |
| LOW | llm/models.py | 3246 | def supported_server_side_tools(self) -> tuple[type[ServerSideTool], ...]: | CODE |
| LOW | llm/models.py | 3681 | def _remove_titles_recursively(obj): | CODE |
| LOW | llm/__init__.py | 239 | def get_embedding_models_with_aliases() -> list["EmbeddingModelWithAliases"]: | CODE |
| LOW | llm/__init__.py | 281 | def get_embedding_model_aliases() -> dict[str, EmbeddingModel]: | CODE |
| LOW | llm/__init__.py | 503 | def get_default_embedding_model(): | CODE |
| LOW | llm/__init__.py | 507 | def set_default_embedding_model(model): | CODE |
| LOW | llm/embeddings.py | 183 | def embed_multi_with_metadata( | CODE |
| LOW | llm/cli.py | 122 | async def display_async_stream_events(events, *, show_reasoning=True): | CODE |
| LOW | llm/cli.py | 299 | def process_fragments_in_chat( | CODE |
| LOW | llm/cli.py | 388 | def resolve_attachment_with_type(value: str, mimetype: str) -> Attachment: | CODE |
| LOW | llm/cli.py | 404 | def attachment_types_callback(ctx, param, values) -> list[Attachment]: | CODE |
| LOW | llm/cli.py | 439 | def _merge_template_attachments(template, attachments, attachment_types): | CODE |
| LOW | llm/cli.py | 1769 | def logs_json_for_response_ids(db, ids): | STRING |
| LOW | llm/cli.py | 2071 | def _format_tool_call_arguments(arguments): | STRING |
| LOW | llm/cli.py | 2409 | def model_matches_id_or_alias(model_with_aliases, model_ids): | STRING |
| LOW | llm/cli.py | 2416 | def render_model_with_aliases( | STRING |
| LOW | llm/cli.py | 2484 | def render_model_with_options(model_id, *, async_=False): | STRING |
| LOW | llm/utils.py | 181 | def extract_fenced_code_block(text: str, last: bool = False) -> str | None: | CODE |
| LOW | llm/logs.py | 1062 | def _needs_model_replacements(condensed: str) -> bool: | STRING |
| LOW | llm/logs.py | 1665 | def _instances_by_tool_call_id( | CODE |
| LOW | llm/default_plugins/openai_models.py | 452 | def register_embedding_models(register): | CODE |
| LOW | llm/default_plugins/openai_models.py | 1860 | def supported_server_side_tools(self): | CODE |
| LOW | llm/default_plugins/openai_models.py | 2147 | def _finalize_responses_kwargs(self, prompt, stream, instructions=None): | CODE |
| LOW | llm/default_plugins/openai_models.py | 2180 | def _reasoning_text_from_item(self, item): | CODE |
| LOW | llm/default_plugins/openai_models.py | 2225 | def _reasoning_refresh_events(self, response_json, done_events): | CODE |
| LOW | llm/default_plugins/openai_models.py | 2356 | def _refresh_server_tool_events(self, output, done_events): | CODE |
| LOW | llm/default_plugins/openai_models.py | 2381 | def _non_streaming_output_events( | CODE |
| LOW | tests/test_cli_openai_models.py | 48 | def test_openai_options_min_max(): | CODE |
| LOW | tests/test_cli_openai_models.py | 107 | def test_deprecated_models_are_not_registered(model_id): | CODE |
| LOW | tests/test_cli_openai_models.py | 216 | def test_code_interpreter_cli_tool_is_resolved_from_model(httpx2_mock): | CODE |
| LOW | tests/test_cli_openai_models.py | 273 | def test_code_interpreter_cli_tool_is_reused_on_continue( | CODE |
| LOW | tests/test_cli_openai_models.py | 396 | def test_web_search_cli_tool_is_resolved_from_model(httpx2_mock): | CODE |
| LOW | tests/test_cli_openai_models.py | 454 | def test_tools_list_for_model_includes_server_side_tools(): | CODE |
| LOW | tests/test_cli_openai_models.py | 486 | def test_tools_list_for_model_with_no_server_side_tools(): | CODE |
| LOW | tests/test_cli_openai_models.py | 497 | def test_tools_list_rejects_unknown_model(): | CODE |
| LOW | tests/test_cli_openai_models.py | 521 | def test_openai_image_detail_option_description(model_id, expected_description): | CODE |
| LOW | tests/test_cli_openai_models.py | 526 | def test_openai_image_detail_option_is_sent_on_image_attachments(httpx2_mock): | CODE |
| LOW | tests/test_cli_openai_models.py | 673 | def test_openai_image_detail_original_is_rejected_for_other_models(): | CODE |
| LOW | tests/test_async_parity.py | 17 | def test_echo_registered_for_both(): | CODE |
| LOW | tests/test_async_parity.py | 26 | async def test_async_to_dict_captures_chain_and_output(): | CODE |
| LOW | tests/test_async_parity.py | 40 | async def test_async_to_dict_raises_before_awaited(): | CODE |
| LOW | tests/test_async_parity.py | 48 | async def test_async_from_dict_rehydrates(): | CODE |
| LOW | tests/test_async_parity.py | 66 | async def test_async_from_dict_then_reply_continues(): | CODE |
| LOW | tests/test_async_parity.py | 90 | async def test_async_from_row_response_messages_synthesized(db_factory, tmp_path): | CODE |
| LOW | tests/test_async_parity.py | 135 | async def test_async_load_conversation_follow_up_preserves_chain(db_factory, tmp_path): | CODE |
| LOW | tests/test_async_parity.py | 186 | async def test_sync_and_async_produce_identical_chain(): | CODE |
| LOW | tests/test_async_parity.py | 205 | async def test_async_chain_tool_result_turn_has_full_chain(): | CODE |
| LOW | tests/test_async_parity.py | 244 | async def test_astream_events_matches_stream_events_for_text_only(): | CODE |
| LOW | tests/test_async_parity.py | 274 | async def test_async_from_dict_model_override(): | CODE |
| LOW | tests/test_async_parity.py | 286 | def test_sync_from_dict_model_override(): | CODE |
| LOW | tests/test_async_parity.py | 298 | async def test_async_to_dict_preserves_datetime(): | CODE |
| LOW | tests/test_async_parity.py | 308 | async def test_async_to_dict_preserves_usage_when_set(async_mock_model): | CODE |
| LOW | tests/test_async_parity.py | 326 | async def test_async_reply_messages_kwarg_appends(): | CODE |
| 653 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | llm/utils.py | 702 | if re.match(r'\s*(["\[\d\-]|true|false|null)', arg_body, re.IGNORECASE): | CODE |
| HIGH | llm/logs.py | 1111 | where json_extract(je.value, '$.literal') is not null) | CODE |
| HIGH | llm/migrations.py | 676 | and p2.tool_name is not null) as tools | CODE |
| HIGH⚡ | tests/test_llm_logs.py | 1450 | """When reasoning is empty/null, no heading appears (existing | STRING |
| HIGH⚡ | tests/test_plugins.py | 479 | '[{"id": ID, "tool_id": 1, "name": "upper", "output": "ONE", "tool_call_id": "tc_TCID", "exception": nul | CODE |
| HIGH⚡ | tests/test_plugins.py | 484 | '[{"id": ID, "tool_id": 1, "name": "upper", "output": "TWO", "tool_call_id": "tc_TCID", "exception": nul | CODE |
| HIGH⚡ | tests/test_plugins.py | 492 | '[{"id": ID, "tool_id": 1, "name": "upper", "output": "THREE", "tool_call_id": "tc_TCID", "exception": n | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/plugins.py | 23 | CODE | |
| LOW | llm/models.py | 604 | CODE | |
| LOW | llm/models.py | 104 | CODE | |
| LOW | llm/models.py | 1319 | CODE | |
| LOW | llm/models.py | 1887 | CODE | |
| LOW | llm/models.py | 2247 | CODE | |
| LOW | llm/models.py | 3038 | CODE | |
| LOW | llm/cli.py | 136 | CODE | |
| LOW | llm/cli.py | 228 | CODE | |
| LOW | llm/cli.py | 685 | CODE | |
| LOW | llm/cli.py | 1415 | CODE | |
| LOW | llm/cli.py | 1688 | CODE | |
| LOW | llm/cli.py | 1883 | CODE | |
| LOW | llm/cli.py | 2832 | CODE | |
| LOW | llm/cli.py | 3386 | CODE | |
| LOW | llm/cli.py | 3529 | CODE | |
| LOW | llm/cli.py | 3727 | CODE | |
| LOW | llm/cli.py | 2104 | CODE | |
| LOW | llm/cli.py | 3623 | CODE | |
| LOW | llm/utils.py | 76 | CODE | |
| LOW | llm/utils.py | 314 | CODE | |
| LOW | llm/utils.py | 588 | CODE | |
| LOW | llm/logs.py | 85 | CODE | |
| LOW | llm/logs.py | 896 | CODE | |
| LOW | llm/parts.py | 253 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 514 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 3070 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 605 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1240 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1412 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1530 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1773 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1954 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2066 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2264 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2381 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2513 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2757 | CODE | |
| LOW | tests/test_llm.py | 1046 | CODE | |
| LOW | tests/test_templates.py | 511 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | llm/__init__.py | 339 | except UnknownModelError: | CODE |
| HIGH | llm/__init__.py | 360 | except UnknownModelError: | CODE |
| HIGH | llm/cli.py | 1495 | except KeyError: | CODE |
| HIGH | llm/cli.py | 2028 | except ValueError: | CODE |
| HIGH | llm/cli.py | 2350 | except ValueError: | CODE |
| HIGH | llm/utils.py | 291 | except ValueError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/__init__.py | 11 | CODE | |
| LOW | llm/__init__.py | 12 | CODE | |
| LOW | llm/__init__.py | 12 | CODE | |
| LOW | llm/__init__.py | 12 | CODE | |
| LOW | llm/__init__.py | 17 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 18 | CODE | |
| LOW | llm/__init__.py | 43 | CODE | |
| LOW | llm/__init__.py | 43 | CODE | |
| LOW | llm/__init__.py | 43 | CODE | |
| LOW | llm/__init__.py | 43 | CODE | |
| LOW | llm/__init__.py | 43 | CODE | |
| LOW | llm/__init__.py | 52 | CODE | |
| LOW | tests/test_options_parameter.py | 112 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/models.py | 1988 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/models.py | 2321 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/models.py | 2376 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/models.py | 2420 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/models.py | 2444 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/models.py | 2462 | except Exception as ex: # noqa: BLE001 | CODE |
| MEDIUM | llm/cli.py | 381 | def convert(self, value, param, ctx): | CODE |
| LOW | llm/cli.py | 282 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/cli.py | 1142 | except Exception as ex: | CODE |
| LOW | llm/cli.py | 4263 | except Exception as ex: # noqa: BLE001 | CODE |
| LOW | llm/cli.py | 1668 | except Exception as ex: # noqa: BLE001 | STRING |
| LOW | llm/default_plugins/openai_models.py | 853 | except Exception as ex: | CODE |
| LOW | llm/default_plugins/openai_models.py | 2216 | except Exception: # noqa: BLE001 | CODE |
| LOW | docs/plugins/plugin-hooks.md | 221 | except Exception as e: | CODE |
| LOW | docs/plugins/plugin-hooks.md | 271 | except Exception as ex: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | llm/__init__.py | 444 | # Try to resolve it to an embedding model | COMMENT |
| MEDIUM | tests/test_embed_cli.py | 179 | # --key should be passed through to the embedding model | COMMENT |
| MEDIUM | tests/test_embed_cli.py | 200 | # --key should be passed through to the embedding model for embed-multi too | COMMENT |
| MEDIUM | tests/test_openai_responses.py | 1269 | # item, otherwise the model loses its chain of thought. | COMMENT |
| MEDIUM | docs/embeddings/python-api.md | 50 | To work with embeddings in this way you will need an instance of a [sqlite-utils Database](https://sqlite-utils.datasett | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/models.py | 493 | CODE | |
| LOW | llm/models.py | 823 | CODE | |
| LOW | llm/models.py | 877 | CODE | |
| LOW | llm/models.py | 956 | CODE | |
| LOW | llm/models.py | 1010 | CODE | |
| LOW | llm/models.py | 3293 | CODE | |
| LOW | llm/models.py | 3340 | CODE | |
| LOW | llm/models.py | 3419 | CODE | |
| LOW | llm/models.py | 3465 | CODE | |
| LOW | llm/logs.py | 1391 | CODE | |
| LOW | llm/logs.py | 1734 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1173 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 1678 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2455 | CODE | |
| LOW | llm/default_plugins/openai_models.py | 2701 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | README.md | 84 | Add `--key your-api-key` if the endpoint requires authentication. See [Run against an endpoint without configuring it](h | CODE |
| HIGH | docs/index.md | 52 | Add `--key your-api-key` if the endpoint requires authentication. See {ref}`Run against an endpoint without configuring | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | llm/cli.py | 4005 | # Create a test Options object to validate | STRING |
| MEDIUM | tests/test_templates.py | 162 | # Create a file to test attachment | COMMENT |
| MEDIUM | tests/test_chat_templates.py | 38 | # Create a system fragment file | COMMENT |
| MEDIUM | docs/conf.py | 28 | # This file is execfile()d with the current directory set to its | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/cli.py | 3664 | # Read the file twice - first time is to get a count | COMMENT |
| LOW | llm/utils.py | 379 | # Check if the schema is newline-separated or comma-separated | COMMENT |
| LOW | tests/test_utils.py | 466 | # Check if the correct number of backticks is used | COMMENT |
| LOW | .github/workflows/stable-docs.yml | 52 | # Check if the list of files is non-empty | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/models.py | 1141 | # truth for replay and for assembling response.messages. | COMMENT |
| LOW | llm/logs.py | 861 | def _load(value: str | None) -> dict | None: | COMMENT |
| LOW | llm/migrations.py | 721 | # only while sorted by path. | COMMENT |
| LOW | docs/conf.py | 21 | node.replace_self(replacement) | COMMENT |
| LOW | docs/conf.py | 141 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/__init__.py | 54 | __all__ = [ | CODE |
| LOW | llm/cli.py | 4166 | def set_model_option(model_id: str, key: str, value: Any) -> None: | CODE |
| LOW | llm/logs.py | 45 | __all__ = [ | CODE |
| LOW | llm/serialization.py | 41 | __all__ = [ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | llm/utils.py | 107 | def handle_request(self, request: httpx2.Request) -> httpx2.Response: | CODE |