Self-hosted bookmark manager that is designed be to be minimal, fast, and easy to set up using Docker.
This report presents the forensic synthetic code analysis of sissbruecker/linkding, a Python project with 10,841 GitHub stars. SynthScan v2.0 examined 56,829 lines of code across 331 source files, recording 1165 pattern matches distributed across 11 syntactic categories. The overall adjusted score of 18.2 places this repository in the Moderate AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
Longitudinal tracking requires multiple scan runs. Once this repository is re-scanned after new commits land, this chart will visualise how the synthetic code signal evolves over time — enabling you to detect whether AI authorship is growing, stabilising, or being actively corrected by human engineers.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 1165 distinct pattern matches across 11 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. 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 diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/admin.py | 141 | def delete_selected_bookmarks(self, request, queryset: QuerySet): | CODE |
| LOW | bookmarks/admin.py | 156 | def archive_selected_bookmarks(self, request, queryset: QuerySet): | CODE |
| LOW | bookmarks/admin.py | 171 | def unarchive_selected_bookmarks(self, request, queryset: QuerySet): | CODE |
| LOW | bookmarks/queries.py | 139 | def _filter_search_query_legacy( | CODE |
| LOW | bookmarks/queries.py | 318 | def query_archived_bookmark_tags( | CODE |
| LOW | bookmarks/queries.py | 328 | def query_shared_bookmark_tags( | CODE |
| LOW | bookmarks/queries.py | 341 | def query_shared_bookmark_users( | CODE |
| LOW | bookmarks/queries.py | 368 | def get_shared_tags_for_query( | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bundle_preview.py | 8 | def test_update_preview_on_filter_changes(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_dropdown.py | 20 | def test_click_toggle_opens_and_closes_dropdown(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_dropdown.py | 34 | def test_outside_click_closes_dropdown(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_dropdown.py | 48 | def test_escape_closes_dropdown_and_restores_focus(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_dropdown.py | 67 | def test_focus_out_closes_dropdown(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_dropdown.py | 83 | def test_aria_expanded_attribute(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_settings_general.py | 9 | def test_should_only_enable_public_sharing_if_sharing_is_enabled(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_settings_general.py | 56 | def test_should_not_show_bookmark_description_max_lines_when_display_inline(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_settings_general.py | 68 | def test_should_show_bookmark_description_max_lines_when_display_separate(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_settings_general.py | 80 | def test_should_update_bookmark_description_max_lines_when_changing_display(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_filter_drawer.py | 8 | def test_show_modal_close_modal(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_edit_bookmark_form.py | 29 | def test_should_not_check_for_existing_bookmark(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_edit_bookmark_form.py | 37 | def test_should_not_prefill_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_edit_bookmark_form.py | 50 | def test_enter_url_should_not_prefill_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_edit_bookmark_form.py | 63 | def test_refresh_button_should_be_visible_when_editing(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_collapse_side_panel.py | 23 | def test_side_panel_should_be_visible_by_default(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_collapse_side_panel.py | 33 | def test_side_panel_should_be_hidden_when_collapsed(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 36 | def test_active_bookmarks_bulk_select_across(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 73 | def test_archived_bookmarks_bulk_select_across(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 110 | def test_active_bookmarks_bulk_select_across_respects_query(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 147 | def test_archived_bookmarks_bulk_select_across_respects_query(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 184 | def test_select_all_toggles_all_checkboxes(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 207 | def test_select_all_shows_select_across(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 223 | def test_select_across_is_unchecked_when_toggling_all(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 244 | def test_select_across_is_unchecked_when_toggling_bookmark(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 265 | def test_execute_resets_all_checkboxes(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 296 | def test_update_select_across_bookmark_count(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_page_bulk_edit.py | 323 | def test_execute_button_is_disabled_when_no_bookmarks_selected(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_bookmark_item.py | 11 | def test_toggle_notes_should_show_hide_notes(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 31 | def test_enter_url_prefills_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 43 | def test_enter_url_does_not_overwrite_modified_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 57 | def test_with_initial_url_prefills_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 74 | def test_with_initial_url_title_description_does_not_overwrite_title_and_description( | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 92 | def test_create_should_check_for_existing_bookmark(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 129 | def test_enter_url_of_existing_bookmark_should_show_notes(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 142 | def test_create_should_preview_auto_tags(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 163 | def test_clear_buttons_only_shown_when_fields_have_content(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 193 | def test_refresh_button_only_shown_for_existing_bookmarks(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 220 | def test_refresh_from_website_button_updates_title_and_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 261 | def test_refresh_from_website_button_does_not_modify_fields_if_metadata_is_same( | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_new_bookmark_form.py | 303 | def test_ctrl_enter_submits_form_from_description(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_a11y_navigation_focus.py | 8 | def test_initial_page_load_focus(self): | CODE |
| LOW | bookmarks/tests_e2e/e2e_test_a11y_navigation_focus.py | 30 | def test_page_navigation_focus(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 40 | def test_partial_update_respects_query(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 52 | def test_partial_update_respects_sort(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 66 | def test_partial_update_respects_page(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 82 | def test_multiple_partial_updates(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 101 | def test_active_bookmarks_partial_update_on_archive(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 112 | def test_active_bookmarks_partial_update_on_delete(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 124 | def test_active_bookmarks_partial_update_on_mark_as_read(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 139 | def test_active_bookmarks_partial_update_on_unshare(self): | CODE |
| LOW | …ks/tests_e2e/e2e_test_bookmark_page_partial_updates.py | 154 | def test_active_bookmarks_partial_update_on_bulk_archive(self): | CODE |
| 1013 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | bookmarks/settings/base.py | 265 | # Creating a connection loads the ICU extension into the SQLite | COMMENT |
| MEDIUM⚡ | bookmarks/tests/test_assets_service.py | 498 | # Create a bookmark with an existing latest_snapshot | COMMENT |
| MEDIUM⚡ | bookmarks/tests/test_assets_service.py | 504 | # Create a new snapshot asset that will fail | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 150 | # Create a bookmark with a very long URL | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 324 | # Create a bookmark with a very long URL | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 412 | # Create a bookmark with a very long URL | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 522 | # Create a bookmark with an existing latest_snapshot | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 541 | # Create a bookmark with multiple snapshots | COMMENT |
| MEDIUM | bookmarks/tests/test_assets_service.py | 601 | # Create a bookmark with multiple snapshots | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/models.py | 123 | except Exception as error: | CODE |
| LOW | bookmarks/models.py | 164 | except Exception: | CODE |
| LOW | bookmarks/models.py | 179 | except Exception as error: | CODE |
| LOW | bookmarks/middlewares.py | 25 | except Exception: | CODE |
| LOW | bookmarks/utils.py | 16 | except Exception as exc: | CODE |
| LOW | bookmarks/management/commands/migrate_tasks.py | 57 | except Exception: | CODE |
| LOW | bookmarks/management/commands/migrate_tasks.py | 71 | except Exception: | CODE |
| LOW | bookmarks/api/routes.py | 123 | except Exception as e: | CODE |
| LOW | bookmarks/api/routes.py | 209 | except Exception as e: | CODE |
| LOW | bookmarks/api/routes.py | 235 | except Exception as e: | CODE |
| LOW | bookmarks/views/health.py | 13 | except Exception: | CODE |
| LOW | bookmarks/views/settings.py | 266 | except Exception: | CODE |
| LOW | bookmarks/views/settings.py | 295 | except Exception: | CODE |
| LOW | bookmarks/services/website_loader.py | 84 | except Exception: | CODE |
| LOW⚡ | bookmarks/services/tasks.py | 41 | except Exception as exc: | CODE |
| LOW | bookmarks/services/tasks.py | 224 | except Exception as exc: | CODE |
| LOW | bookmarks/services/tasks.py | 308 | except Exception as error: | CODE |
| LOW | bookmarks/services/importer.py | 69 | except Exception: | CODE |
| LOW | bookmarks/services/importer.py | 195 | except Exception: | CODE |
| LOW | bookmarks/services/assets.py | 49 | except Exception as error: | CODE |
| LOW | bookmarks/services/assets.py | 213 | except Exception as e: | CODE |
| LOW | bookmarks/services/bookmarks.py | 237 | except Exception as e: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | bookmarks/queries.py | 5 | from django.core.exceptions import ValidationError | CODE |
| CRITICAL | bookmarks/tests/test_bookmark_validation.py | 3 | from django.core.exceptions import ValidationError | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/utils.py | 83 | CODE | |
| LOW | bookmarks/queries.py | 60 | CODE | |
| LOW | bookmarks/tests_e2e/helpers.py | 32 | CODE | |
| LOW | bookmarks/tests/test_tag_cloud_template.py | 33 | CODE | |
| LOW | bookmarks/management/commands/full_backup.py | 15 | CODE | |
| LOW | bookmarks/views/tags.py | 113 | CODE | |
| LOW | bookmarks/services/assets.py | 88 | CODE | |
| LOW | bookmarks/services/assets.py | 170 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 353 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 419 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 511 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 59 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 126 | CODE | |
| LOW | bookmarks/services/search_query_parser.py | 303 | CODE | |
| LOW | bookmarks/services/favicon_loader.py | 60 | CODE | |
| LOW | bookmarks/services/bookmarks.py | 226 | CODE | |
| LOW | bookmarks/services/preview_image_loader.py | 27 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/models.py | 18 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/management/commands/enable_wal.py | 7 | logger = logging.getLogger(__name__) | CODE |
| LOW | …kmarks/management/commands/create_initial_superuser.py | 7 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/management/commands/generate_secret_key.py | 7 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/api/routes.py | 33 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/views/settings.py | 28 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/tags.py | 10 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/singlefile.py | 14 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/website_loader.py | 11 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/tasks.py | 18 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/importer.py | 12 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/assets.py | 21 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/favicon_loader.py | 14 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/bookmarks.py | 9 | logger = logging.getLogger(__name__) | CODE |
| LOW | bookmarks/services/preview_image_loader.py | 12 | logger = logging.getLogger(__name__) | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/models.py | 260 | CODE | |
| LOW | bookmarks/middlewares.py | 41 | CODE | |
| LOW | bookmarks/templatetags/shared.py | 67 | CODE | |
| LOW | bookmarks/templatetags/shared.py | 86 | CODE | |
| LOW | bookmarks/tests/helpers.py | 54 | CODE | |
| LOW | bookmarks/tests/helpers.py | 105 | CODE | |
| LOW | bookmarks/tests/helpers.py | 174 | CODE | |
| LOW | bookmarks/tests/helpers.py | 205 | CODE | |
| LOW | bookmarks/tests/helpers.py | 414 | CODE | |
| LOW | bookmarks/views/turbo.py | 26 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/tasks.py | 3 | CODE | |
| LOW | bookmarks/apps.py | 10 | CODE | |
| LOW | bookmarks/settings/__init__.py | 4 | CODE | |
| LOW | bookmarks/settings/__init__.py | 6 | CODE | |
| LOW | bookmarks/settings/dev.py | 9 | CODE | |
| LOW | bookmarks/settings/dev.py | 68 | CODE | |
| LOW | bookmarks/settings/prod.py | 12 | CODE | |
| LOW | bookmarks/settings/prod.py | 63 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/tests/test_auth_proxy_support.py | 21 | "auth_proxy_user", "user@example.com", "password123" | CODE |
| LOW⚡ | bookmarks/tests/test_auth_proxy_support.py | 43 | "auth_proxy_user", "user@example.com", "password123" | CODE |
| LOW⚡ | bookmarks/tests/test_auth_proxy_support.py | 53 | "auth_proxy_user", "user@example.com", "password123" | CODE |
| LOW | bookmarks/tests/helpers.py | 281 | user = User.objects.create_user(name, "user@example.com", "password123") | CODE |
| LOW | …environments/authelia-oidc/authelia/users_database.yml | 14 | email: 'admin@example.com' | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bookmarks/tests_e2e/helpers.py | 42 | # Check if THIS test is in failures/errors (not just any test) | COMMENT |
| LOW | bookmarks/management/commands/migrate_tasks.py | 15 | # Check if background_task table exists | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | install-linkding.sh | 1 | #!/usr/bin/env bash | COMMENT |
| LOW | docs/src/env.d.ts | 1 | /// <reference path="../.astro/types.d.ts" /> | COMMENT |