The user-friendly command line shell.
This report summarizes scanner evidence for fish-shell/fish-shell, a Rust project with 34,374 GitHub stars. SynthScan examined 119,425 lines of code across 359 source files, recording 212 pattern matches distributed across 16 syntactic categories. The legacy adjusted pattern signal is 2.9 (Low 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.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 172 finding(s).
Are imports declared and package/API names verified? 22 finding(s).
Are wrappers, guards, and repeated structures necessary? 34 finding(s).
Which changes need focused human review? 212 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 212 distinct pattern matches across 16 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 | crates/gettext-mo-file-parser/src/lib.rs | 21 | } | COMMENT |
| LOW | crates/gettext-extraction/src/lib.rs | 81 | /// the message ID is written into a new file in this directory, | COMMENT |
| LOW | crates/wgetopt/src/lib.rs | 41 | /// regardless of [Ordering]. | COMMENT |
| LOW | crates/wgetopt/src/lib.rs | 61 | /// Indicates whether an option takes an argument, and whether that argument | COMMENT |
| LOW | crates/wgetopt/src/lib.rs | 121 | shortopts: &'opts wstr, | COMMENT |
| LOW | crates/util/src/lib.rs | 1 | //! Generic utilities library. | COMMENT |
| LOW | crates/util/src/lib.rs | 21 | /// file1.txt | COMMENT |
| LOW | crates/color/src/lib.rs | 141 | } else { | COMMENT |
| LOW | crates/fluent/src/lib.rs | 181 | } | COMMENT |
| LOW | crates/fluent/src/lib.rs | 201 | /// | COMMENT |
| LOW | crates/fluent/src/lib.rs | 221 | $( | COMMENT |
| LOW | crates/printf/src/lib.rs | 21 | /// let s = sprintf!("%0.5g", 123456.0); | COMMENT |
| LOW | crates/printf/src/lib.rs | 61 | }; | COMMENT |
| LOW | crates/printf/src/lib.rs | 81 | /// let mut output = String::new(); | COMMENT |
| LOW | crates/printf/src/printf_impl.rs | 321 | /// Formats a string using the provided format specifiers, arguments, and locale, | COMMENT |
| LOW | crates/printf/src/locale.rs | 1 | /// The numeric locale. Note this is a pure value type. | COMMENT |
| LOW | crates/printf/src/fmt_fp/decimal.rs | 241 | // which is given by remainder (that is, remainder = self[digit_idx] % mod_base). | COMMENT |
| LOW | crates/printf/src/fmt_fp/mod.rs | 101 | COMMENT | |
| LOW | crates/common/src/lib.rs | 1221 | /// let cell = ScopedCell::new(5); | COMMENT |
| LOW | crates/common/src/lib.rs | 1261 | COMMENT | |
| LOW | crates/common/src/lib.rs | 1301 | } | COMMENT |
| LOW | crates/common/src/lib.rs | 1321 | pub fn scoped_replace(&self, value: T) -> impl DerefMut + use<T> { | COMMENT |
| LOW | crates/common/src/lib.rs | 1341 | /// use fish_common::ScopeGuard; | COMMENT |
| LOW | crates/common/src/lib.rs | 1381 | } | COMMENT |
| LOW | crates/common/src/lib.rs | 1401 | /// const COLORS: &[(&wstr, u32)] = &[ | COMMENT |
| LOW | crates/widestring/src/lib.rs | 41 | // | COMMENT |
| LOW | crates/widestring/src/lib.rs | 81 | /// Character representing process expansion for %self. | COMMENT |
| LOW | crates/widestring/src/lib.rs | 341 | const ENCODED_PUA_CHAR_SECOND_CHAR_RANGE: Range<char> = | COMMENT |
| LOW | crates/widestring/src/lib.rs | 361 | /// The buffers have to be considered before taking more chars from `encoded_chars`. | COMMENT |
| LOW | crates/widestring/src/lib.rs | 581 | pub unsafe fn charptr2wcstring(input: *const libc::c_char) -> WString { | COMMENT |
| LOW | crates/xtask/src/gettext.rs | 21 | COMMENT | |
| LOW | crates/xtask/src/fluent.rs | 41 | from_source: Option<Option<PathBuf>>, | COMMENT |
| LOW | crates/xtask/src/fluent.rs | 61 | /// If a Fluent variable is renamed or removed, the translations of the message will be deleted. | COMMENT |
| LOW | crates/xtask/src/fluent.rs | 81 | /// The message ID. | COMMENT |
| LOW | crates/xtask/src/fluent.rs | 101 | /// indicate that translators should have a look at it. | COMMENT |
| LOW | crates/xtask/src/main.rs | 41 | /// Run ShellCheck on non-fish shell scripts | COMMENT |
| LOW | doc_src/conf.py | 141 | # This is also used if you do content translation via gettext catalogs. | COMMENT |
| LOW | doc_src/conf.py | 161 | # a list of builtin themes. | COMMENT |
| LOW | doc_src/conf.py | 281 | # Bibliographic Dublin Core info. | COMMENT |
| LOW | tests/fish_test_helper.c | 1 | // fish_test_helper is a little program with no fish dependencies that acts like certain other | COMMENT |
| LOW | tests/pexpects/commandline.py | 121 | # send(control("u") * 6) | COMMENT |
| LOW | tests/pexpects/bind.py | 141 | # Delay needed to allow fish to transition to vi "normal" mode. | COMMENT |
| LOW | tests/pexpects/history.py | 1 | #!/usr/bin/env python3 | COMMENT |
| LOW | src/job_group.rs | 41 | } | COMMENT |
| LOW | src/job_group.rs | 61 | /// the terminal to the same state when resuming a stopped job. | COMMENT |
| LOW | src/job_group.rs | 121 | COMMENT | |
| LOW | src/timer.rs | 1 | //! This module houses `TimerSnapshot` which can be used to calculate the elapsed time (system CPU | COMMENT |
| LOW | src/exec.rs | 121 | return false; | COMMENT |
| LOW | src/exec.rs | 361 | } | COMMENT |
| LOW | src/exec.rs | 1221 | /// the pipeline should be cancelled. | COMMENT |
| LOW | src/exec.rs | 1241 | // so that stdout and stderr both wind up referencing the pipe. | COMMENT |
| LOW | src/tty_handoff.rs | 341 | // Called from a signal handler to mark the tty as invalid (e.g. SIGHUP). | COMMENT |
| LOW | src/tty_handoff.rs | 441 | COMMENT | |
| LOW | src/parse_util.rs | 101 | COMMENT | |
| LOW | src/parse_util.rs | 981 | inc_dec = (1, 1); | COMMENT |
| LOW | src/terminal.rs | 341 | pub fn style_writer(&mut self) -> OutputterStyleWriter<'_> { | COMMENT |
| LOW | src/proc.rs | 341 | } | COMMENT |
| LOW | src/screen.rs | 221 | COMMENT | |
| LOW | src/topic_monitor.rs | 261 | } | COMMENT |
| LOW | src/topic_monitor.rs | 301 | COMMENT | |
| 54 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/pexpects/wildcard_tab.py | 67 | sendline(r"mkdir benchmarks && mkdir benchmarks/somedir && touch benchmarks/somefile") | CODE |
| HIGH | tests/pexpects/pipeline.py | 28 | # 'not' because we expect to have no jobs, in which case `jobs` will return false | COMMENT |
| HIGH⚡ | tests/pexpects/isatty.py | 20 | test -t 0 && echo stdin | STRING |
| HIGH⚡ | tests/pexpects/isatty.py | 21 | test -t 1 && echo stdout | STRING |
| HIGH⚡ | tests/pexpects/isatty.py | 22 | test -t 2 && echo stderr | STRING |
| HIGH | tests/pexpects/isatty.py | 60 | sendline("isatty stdin && echo yes") | CODE |
| HIGH | tests/pexpects/isatty.py | 64 | sendline("cat </dev/null | isatty stdin || echo no") | CODE |
| HIGH | tests/pexpects/autosuggest.py | 77 | run("touch configure && chmod +x configure") | CODE |
| HIGH | tests/pexpects/status.py | 28 | sendline("true 7 && status current-commandline") | CODE |
| HIGH | tests/pexpects/status.py | 29 | expect_prompt("\r\n.*true 7 && status current-commandline\r\n") | CODE |
| HIGH | tests/pexpects/read.py | 58 | sendline(r"read -c init_text somevar && echo $somevar") | CODE |
| HIGH | tests/pexpects/read.py | 63 | sendline(r"read --command='some other text' somevar && echo $somevar") | CODE |
| HIGH | share/tools/web_config/webconfig.py | 807 | + "if set -q __fish_initialized && test $__fish_initialized -lt 4300\n" | CODE |
| HIGH | share/tools/web_config/webconfig.py | 999 | + "funcsave fish_prompt && funcsave fish_right_prompt 2>/dev/null" | CODE |
| HIGH | share/tools/web_config/webconfig.py | 1019 | + '" \n false \n functions -q fish_right_prompt && fish_right_prompt\n' | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/pexpects/read.py | 126 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 32 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 37 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 39 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 41 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 50 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 52 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 54 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 60 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 65 | # ========== | COMMENT |
| MEDIUM⚡ | tests/pexpects/history.py | 72 | # ========== | COMMENT |
| MEDIUM | tests/pexpects/history.py | 99 | # ========== | COMMENT |
| MEDIUM | tests/pexpects/history.py | 106 | # ========== | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | doc_src/fish_synopsis.py | 85 | CODE | |
| LOW | doc_src/conf.py | 216 | CODE | |
| LOW | tests/test_driver.py | 111 | CODE | |
| LOW | tests/test_driver.py | 306 | CODE | |
| LOW | tests/pexpect_helper.py | 75 | CODE | |
| LOW | tests/littlecheck.py | 796 | CODE | |
| LOW | tests/littlecheck.py | 207 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 1251 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 1872 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 2088 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 468 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 517 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 588 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 655 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 680 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 885 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 930 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 1092 | CODE | |
| LOW | share/tools/create_manpage_completions.py | 1708 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 229 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 1429 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 1125 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 1146 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 1183 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 267 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | doc_src/conf.py | 24 | except ImportError: | CODE |
| HIGH | share/tools/create_manpage_completions.py | 1868 | except (OSError, IOError): | CODE |
| HIGH | share/tools/create_manpage_completions.py | 2116 | except FileNotFoundError: | CODE |
| HIGH | share/tools/web_config/webconfig.py | 1472 | except socket.error: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/ast.rs | 2396 | // exhausted the stream as requested. | COMMENT |
| HIGH | src/builtins/read.rs | 309 | /// Read from the fd in chunks until we see newline or null, as requested, is seen. This is only | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/pexpect_helper.py | 197 | def send_cursor_position_report(self, *, y: int, x: int): | CODE |
| LOW | tests/pexpect_helper.py | 202 | def send_primary_device_attribute(self): | CODE |
| LOW | tests/pexpect_helper.py | 285 | def report_exception_and_exit(self, pat, unmatched, err): | CODE |
| LOW | share/tools/create_manpage_completions.py | 1851 | def cleanup_autogenerated_completions_in_directory(dir): | STRING |
| LOW | share/tools/create_manpage_completions.py | 1864 | def cleanup_autogenerated_file(path): | STRING |
| LOW | share/tools/create_manpage_completions.py | 2018 | def parse_and_output_man_pages(paths, output_directory, show_progress): | STRING |
| LOW | share/tools/create_manpage_completions.py | 2088 | def get_paths_from_man_locations(): | STRING |
| LOW | share/tools/web_config/webconfig.py | 356 | def html_color_for_ansi_color_index(val): | CODE |
| LOW | share/tools/web_config/webconfig.py | 625 | def append_html_for_ansi_escape(full_val, result, span_open): | CODE |
| LOW | share/tools/web_config/webconfig.py | 800 | class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | CODE |
| LOW | share/tools/web_config/webconfig.py | 963 | def do_set_color_for_variable(self, name, color): | CODE |
| LOW | share/tools/web_config/webconfig.py | 1053 | def parse_one_sample_prompt_hash(self, line, result_dict): | CODE |
| LOW | share/tools/web_config/webconfig.py | 1094 | def do_get_sample_prompts_list(self): | CODE |
| LOW | share/tools/web_config/webconfig.py | 1125 | def font_size_for_ansi_prompt(self, prompt_demo_ansi): | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/littlecheck.py | 838 | # To facilitate integration with testing frameworks, use exit code 125 to indicate that all | COMMENT |
| MEDIUM | tests/pexpects/history.py | 8 | # meant to be a comprehensive test of the history subsystem. Those types of | COMMENT |
| LOW | build_tools/make_linux_packages.sh | 72 | # just use dpkg-buildpackage directly | COMMENT |
| LOW | share/tools/create_manpage_completions.py | 2104 | # If we can't have the OS interpret $MANPATH, just use it as-is (gulp). | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/env_universal_common.rs | 641 | const SAVE_MSG: &[u8] = b"# This file contains fish universal variable definitions.\n"; | CODE |
| MEDIUM | src/env_universal_common.rs | 948 | "# This file contains fish universal variable definitions.\n", | CODE |
| MEDIUM | src/env_universal_common.rs | 966 | "# This file contains fish universal variable definitions.\n", | CODE |
| MEDIUM | src/env_universal_common.rs | 1029 | "# This file contains fish universal variable definitions.\n", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | Cargo.toml | 10 | # don't forget to update COPYING and debian/copyright too | COMMENT |
| LOW | Cargo.toml | 10 | # don't forget to update COPYING and debian/copyright too | COMMENT |
| LOW | src/parser_keywords.rs | 40 | // Don't forget to add any new reserved keywords to the documentation | COMMENT |
| MEDIUM | src/builtins/string/shorten.rs | 155 | // This should work for most cases considering the combiners typically have width 0. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | doc_src/fish_indent_lexer.py | 7 | CODE | |
| LOW | doc_src/conf.py | 19 | CODE | |
| LOW | tests/test_driver.py | 21 | CODE | |
| LOW | tests/pexpect_helper.py | 16 | CODE | |
| LOW | tests/littlecheck.py | 5 | CODE | |
| LOW | tests/littlecheck.py | 6 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 4 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | share/tools/create_manpage_completions.py | 1362 | CODE | |
| LOW | share/tools/web_config/webconfig.py | 1045 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | doc_src/fish_synopsis.py | 3 | # Example usage: | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/fs.rs | 280 | /// # Return value | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/env_dispatch.rs | 510 | // TODO: Add tests for the locale vars. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_driver.py | 233 | except Exception as e: | CODE |