Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Security: Kashkovsky/threadnote

docs/security.md

Security

Threadnote stores local canonical content under ~/.threadnote with private directories and files. Every threadnote:// identifier is parsed into validated portable segments; traversal, ambiguous encodings, escaping links, and unsupported file types are rejected.

Writes use per-resource locks, compare-and-swap where replacement semantics require it, a same-directory temporary file, durable close, and atomic rename. Derived index generations are activated by a checksummed pointer only after the full generation exists.

Model artifacts are pinned by immutable repository revision, byte count, SHA-256, role, runtime version, and license. Install and repair extract and verify the core embedding model embedded in the standalone executable; additional model roles require an explicit selection and download. Partial downloads are never loaded. The llama adapter requests prebuilt binaries and refuses runtime compilation or implicit binary download.

Share publishing scrubs known credential and machine-local path patterns before writing or pushing. Handoffs and preferences are not publishable. Publish order preserves the personal source until the shared canonical write, verification, git commit, and push succeed.

Obsidian sources require an explicit include allowlist and always exclude .obsidian/**, trash, configured Inbox folders, and managed projection folders. Source traversal rejects symbolic links and vault-boundary escapes. Content is secret-scanned before the sanitized copy is committed to the native store. External resource URIs impose external authority and untrusted trust; source frontmatter cannot elevate either value.

Obsidian projections write only managed paths, preserve edited and unmanaged files by default, and secret-scan each generated note before atomic replacement. Inbox notes form review candidates but never silently create durable memory.

The manager binds to loopback, uses a per-process bearer token, and never exposes a model or memory server. MCP uses stdio. Threadnote has no background daemon, listening storage port, or native HTTP MCP endpoint.

Anonymous operational telemetry is disabled by default and requires explicit persisted consent. It exports only a separate allowlisted diagnostic span for each eligible CLI command and MCP tool—including duration, bounded process memory, phase/state observations, and safe typed failures—and never the application's Effect span tree, logs, arguments, payloads, content, paths, exception messages, or stacks. There is no persistent installation identifier; correlation uses a random agent-session alias. DO_NOT_TRACK=1 and THREADNOTE_TELEMETRY=0 are kill switches. The complete data and destination contract is documented in Optional anonymous telemetry.

Official standalone installs and updates accept only immutable GitHub releases and verify the archive SHA-256 before extraction. macOS additionally requires valid code signatures during installation and Apple notarization acceptance before publication. Windows 4.6 archives are explicitly marked unsigned; the PowerShell installer and updater warn before activation and rely on the immutable GitHub release plus its verified SHA-256 checksum. Windows may therefore show a SmartScreen warning. Linux uses the same GitHub immutability and checksum trust root without an OS code signature. The repository's release authority is intentionally trusted: this model detects corrupted, substituted, or mutable delivery, but it does not claim to survive compromise of the repository publisher itself. Custom release APIs require an explicit untrusted-source opt-in.

There aren't any published security advisories