diff --git a/hindsight-docs/blog/2026-02-09-resolving-memory-conflicts.md b/hindsight-docs/blog/2026-02-09-resolving-memory-conflicts.md
index 96f77efc..2a8db62f 100644
--- a/hindsight-docs/blog/2026-02-09-resolving-memory-conflicts.md
+++ b/hindsight-docs/blog/2026-02-09-resolving-memory-conflicts.md
@@ -1,4 +1,14 @@
+---
+title: How We Solved Memory Conflicts in Hindsight
+description: Learn how Hindsight handles contradictory information by tracking temporal evolution and preserving history in its memory consolidation system.
+authors: [hindsight]
+tags: [engineering, memory-systems, conflict-resolution]
+image: /img/blog/2026-02-09/consolidation-pipeline.png
+date: 2026-02-09
+---
+
# How We Solved Memory Conflicts in Hindsight
+
One of the hardest problems we tackled in Hindsight was dealing with contradictions. When you're building a memory system for AI agents, reality isn't static. It evolves.
A CRM agent might learn that "Acme Corp is a key prospect" in January, then encounter "Acme Corp is now a paying customer" in March. Naive approaches either lose the history or drown in duplicate facts.
diff --git a/hindsight-docs/src/components/CopyPageButton/index.tsx b/hindsight-docs/src/components/CopyPageButton/index.tsx
new file mode 100644
index 00000000..3147af7f
--- /dev/null
+++ b/hindsight-docs/src/components/CopyPageButton/index.tsx
@@ -0,0 +1,162 @@
+import React, { useState, useCallback } from 'react';
+import styles from './styles.module.css';
+
+export default function CopyPageButton(): JSX.Element | null {
+ const [copied, setCopied] = useState(false);
+
+ const copyPageAsMarkdown = useCallback(async () => {
+ try {
+ // Get the page content
+ const contentElement = document.querySelector('.markdown');
+ if (!contentElement) return;
+
+ // Convert HTML to markdown-like text
+ let markdown = '';
+
+ // Add title
+ const title = document.querySelector('h1')?.textContent;
+ if (title) {
+ markdown += `# ${title}\n\n`;
+ }
+
+ // Extract text content from the markdown container
+ const extractMarkdown = (element: Element): string => {
+ let text = '';
+
+ const processNode = (node: Node): string => {
+ if (node.nodeType === Node.TEXT_NODE) {
+ return node.textContent || '';
+ }
+
+ if (node.nodeType === Node.ELEMENT_NODE) {
+ const el = node as Element;
+ const tagName = el.tagName.toLowerCase();
+ const children = Array.from(el.childNodes).map(processNode).join('');
+
+ switch (tagName) {
+ case 'h1':
+ return `# ${children}\n\n`;
+ case 'h2':
+ return `## ${children}\n\n`;
+ case 'h3':
+ return `### ${children}\n\n`;
+ case 'h4':
+ return `#### ${children}\n\n`;
+ case 'h5':
+ return `##### ${children}\n\n`;
+ case 'h6':
+ return `###### ${children}\n\n`;
+ case 'p':
+ return `${children}\n\n`;
+ case 'ul':
+ return `${children}\n`;
+ case 'ol':
+ return `${children}\n`;
+ case 'li':
+ const parent = el.parentElement;
+ const isOrdered = parent?.tagName.toLowerCase() === 'ol';
+ if (isOrdered) {
+ const index = Array.from(parent?.children || []).indexOf(el) + 1;
+ return `${index}. ${children}\n`;
+ }
+ return `- ${children}\n`;
+ case 'code':
+ const isBlock = el.parentElement?.tagName.toLowerCase() === 'pre';
+ if (isBlock) {
+ const lang = el.className.replace('language-', '');
+ return `\`\`\`${lang}\n${children}\n\`\`\`\n\n`;
+ }
+ return `\`${children}\``;
+ case 'pre':
+ return children; // Already handled by code block
+ case 'blockquote':
+ return children.split('\n').map(line => `> ${line}`).join('\n') + '\n\n';
+ case 'a':
+ const href = el.getAttribute('href') || '';
+ return `[${children}](${href})`;
+ case 'strong':
+ case 'b':
+ return `**${children}**`;
+ case 'em':
+ case 'i':
+ return `*${children}*`;
+ case 'br':
+ return '\n';
+ case 'hr':
+ return '---\n\n';
+ case 'table':
+ return `${children}\n`;
+ case 'thead':
+ case 'tbody':
+ return children;
+ case 'tr':
+ return `${children}|\n`;
+ case 'th':
+ case 'td':
+ return `| ${children} `;
+ case 'img':
+ const src = el.getAttribute('src') || '';
+ const alt = el.getAttribute('alt') || '';
+ return ``;
+ default:
+ return children;
+ }
+ }
+
+ return '';
+ };
+
+ Array.from(element.childNodes).forEach(node => {
+ text += processNode(node);
+ });
+
+ return text;
+ };
+
+ // Skip the title h1 if it's already added
+ const contentToCopy = Array.from(contentElement.children)
+ .filter(child => !(child.tagName === 'H1' && child.textContent === title))
+ .map(child => extractMarkdown(child))
+ .join('');
+
+ markdown += contentToCopy;
+
+ // Clean up excessive newlines
+ markdown = markdown.replace(/\n{3,}/g, '\n\n').trim();
+
+ // Copy to clipboard
+ await navigator.clipboard.writeText(markdown);
+
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch (error) {
+ console.error('Failed to copy page content:', error);
+ }
+ }, []);
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/hindsight-docs/src/components/CopyPageButton/styles.module.css b/hindsight-docs/src/components/CopyPageButton/styles.module.css
new file mode 100644
index 00000000..7db51752
--- /dev/null
+++ b/hindsight-docs/src/components/CopyPageButton/styles.module.css
@@ -0,0 +1,55 @@
+.copyPageButton {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 12px;
+ background: transparent;
+ border: 1px solid var(--ifm-color-emphasis-300);
+ border-radius: 6px;
+ color: var(--ifm-font-color-base);
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+}
+
+.copyPageButton:hover {
+ background-color: var(--ifm-color-emphasis-100);
+ border-color: var(--ifm-color-emphasis-400);
+}
+
+.copyPageButton:active {
+ transform: translateY(1px);
+}
+
+.copyPageButton.copied {
+ background-color: var(--ifm-color-success-contrast-background);
+ border-color: var(--ifm-color-success);
+ color: var(--ifm-color-success-darkest);
+}
+
+.copyPageButton.copied:hover {
+ background-color: var(--ifm-color-success-contrast-background);
+ border-color: var(--ifm-color-success);
+}
+
+.buttonText {
+ margin: 0 4px;
+}
+
+/* Dark mode adjustments */
+[data-theme='dark'] .copyPageButton {
+ border-color: var(--ifm-color-emphasis-400);
+}
+
+[data-theme='dark'] .copyPageButton:hover {
+ background-color: var(--ifm-color-emphasis-200);
+ border-color: var(--ifm-color-emphasis-500);
+}
+
+[data-theme='dark'] .copyPageButton.copied {
+ background-color: var(--ifm-color-success-dark);
+ border-color: var(--ifm-color-success);
+ color: var(--ifm-color-success-contrast-foreground);
+}
\ No newline at end of file
diff --git a/hindsight-docs/src/theme/DocItem/Content/index.tsx b/hindsight-docs/src/theme/DocItem/Content/index.tsx
new file mode 100644
index 00000000..97a084e5
--- /dev/null
+++ b/hindsight-docs/src/theme/DocItem/Content/index.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import DocItemContent from '@theme-original/DocItem/Content';
+import type DocItemContentType from '@theme/DocItem/Content';
+import type { WrapperProps } from '@docusaurus/types';
+import CopyPageButton from '@site/src/components/CopyPageButton';
+import styles from './styles.module.css';
+
+type Props = WrapperProps;
+
+export default function DocItemContentWrapper(props: Props): JSX.Element {
+ return (
+ <>
+
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/hindsight-docs/src/theme/DocItem/Content/styles.module.css b/hindsight-docs/src/theme/DocItem/Content/styles.module.css
new file mode 100644
index 00000000..da75a9b0
--- /dev/null
+++ b/hindsight-docs/src/theme/DocItem/Content/styles.module.css
@@ -0,0 +1,20 @@
+.docItemHeader {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ margin-bottom: 1rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid var(--ifm-color-emphasis-200);
+}
+
+.docItemActions {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+}
+
+@media (max-width: 768px) {
+ .docItemHeader {
+ margin-bottom: 0.75rem;
+ }
+}
\ No newline at end of file