Memos is an open-source, self-hosted note-taking app that brings your everyday thoughts together in a personal timeline. Your data stays yours, and you choose what to keep private or share.
This report summarizes scanner evidence for usememos/memos, a Go project with 64,195 GitHub stars. SynthScan examined 245,953 lines of code across 1251 source files, recording 108 pattern matches distributed across 3 syntactic categories. The legacy adjusted pattern signal is 0.4 (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? 66 finding(s).
Are imports declared and package/API names verified? 42 finding(s).
Are wrappers, guards, and repeated structures necessary? 34 finding(s).
Which changes need focused human review? 108 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 108 distinct pattern matches across 3 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 | core/configuration/configuration_test.go | 20 | LookupEnv: func(string) (string, bool) { return "placeholder", true }, | CODE |
| LOW | core/configuration/plan_test.go | 184 | {Id: "openai", Title: "OpenAI", Type: storepb.AIProviderType_OPENAI, Endpoint: instancesetting.DefaultOpenAIEndpoint, | CODE |
| LOW | core/configuration/plan_test.go | 384 | reader.users = []*store.User{{ID: 1, Username: "admin", Role: store.RoleAdmin, Nickname: "Set by the user", Email: "adm | CODE |
| LOW | web/tests/quick-find-navigation.test.tsx | 213 | expect(input).toHaveAttribute("placeholder", "common.search Product · common.memos"); | CODE |
| LOW | web/tests/quick-find-navigation.test.tsx | 227 | expect(input).toHaveAttribute("placeholder", "common.search Product (123e4567…) · common.memos"); | CODE |
| LOW | web/tests/usage-limits-settings.test.tsx | 215 | expect(screen.getByRole("textbox", { name: "Largest file (MiB)" })).toHaveAttribute("placeholder", "Unlimited"); | CODE |
| LOW | markdown/parser/gfm_email_test.go | 30 | {name: "first email wins", source: "foo@bar.com@baz.example", expected: []GFMEmailMatch{emailMatch(0, 11, "foo@bar.com | CODE |
| LOW | markdown/parser/gfm_email_test.go | 34 | expected: []GFMEmailMatch{emailMatch(0, 11, "foo@bar.com"), emailMatch(11, 23, "+abc@def.com")}, | CODE |
| LOW | internal/email/message_test.go | 19 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 37 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 46 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 76 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 104 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 176 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 204 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/message_test.go | 238 | msg := Message{To: []string{"user@example.com"}, Subject: "Test", Body: "Test"} | CODE |
| LOW | internal/email/message_test.go | 258 | msg := Message{To: []string{"user@example.com"}, Subject: "Test", Body: "Test"} | CODE |
| LOW | internal/email/README.md | 43 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/README.md | 152 | To: []string{"user@example.com"}, | CODE |
| LOW | internal/email/README.md | 179 | Bcc: []string{"admin@example.com"}, | CODE |
| LOW | internal/email/doc.go | 55 | // To: []string{"user@example.com"}, | COMMENT |
| LOW | internal/email/doc.go | 74 | // To: []string{"user@example.com"}, | COMMENT |
| LOW | internal/email/config_test.go | 20 | SMTPUsername: "user@example.com", | CODE |
| LOW | internal/email/config_test.go | 31 | SMTPUsername: "user@example.com", | CODE |
| LOW | internal/email/config_test.go | 42 | SMTPUsername: "user@example.com", | CODE |
| LOW | internal/email/config_test.go | 53 | SMTPUsername: "user@example.com", | CODE |
| LOW | internal/email/client_test.go | 13 | SMTPUsername: "user@example.com", | CODE |
| LOW | provider/idp/oauth2/oauth2_test.go | 120 | testName = "John Doe" | CODE |
| LOW | server/api/sse_service_test.go | 459 | Username: "user", Role: store.RoleAdmin, Email: "user@example.com", | CODE |
| LOW | server/api/sse_service_test.go | 499 | Username: "user", Role: store.RoleAdmin, Email: "user@example.com", | CODE |
| LOW | server/api/sse_service_test.go | 529 | Username: "user", Role: store.RoleAdmin, Email: "user@example.com", | CODE |
| LOW | server/api/sse_service_test.go | 666 | Username: "user", Role: store.RoleAdmin, Email: "user@example.com", | CODE |
| LOW | server/api/sse_service_test.go | 706 | Username: "user", Role: store.RoleAdmin, Email: "user@example.com", | CODE |
| LOW | server/api/test/user_service_email_username_test.go | 189 | Username: "admin@example.com", | CODE |
| LOW | docs/design/memos-export-format.md | 139 | "location": { "placeholder": "Office", "latitude": 52.52, "longitude": 13.405 }, | CODE |
| LOW | docs/design/memo-export/1.0/memo.schema.json | 34 | "placeholder": { "type": "string" }, | CODE |
| LOW | filter/engine_test.go | 640 | {2, `{"location":{"placeholder":"Tokyo","latitude":35.6,"longitude":139.7}}`}, | CODE |
| LOW | store/seed/sqlite/01__dump.sql | 87 | INSERT INTO memo (id,uid,creator_id,created_ts,updated_ts,content,visibility,payload,space_id) VALUES(3,'goldenhour0001' | CODE |
| LOW⚡ | store/seed/sqlite/01__dump.sql | 120 | INSERT INTO memo (id,uid,creator_id,created_ts,updated_ts,content,visibility,payload,space_id) VALUES(12,'bobnighttrain1 | CODE |
| LOW⚡ | store/seed/sqlite/01__dump.sql | 123 | INSERT INTO memo (id,uid,creator_id,created_ts,updated_ts,content,visibility,payload,space_id) VALUES(13,'bobbucketlist1 | CODE |
| LOW⚡ | store/seed/sqlite/01__dump.sql | 129 | INSERT INTO memo (id,uid,creator_id,created_ts,updated_ts,content,visibility,payload,space_id) VALUES(15,'johnnyreading0 | CODE |
| LOW | store/test/configuration_state_test.go | 177 | require.Equal(t, "admin@example.com", created.Email, "the email is normalized as the store's writes do") | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | web/src/connect.ts | 102 | function shouldHandleUnauthenticatedRetry(error: unknown, isRetryAttempt: boolean): boolean { | CODE |
| LOW | web/src/contexts/MentionResolutionContext.tsx | 58 | export function useResolvedMentionUsernames(content: string) { | CODE |
| LOW | web/src/utils/redirect-safety.ts | 90 | export function shouldGatePrivateInstance(params: { isPrivateInstance: boolean; isAuthenticated: boolean; pathname: stri | CODE |
| LOW | web/src/utils/media-item.ts | 53 | export function buildAttachmentVisualItems(attachments: Attachment[]): AttachmentVisualItem[] { | CODE |
| LOW | web/src/utils/media-item.ts | 104 | export function countLogicalAttachmentItems(attachments: Attachment[]): number { | CODE |
| LOW | web/src/utils/media-item.ts | 115 | function buildSingleAttachmentItem(attachment: Attachment): AttachmentVisualItem { | CODE |
| LOW | web/src/utils/markdown-manipulation.ts | 117 | export function createUniqueSlugGenerator(reservedSlugs: Iterable<string> = []): (baseSlug: string) => string { | CODE |
| LOW | web/src/utils/tag-grammar.ts | 96 | function isNonCombiningXIDContinuationAt(source: string, index: number, limit: number): boolean { | CODE |
| LOW | web/src/components/CreateIdentityProviderDialog.tsx | 183 | function buildDialogStateFromTemplate(templateName: string) { | CODE |
| LOW | web/src/components/CreateIdentityProviderDialog.tsx | 202 | function buildDialogStateFromProvider(identityProvider: IdentityProvider) { | CODE |
| LOW | web/src/components/CreateIdentityProviderDialog.tsx | 263 | function CreateIdentityProviderDialog({ open, onOpenChange, identityProvider, onSuccess }: Props) { | CODE |
| LOW | web/src/components/ChangeMemberPasswordDialog.tsx | 19 | function ChangeMemberPasswordDialog({ open, onOpenChange, user, onSuccess }: Props) { | CODE |
| LOW | web/src/components/MemoDisplaySettingMenu.tsx | 44 | function MemoDisplaySettingsContent() { | CODE |
| LOW | web/src/components/UpdateCustomizedProfileDialog.tsx | 26 | function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props) { | CODE |
| LOW | web/src/components/Settings/sso-display.ts | 19 | export function getIdentityProviderTypeLabel(type: IdentityProvider_Type): string { | CODE |
| LOW | web/src/components/Settings/sso-display.ts | 60 | export function getIdentifierFilterSummary(filter: string, t: Translate): string { | CODE |
| LOW | web/src/components/PagedMemoList/PagedMemoList.tsx | 59 | function useAutoFetchWhenNotScrollable({ | CODE |
| LOW | web/src/components/ColumnGrid/ColumnGridContext.tsx | 30 | export function ColumnGridUntrappedProvider({ children }: { children: ReactNode }) { | CODE |
| LOW | web/src/components/MemoEditor/edit/types/attachment.ts | 87 | function visualItemToAttachmentItem(item: ReturnType<typeof buildAttachmentVisualItems>[number]): AttachmentItem { | CODE |
| LOW | …nents/MemoEditor/edit/utils/deriveDefaultCreateTime.ts | 10 | export function deriveDefaultCreateTimeFromFilters(filters: MemoFilter[], now: Date = new Date()): Date | undefined { | CODE |
| LOW | …nents/MemoEditor/edit/utils/deriveDefaultCreateTime.ts | 20 | export function deriveDefaultCreateTimeFromDate(value: string, now: Date = new Date()): Date | undefined { | CODE |
| LOW | …c/components/MemoEditor/edit/hooks/useAudioRecorder.ts | 16 | function getSupportedAudioMimeType(): string | undefined { | CODE |
| LOW | web/src/hooks/useAttachmentQueries.ts | 51 | export function useBatchDeleteAttachments() { | CODE |
| LOW | web/src/hooks/useMemoQueries.ts | 160 | export function findMemoInCollectionQueries(queryClient: QueryClient, name: string, freshOnly = false): Memo | undefined | CODE |
| LOW | web/src/hooks/useMemoQueries.ts | 194 | function patchMemoInCollectionQueries(queryClient: QueryClient, update: MemoPatch) { | CODE |
| LOW | web/src/hooks/useLiveMemoRefresh.ts | 480 | function invalidateLiveMemoQueries(queryClient: ReturnType<typeof useQueryClient>) { | CODE |
| LOW | web/src/hooks/useAttachmentLibrary.ts | 245 | export function useAttachmentLibraryStats(filter?: string) { | CODE |
| LOW | web/src/hooks/useAttachmentLibrary.ts | 253 | export function useUnusedAttachmentLibrary(locale: string, filter?: string, enabled = true) { | CODE |
| LOW | web/src/hooks/useUserQueries.ts | 286 | export function useUpdateUserGeneralSetting(currentUserName?: string) { | CODE |
| LOW | web/src/hooks/useUserQueries.ts | 317 | export function useUpdateUserEditorSetting(currentUserName?: string) { | CODE |
| LOW | web/src/hooks/useSpaceQueries.ts | 328 | export function useDeclineSpaceInvitation(viewerName: string) { | CODE |
| LOW | web/src/lib/context-suggestions.ts | 83 | export function getContextSuggestionCandidates(filters: MemoFilter[], viewFilter?: string): MemoSuggestion[] { | CODE |
| LOW | web/src/lib/suggestion-expression.ts | 92 | export function parseSuggestionExpression(source: string): SuggestionExpression | undefined { | CODE |
| LOW | web/src/lib/tag-suggestions.ts | 45 | export function getTagSuggestionCandidates(filters: MemoFilter[], viewFilter?: string): { tag: string; source: Suggestio | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | core/memoexport/doc.go | 1 | // Package memoexport implements the Memos Export Format: a ZIP container that | COMMENT |
| LOW | web/src/components/ui/popup.ts | 1 | // Shared enter/exit motion for popup surfaces (dropdown menu, popover, tooltip), driven by | COMMENT |
| LOW | markdown/doc.go | 1 | // Package markdown is the markdown engine: parsing memo content into the AST | COMMENT |
| LOW | internal/ratelimit/ratelimit.go | 81 | } | COMMENT |
| LOW | internal/profile/profile.go | 21 | // Port is the binding port for server | COMMENT |
| LOW | internal/email/doc.go | 1 | // Package email provides SMTP email sending functionality for self-hosted Memos instances. | COMMENT |
| LOW | internal/email/doc.go | 21 | // # Common SMTP Settings | COMMENT |
| LOW | internal/email/doc.go | 41 | // - UseTLS: true | COMMENT |
| LOW | internal/email/doc.go | 61 | // err := email.Send(config, message) | COMMENT |
| LOW | internal/email/doc.go | 81 | // | COMMENT |
| LOW | provider/ai/audio/webm.go | 21 | const ( | COMMENT |
| LOW | server/doc.go | 1 | // Package server is the HTTP process: it boots the net/http server, mounts every | COMMENT |
| LOW | server/test/startup_test.go | 41 | COMMENT | |
| LOW | server/auth/token.go | 81 | // RefreshTokenClaims contains claims for long-lived refresh tokens. | COMMENT |
| LOW | server/api/auth_service_session.go | 101 | // This endpoint implements refresh token rotation with sliding window sessions: | COMMENT |
| LOW | server/api/auth_service_session.go | 321 | // The address comes from the trusted-proxy resolver, never from a header | COMMENT |
| LOW | server/api/auth_service.go | 41 | }, nil | COMMENT |
| LOW | server/api/auth_service.go | 141 | // as the local lookup key. On the miss path, a local user is created with the | COMMENT |
| LOW | server/api/attachment_service_image.go | 81 | } | COMMENT |
| LOW | server/api/user_service_identities.go | 141 | } | COMMENT |
| LOW | server/api/user_service_access_tokens.go | 61 | // - Optional expiration time (can be never-expiring) | COMMENT |
| LOW | server/api/header_carrier.go | 81 | COMMENT | |
| LOW | server/api/memo_service_webhooks.go | 141 | // parseMemoOrderBy parses the order_by field and sets the appropriate ordering in memoFind. | COMMENT |
| LOW | server/api/authz.go | 81 | } | COMMENT |
| LOW | filter/engine_test.go | 521 | COMMENT | |
| LOW | filter/doc.go | 1 | // Package filter compiles the CEL filter expressions accepted by the list | COMMENT |
| LOW | store/memo.go | 161 | // transport-facing mutation. Drivers discover and authorize the current memo, | COMMENT |
| LOW | store/doc.go | 1 | // Package store is the persistence layer: the Store facade, the Driver | COMMENT |
| LOW | store/user_unique.go | 21 | // uniqueViolationMarkers precede the constraint, index, or column name in the | COMMENT |
| LOW | store/migrator.go | 21 | // Migration System Overview: | COMMENT |
| LOW | store/migrator.go | 41 | // - Every driver ships the same set of migration versions; a schema change is | COMMENT |
| LOW | store/db/sqlite/sqlite.go | 41 | // good practice to be explicit and prevent future surprises on SQLite upgrades. | COMMENT |