feat(docs): Integrations Hub + unified page hero (#620)

* fix(security): address all Dependabot vulnerability alerts

Python (uv.lock, pyproject.toml):
- authlib 1.6.6 → 1.6.9 (JWS header injection, OIDC hash binding, Bleichenbacher padding oracle)
- pyasn1 0.6.2 → 0.6.3 (unbounded recursion DoS)
- pyjwt 2.10.1 → 2.12.1 (unknown crit header extensions - also in integration-tests and crewai)
- orjson 3.11.4 → 3.11.7 (deeply nested JSON recursion DoS)
- tornado 6.5.2 → 6.5.5 (multipart DoS, incomplete cookie validation)

npm (package.json, package-lock.json):
- next ^16.1.6 → ^16.1.7 (HTTP smuggling, CSRF bypass, cache DoS, null origin bypass)
- fast-xml-parser override updated to >=5.5.6 (numeric entity expansion bypass)
- undici override added >=7.24.0 (WebSocket overflow, smuggling, CRLF injection, DoS)
- flatted override added >=3.4.0 (unbounded recursion DoS)
- svgo override added >=3.3.3 (DOCTYPE entity expansion DoS)
- dompurify override added >=3.3.2 (XSS vulnerability)

* feat(docs): add Integrations Hub and unified page hero

- Add /integrations page with search, type filter, and card grid
- Integrations defined in a single JSON file (src/data/integrations.json)
  supporting official and community entries with icon, author, and link
- Scrolling integrations banner moved from global navbar to /integrations only
- Remove IntegrationsGrid component; replace all usages with link to hub
- Add PageHero component with full-bleed gradient background, shared across
  Cookbook, FAQ, Best Practices, Changelog, and Blog index pages
- Remove FAQ from top navbar (already in Resources dropdown)
- Move integration changelogs table to bottom of changelog page
This commit is contained in:
Nicolò Boschi 2026-03-19 20:29:55 +01:00 committed by GitHub
parent ea662d062e
commit 80b1badf74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 787 additions and 106 deletions

View file

@ -9,7 +9,7 @@ Get up and running with Hindsight in 60 seconds.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
import {ClientsGrid} from '@site/src/components/SupportedGrids';
{/* Import raw source files */}
import quickstartPy from '!!raw-loader!@site/examples/api/quickstart.py';
@ -117,7 +117,7 @@ go get github.com/vectorize-io/hindsight/hindsight-clients/go
## Integrations
<IntegrationsGrid />
Browse all supported integrations in the [Integrations Hub](/integrations).
## Next Steps

View file

@ -3,7 +3,7 @@ sidebar_position: 1
slug: /
---
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
import {ClientsGrid} from '@site/src/components/SupportedGrids';
# Overview
@ -122,7 +122,7 @@ These settings only affect the `reflect` operation, not `recall`.
## Integrations
<IntegrationsGrid />
Browse all supported integrations in the [Integrations Hub](/integrations).
## Next Steps

View file

@ -209,10 +209,10 @@ const config: Config = {
className: 'navbar-item-developer',
},
{
to: '/faq',
to: '/integrations',
position: 'left',
label: 'FAQ',
className: 'navbar-item-faq',
label: 'Integrations',
className: 'navbar-item-integrations',
},
{
to: '/changelog',

View file

@ -0,0 +1,46 @@
.hero {
width: 100vw;
position: relative;
left: 50%;
margin-left: -50vw;
/* cancel Docusaurus's margin-vert--lg on the page <main> */
margin-top: -2rem;
padding: 4rem 1.5rem 3.5rem;
text-align: center;
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.12) 0%, transparent 70%),
var(--ifm-background-color);
border-bottom: 1px solid var(--ifm-color-emphasis-200);
margin-bottom: 3rem;
}
[data-theme='dark'] .hero {
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.18) 0%, transparent 70%),
var(--ifm-background-color);
border-bottom-color: rgba(255, 255, 255, 0.07);
}
.title {
font-size: 3rem;
font-weight: 800;
background: linear-gradient(135deg, #0074d9, #009296);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: -0.03em;
line-height: 1.15;
margin-bottom: 0.75rem;
}
.subtitle {
font-size: 1.05rem;
color: var(--ifm-color-emphasis-600);
max-width: 560px;
margin: 0 auto;
line-height: 1.7;
}
@media (max-width: 640px) {
.title {
font-size: 2.2rem;
}
}

View file

@ -0,0 +1,16 @@
import React, {type ReactNode} from 'react';
import styles from './PageHero.module.css';
interface PageHeroProps {
title: string;
subtitle?: string;
}
export default function PageHero({title, subtitle}: PageHeroProps): ReactNode {
return (
<div className={styles.hero}>
<h1 className={styles.title}>{title}</h1>
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
</div>
);
}

View file

@ -1,7 +1,7 @@
import React from 'react';
import type {IconType} from 'react-icons';
import {IconGrid} from './IconGrid';
import {SiPython, SiGo, SiOpenai, SiAnthropic, SiGooglegemini, SiOllama, SiCrewai, SiPydantic, SiVercel} from 'react-icons/si';
import {SiPython, SiGo, SiOpenai, SiAnthropic, SiGooglegemini, SiOllama} from 'react-icons/si';
import {LuTerminal, LuPlug, LuZap, LuBrainCog, LuSparkles, LuGlobe} from 'react-icons/lu';
const OpenAICompatibleIcon: IconType = ({size = 28, ...props}) => (
@ -27,22 +27,6 @@ export function ClientsGrid() {
);
}
export function IntegrationsGrid() {
return (
<IconGrid items={[
{ label: 'Local MCP Server', imgSrc: '/img/icons/mcp.png', href: '/sdks/integrations/local-mcp' },
{ label: 'LiteLLM', imgSrc: '/img/icons/litellm.png', href: '/sdks/integrations/litellm' },
{ label: 'OpenClaw', imgSrc: '/img/icons/openclaw.png', href: '/sdks/integrations/openclaw' },
{ label: 'Vercel AI SDK', icon: SiVercel, href: '/sdks/integrations/ai-sdk' },
{ label: 'Vercel Chat SDK', icon: SiVercel, href: '/sdks/integrations/chat' },
{ label: 'CrewAI', imgSrc: '/img/icons/crewai.png', href: '/sdks/integrations/crewai' },
{ label: 'Pydantic AI', imgSrc: '/img/icons/pydanticai.png', href: '/sdks/integrations/pydantic-ai' },
{ label: 'Skills', imgSrc: '/img/icons/skills.png', href: '/sdks/integrations/skills' },
{ label: 'Agno', imgSrc: '/img/icons/agno.png', href: '/sdks/integrations/agno' },
{ label: 'Hermes', imgSrc: '/img/icons/hermes.png', href: '/sdks/integrations/hermes' },
]} />
);
}
export function LLMProvidersGrid() {
return (

View file

@ -0,0 +1,114 @@
{
"integrations": [
{
"id": "litellm",
"name": "LiteLLM",
"description": "Add long-term memory to any LLM via LiteLLM proxy callbacks. Zero code changes — configure once and every model gets memory.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/litellm",
"icon": "/img/icons/litellm.png"
},
{
"id": "crewai",
"name": "CrewAI",
"description": "Give CrewAI agents persistent, cross-session memory. Facts learned in one run are available in every future run.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/crewai",
"icon": "/img/icons/crewai.png"
},
{
"id": "pydantic-ai",
"name": "Pydantic AI",
"description": "Integrate Hindsight memory into Pydantic AI agents with a simple dependency injection pattern.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/pydantic-ai",
"icon": "/img/icons/pydanticai.png"
},
{
"id": "vercel-ai-sdk",
"name": "Vercel AI SDK",
"description": "Add persistent memory to Vercel AI SDK applications. Works with any model provider supported by the AI SDK.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/ai-sdk",
"icon": "/img/icons/vercel.png"
},
{
"id": "vercel-chat",
"name": "Vercel Chat",
"description": "Drop-in memory layer for the Vercel AI Chatbot. Remembers users across sessions out of the box.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/chat",
"icon": "/img/icons/vercel.png"
},
{
"id": "agno",
"name": "Agno",
"description": "Plug Hindsight into Agno agents for structured, long-term memory storage and retrieval.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/agno",
"icon": "/img/icons/agno.png"
},
{
"id": "hermes",
"name": "Hermes",
"description": "Use Hindsight as the memory backend for the Hermes multi-agent messaging framework.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/hermes",
"icon": "/img/icons/hermes.png"
},
{
"id": "local-mcp",
"name": "MCP Server",
"description": "Expose Hindsight memory as a Model Context Protocol server. Compatible with Claude, Cursor, and any MCP client.",
"type": "official",
"by": "hindsight",
"category": "mcp",
"link": "/sdks/integrations/local-mcp",
"icon": "/img/icons/mcp.png"
},
{
"id": "openclaw",
"name": "OpenClaw",
"description": "Integrate Hindsight with OpenClaw to add memory capabilities to Claude-based agent workflows.",
"type": "official",
"by": "hindsight",
"category": "framework",
"link": "/sdks/integrations/openclaw",
"icon": "/img/icons/openclaw.png"
},
{
"id": "skills",
"name": "Claude Code Skills",
"description": "Add Hindsight memory to Claude Code agents via the Skills integration. Persistent context across coding sessions.",
"type": "official",
"by": "hindsight",
"category": "tool",
"link": "/sdks/integrations/skills",
"icon": "/img/icons/skills.png"
},
{
"id": "hindsight-openclaw-pro",
"name": "hindsight-openclaw-pro",
"description": "Production-grade Hindsight memory plugin for OpenClaw — per-agent config, multi-bank recall, and IaC bank management via the hoppro CLI.",
"type": "community",
"by": "mrkhachaturov",
"category": "framework",
"link": "https://github.com/mrkhachaturov/hindsight-openclaw-pro",
"icon": "/img/icons/openclaw.png"
}
]
}

View file

@ -4,9 +4,9 @@ description: Practical guidance for agents and developers integrating Hindsight
hide_table_of_contents: true
---
# Best Practices
import PageHero from '@site/src/components/PageHero';
Practical guidance for agents and developers integrating Hindsight memory into production systems.
<PageHero title="Best Practices" subtitle="Practical guidance for agents and developers integrating Hindsight memory into production systems." />
**Contents**
- [Core Concepts](#core-concepts) — Memory banks, taxonomy, memory types

View file

@ -2,22 +2,9 @@
hide_table_of_contents: true
---
# Changelog
import PageHero from '@site/src/components/PageHero';
This changelog highlights user-facing changes only. Internal maintenance, CI/CD, and infrastructure updates are omitted.
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
## Integration Changelogs
| Integration | Package | Description |
|---|---|---|
| [LiteLLM](/changelog/integrations/litellm) | `hindsight-litellm` | Universal LLM memory via LiteLLM (100+ providers) |
| [Pydantic AI](/changelog/integrations/pydantic-ai) | `hindsight-pydantic-ai` | Persistent memory tools for Pydantic AI agents |
| [CrewAI](/changelog/integrations/crewai) | `hindsight-crewai` | Persistent memory for CrewAI agents |
| [AI SDK](/changelog/integrations/ai-sdk) | `@vectorize-io/hindsight-ai-sdk` | Memory integration for Vercel AI SDK |
| [Chat SDK](/changelog/integrations/chat) | `@vectorize-io/hindsight-chat` | Memory integration for Vercel Chat SDK |
| [OpenClaw](/changelog/integrations/openclaw) | `@vectorize-io/hindsight-openclaw` | Hindsight memory plugin for OpenClaw |
<PageHero title="Changelog" subtitle="User-facing changes only. Internal maintenance and infrastructure updates are omitted." />
## [0.4.19](https://github.com/vectorize-io/hindsight/releases/tag/v0.4.19)
@ -606,3 +593,14 @@ For full release details, see [GitHub Releases](https://github.com/vectorize-io/
**Bug Fixes**
- Fixed the standalone Docker image so it builds/runs correctly. ([`1056a20`](https://github.com/vectorize-io/hindsight/commit/1056a20))
## Integration Changelogs
| Integration | Package | Description |
|---|---|---|
| [LiteLLM](/changelog/integrations/litellm) | `hindsight-litellm` | Universal LLM memory via LiteLLM (100+ providers) |
| [Pydantic AI](/changelog/integrations/pydantic-ai) | `hindsight-pydantic-ai` | Persistent memory tools for Pydantic AI agents |
| [CrewAI](/changelog/integrations/crewai) | `hindsight-crewai` | Persistent memory for CrewAI agents |
| [AI SDK](/changelog/integrations/ai-sdk) | `@vectorize-io/hindsight-ai-sdk` | Memory integration for Vercel AI SDK |
| [Chat SDK](/changelog/integrations/chat) | `@vectorize-io/hindsight-chat` | Memory integration for Vercel Chat SDK |
| [OpenClaw](/changelog/integrations/openclaw) | `@vectorize-io/hindsight-openclaw` | Hindsight memory plugin for OpenClaw |

View file

@ -4,26 +4,12 @@ hide_table_of_contents: true
---
import CookbookGrid from '@site/src/components/CookbookGrid';
import PageHero from '@site/src/components/PageHero';
<PageHero title="Cookbook" subtitle="Practical examples and complete applications built with Hindsight." />
<div>
<div style={{textAlign: 'center', marginBottom: '3.5rem'}}>
<h1 style={{
fontSize: '3rem',
fontWeight: 800,
background: 'linear-gradient(135deg, #0074d9, #009296)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text',
letterSpacing: '-0.03em',
lineHeight: 1.15,
marginBottom: '0.75rem',
}}>Cookbook</h1>
<p style={{fontSize: '1.05rem', color: 'var(--ifm-color-emphasis-600)', maxWidth: 520, margin: '0 auto', lineHeight: 1.7}}>
Practical examples and complete applications built with Hindsight.
</p>
</div>
## Recipes
<CookbookGrid

View file

@ -4,9 +4,10 @@ description: Common questions and answers about Hindsight
hide_table_of_contents: true
---
import {ClientsGrid, IntegrationsGrid, LLMProvidersGrid} from '@site/src/components/SupportedGrids';
import {ClientsGrid, LLMProvidersGrid} from '@site/src/components/SupportedGrids';
import PageHero from '@site/src/components/PageHero';
# Frequently Asked Questions
<PageHero title="FAQ" subtitle="Common questions and answers about Hindsight." />
**Contents**
- [What is Hindsight and how does it differ from RAG?](#what-is-hindsight-and-how-does-it-differ-from-rag)
@ -64,7 +65,7 @@ Unlike vector databases (just search) or RAG systems (document retrieval), Hinds
### Which integrations are supported?
<IntegrationsGrid />
Browse all supported integrations in the [Integrations Hub](/integrations).
---

View file

@ -0,0 +1,408 @@
/* ── Full-width hero ─────────────────────────────────────────────────────── */
.heroSection {
width: 100%;
padding: 5rem 1.5rem 4rem;
text-align: center;
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.12) 0%, transparent 70%),
var(--ifm-background-color);
border-bottom: 1px solid var(--ifm-color-emphasis-200);
}
[data-theme='dark'] .heroSection {
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.18) 0%, transparent 70%),
var(--ifm-background-color);
border-bottom-color: rgba(255, 255, 255, 0.07);
}
.heroTitle {
font-size: 3.2rem;
font-weight: 800;
background: linear-gradient(135deg, #0074d9, #009296);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: -0.03em;
line-height: 1.1;
margin-bottom: 0.75rem;
}
.heroSubtitle {
font-size: 1.05rem;
color: var(--ifm-color-emphasis-600);
max-width: 500px;
margin: 0 auto 2.25rem;
line-height: 1.7;
}
/* ── Search ──────────────────────────────────────────────────────────────── */
.searchWrapper {
position: relative;
max-width: 640px;
margin: 0 auto;
}
.searchInput {
width: 100%;
box-sizing: border-box;
padding: 1.05rem 3.5rem 1.05rem 1.5rem;
border-radius: 14px;
border: 2px solid var(--ifm-color-emphasis-300);
background: var(--ifm-background-surface-color);
color: var(--ifm-font-color-base);
font-size: 1.1rem;
font-family: inherit;
outline: none;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
}
.searchInput::placeholder {
color: var(--ifm-color-emphasis-400);
}
.searchInput:focus {
border-color: #0074d9;
box-shadow: 0 0 0 4px rgba(0, 116, 217, 0.15), 0 4px 24px rgba(0, 0, 0, 0.08);
}
[data-theme='dark'] .searchInput {
background: #242428;
border-color: rgba(255, 255, 255, 0.15);
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
[data-theme='dark'] .searchInput:focus {
border-color: #4da6ff;
box-shadow: 0 0 0 4px rgba(77, 166, 255, 0.18), 0 4px 24px rgba(0, 0, 0, 0.4);
}
.searchClear {
position: absolute;
right: 1rem;
top: 50%;
transform: translateY(-50%);
background: var(--ifm-color-emphasis-200);
border: none;
color: var(--ifm-color-emphasis-600);
cursor: pointer;
font-size: 1rem;
line-height: 1;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.1s;
}
.searchClear:hover {
background: var(--ifm-color-emphasis-300);
}
/* ── Hero stats ──────────────────────────────────────────────────────────── */
.heroStats {
display: inline-flex;
align-items: center;
gap: 0.6rem;
font-size: 0.82rem;
color: var(--ifm-color-emphasis-500);
margin-top: 1.25rem;
}
.stat strong {
color: var(--ifm-color-emphasis-800);
}
[data-theme='dark'] .stat strong {
color: var(--ifm-color-emphasis-700);
}
.statDivider {
color: var(--ifm-color-emphasis-300);
}
/* ── Page container ──────────────────────────────────────────────────────── */
.page {
max-width: 1200px;
margin: 0 auto;
padding: 2.5rem 1.5rem 5rem;
}
/* ── Toolbar (filters + count) ───────────────────────────────────────────── */
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1.75rem;
flex-wrap: wrap;
gap: 0.75rem;
}
.filterGroup {
display: flex;
align-items: center;
gap: 0.4rem;
}
.filterPill {
display: inline-flex;
align-items: center;
font-size: 0.82rem;
font-weight: 500;
padding: 0.3rem 0.85rem;
border-radius: 999px;
border: 1px solid var(--ifm-color-emphasis-300);
background: transparent;
color: var(--ifm-color-emphasis-700);
cursor: pointer;
transition: all 0.15s ease;
font-family: inherit;
}
.filterPill:hover {
border-color: var(--ifm-color-primary);
color: var(--ifm-color-primary);
}
.filterPillActive {
background: var(--ifm-color-primary);
border-color: var(--ifm-color-primary);
color: #fff !important;
}
[data-theme='dark'] .filterPill {
border-color: rgba(255, 255, 255, 0.15);
color: var(--ifm-color-emphasis-600);
}
/* ── Result count ────────────────────────────────────────────────────────── */
.resultCount {
font-size: 0.8rem;
color: var(--ifm-color-emphasis-400);
margin: 0;
}
/* ── Grid ────────────────────────────────────────────────────────────────── */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.25rem;
margin-bottom: 4rem;
}
@media (max-width: 996px) {
.grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
.grid { grid-template-columns: 1fr; }
.heroTitle { font-size: 2.2rem; }
}
/* ── Card ────────────────────────────────────────────────────────────────── */
.card {
display: flex;
flex-direction: column;
border-radius: 12px;
border: 1px solid var(--ifm-color-emphasis-200);
background: var(--ifm-background-surface-color);
text-decoration: none !important;
color: inherit;
transition: box-shadow 0.2s ease, transform 0.2s ease;
overflow: hidden;
}
[data-theme='dark'] .card {
background: #1c1c1e;
border-color: rgba(255, 255, 255, 0.07);
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(0, 116, 217, 0.12);
text-decoration: none !important;
color: inherit;
}
.cardHeader {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.1rem 0;
}
.cardIcon {
width: 36px;
height: 36px;
object-fit: contain;
flex-shrink: 0;
}
.typeBadge {
font-size: 0.63rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.15rem 0.5rem;
border-radius: 999px;
}
.typeBadgeOfficial {
background: rgba(0, 116, 217, 0.12);
color: #0074d9;
}
[data-theme='dark'] .typeBadgeOfficial {
background: rgba(0, 116, 217, 0.2);
color: #4da6ff;
}
.typeBadgeCommunity {
background: rgba(0, 146, 150, 0.12);
color: #009296;
}
[data-theme='dark'] .typeBadgeCommunity {
background: rgba(0, 146, 150, 0.2);
color: #00bcc0;
}
.cardBody {
flex: 1;
padding: 0.85rem 1.1rem 0.75rem;
}
.cardTitle {
font-size: 1rem;
font-weight: 700;
margin: 0 0 0.4rem;
color: var(--ifm-heading-color);
letter-spacing: -0.01em;
border-bottom: none !important;
border-image: none !important;
}
.cardDescription {
font-size: 0.82rem;
color: var(--ifm-color-emphasis-600);
line-height: 1.6;
margin: 0;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.cardFooter {
display: flex;
align-items: center;
padding: 0.65rem 1.1rem 0.9rem;
margin-top: 0.25rem;
border-top: 1px solid var(--ifm-color-emphasis-100);
}
[data-theme='dark'] .cardFooter {
border-top-color: rgba(255, 255, 255, 0.06);
}
.byLine {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-size: 0.78rem;
font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Monaco, Consolas, monospace;
color: var(--ifm-color-emphasis-600);
}
.authorIcon {
width: 22px;
height: 22px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
border: 1px solid var(--ifm-color-emphasis-200);
}
[data-theme='dark'] .authorIcon {
border-color: rgba(255, 255, 255, 0.1);
}
.authorName {
font-weight: 500;
}
/* ── Empty state ─────────────────────────────────────────────────────────── */
.empty {
text-align: center;
padding: 4rem 2rem;
color: var(--ifm-color-emphasis-500);
}
.resetButton {
margin-top: 1rem;
padding: 0.4rem 1rem;
border-radius: 6px;
border: 1px solid var(--ifm-color-primary);
background: transparent;
color: var(--ifm-color-primary);
font-size: 0.85rem;
font-family: inherit;
cursor: pointer;
transition: all 0.15s ease;
}
.resetButton:hover {
background: var(--ifm-color-primary);
color: #fff;
}
/* ── Submit banner ───────────────────────────────────────────────────────── */
.submitBanner {
border-radius: 14px;
border: 1px solid var(--ifm-color-emphasis-200);
background: linear-gradient(135deg, rgba(0, 116, 217, 0.06), rgba(0, 146, 150, 0.06));
padding: 2.5rem 2rem;
text-align: center;
}
[data-theme='dark'] .submitBanner {
border-color: rgba(255, 255, 255, 0.08);
background: linear-gradient(135deg, rgba(0, 116, 217, 0.1), rgba(0, 146, 150, 0.1));
}
.submitBannerContent {
max-width: 480px;
margin: 0 auto;
}
.submitBannerTitle {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.submitBannerText {
font-size: 0.9rem;
color: var(--ifm-color-emphasis-600);
margin-bottom: 1.25rem;
line-height: 1.6;
}
.submitButton {
display: inline-block;
padding: 0.55rem 1.4rem;
border-radius: 8px;
background: linear-gradient(135deg, #0074d9, #009296);
color: #fff !important;
font-size: 0.9rem;
font-weight: 600;
text-decoration: none !important;
transition: opacity 0.15s ease, transform 0.15s ease;
}
.submitButton:hover {
opacity: 0.9;
transform: translateY(-1px);
color: #fff !important;
}

View file

@ -0,0 +1,163 @@
import React, {useMemo, useState} from 'react';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import Layout from '@theme/Layout';
import IntegrationsBanner from '@site/src/components/IntegrationsBanner';
import integrationsData from '@site/src/data/integrations.json';
import styles from './index.module.css';
const INTEGRATIONS_JSON_URL =
'https://github.com/vectorize-io/hindsight/edit/main/hindsight-docs/src/data/integrations.json';
type IntegrationType = 'official' | 'community';
interface Integration {
id: string;
name: string;
description: string;
type: IntegrationType;
by: string;
category: string;
link: string;
icon?: string;
}
function IntegrationCard({integration}: {integration: Integration}) {
const iconSrc = useBaseUrl(integration.icon ?? '');
const faviconSrc = useBaseUrl('/img/favicon.png');
const isExternal = integration.link.startsWith('http');
return (
<Link to={integration.link} className={styles.card} {...(isExternal ? {target: '_blank', rel: 'noopener noreferrer'} : {})}>
<div className={styles.cardHeader}>
{integration.icon && <img src={iconSrc} alt="" className={styles.cardIcon} aria-hidden />}
<span className={`${styles.typeBadge} ${integration.type === 'official' ? styles.typeBadgeOfficial : styles.typeBadgeCommunity}`}>
{integration.type === 'official' ? 'Official' : 'Community'}
</span>
</div>
<div className={styles.cardBody}>
<h3 className={styles.cardTitle}>{integration.name}</h3>
<p className={styles.cardDescription}>{integration.description}</p>
</div>
<div className={styles.cardFooter}>
{integration.type === 'official' ? (
<span className={styles.byLine}>
<img src={faviconSrc} alt="" className={styles.authorIcon} aria-hidden />
<span className={styles.authorName}>Hindsight Team</span>
</span>
) : (
<span className={styles.byLine}>
<img src={`https://github.com/${integration.by}.png?size=40`} alt="" className={styles.authorIcon} aria-hidden />
<span className={styles.authorName}>@{integration.by}</span>
</span>
)}
</div>
</Link>
);
}
export default function IntegrationsHub(): React.ReactElement {
const [search, setSearch] = useState('');
const [selectedType, setSelectedType] = useState<IntegrationType | 'all'>('all');
const integrations = integrationsData.integrations as Integration[];
const filtered = useMemo(() => {
const q = search.toLowerCase().trim();
return integrations.filter((i) => {
if (selectedType !== 'all' && i.type !== selectedType) return false;
if (q && !i.name.toLowerCase().includes(q) && !i.description.toLowerCase().includes(q)) return false;
return true;
});
}, [integrations, search, selectedType]);
const officialCount = integrations.filter((i) => i.type === 'official').length;
const communityCount = integrations.filter((i) => i.type === 'community').length;
return (
<Layout title="Integrations Hub" description="Browse official and community integrations for Hindsight agent memory">
{/* Full-width hero with its own background */}
<div className={styles.heroSection}>
<h1 className={styles.heroTitle}>Integrations Hub</h1>
<p className={styles.heroSubtitle}>
Connect Hindsight to your stack. Browse official integrations and community-built connectors.
</p>
<div className={styles.searchWrapper}>
<input
type="text"
className={styles.searchInput}
placeholder="Search integrations…"
value={search}
onChange={(e) => setSearch(e.target.value)}
aria-label="Search integrations"
autoComplete="off"
/>
{search && (
<button className={styles.searchClear} onClick={() => setSearch('')} aria-label="Clear search">
×
</button>
)}
</div>
<div className={styles.heroStats}>
<span className={styles.stat}><strong>{officialCount}</strong> official</span>
<span className={styles.statDivider}>·</span>
<span className={styles.stat}><strong>{communityCount}</strong> community</span>
</div>
</div>
{/* Scrolling banner */}
<IntegrationsBanner />
{/* Main content */}
<div className={styles.page}>
<div className={styles.toolbar}>
<div className={styles.filterGroup}>
{(['all', 'official', 'community'] as const).map((t) => (
<button
key={t}
className={`${styles.filterPill} ${selectedType === t ? styles.filterPillActive : ''}`}
onClick={() => setSelectedType(t)}>
{t === 'all' ? 'All' : t.charAt(0).toUpperCase() + t.slice(1)}
</button>
))}
</div>
<span className={styles.resultCount}>{filtered.length} integration{filtered.length !== 1 ? 's' : ''}</span>
</div>
{filtered.length === 0 ? (
<div className={styles.empty}>
<p>No integrations match your search.</p>
<button className={styles.resetButton} onClick={() => { setSearch(''); setSelectedType('all'); }}>
Reset filters
</button>
</div>
) : (
<div className={styles.grid}>
{filtered.map((integration) => (
<IntegrationCard key={integration.id} integration={integration} />
))}
</div>
)}
<div className={styles.submitBanner}>
<div className={styles.submitBannerContent}>
<h2 className={styles.submitBannerTitle}>Built something with Hindsight?</h2>
<p className={styles.submitBannerText}>
Share your integration with the community. Open a pull request and add your entry to the integrations list.
</p>
<Link
href={INTEGRATIONS_JSON_URL}
className={styles.submitButton}
target="_blank"
rel="noopener noreferrer">
Submit an integration
</Link>
</div>
</div>
</div>
</Layout>
);
}

View file

@ -3,6 +3,7 @@ import Link from '@docusaurus/Link';
import Layout from '@theme/Layout';
import type {Props} from '@theme/BlogListPage';
import type {PropBlogPostContent} from '@docusaurus/plugin-content-blog';
import PageHero from '@site/src/components/PageHero';
import styles from './styles.module.css';
const CLOUD_TAG = 'hindsight-cloud';
@ -70,10 +71,7 @@ export default function BlogListPage({items, metadata}: Props): React.ReactEleme
return (
<Layout title={blogTitle} description={blogDescription}>
<main className={styles.blogPage}>
<header className={styles.header}>
<h1 className={styles.headerTitle}>{blogTitle}</h1>
{blogDescription && <p className={styles.headerSubtitle}>{blogDescription}</p>}
</header>
<PageHero title={blogTitle} subtitle={blogDescription} />
{cloudPosts.length > 0 && (
<section className={styles.section}>

View file

@ -1,33 +1,7 @@
.blogPage {
max-width: 1280px;
margin: 0 auto;
padding: 4rem 2rem 6rem;
}
/* ── Header ─────────────────────────────────────── */
.header {
text-align: center;
margin-bottom: 4rem;
}
.headerTitle {
font-size: 3rem;
font-weight: 800;
background: linear-gradient(135deg, #0074d9, #009296);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 0.75rem;
line-height: 1.15;
letter-spacing: -0.03em;
}
.headerSubtitle {
font-size: 1.05rem;
color: var(--ifm-color-emphasis-600);
max-width: 520px;
margin: 0 auto;
line-height: 1.7;
padding: 2rem 2rem 6rem;
}
/* ── Section ─────────────────────────────────────── */
@ -93,9 +67,6 @@
gap: 2rem;
}
.headerTitle {
font-size: 2.25rem;
}
}
/* ── Card ────────────────────────────────────────── */

View file

@ -1,15 +1,11 @@
import React, {type ReactNode} from 'react';
import NavbarLayout from '@theme/Navbar/Layout';
import NavbarContent from '@theme/Navbar/Content';
import IntegrationsBanner from '@site/src/components/IntegrationsBanner';
export default function Navbar(): ReactNode {
return (
<>
<NavbarLayout>
<NavbarContent />
</NavbarLayout>
<IntegrationsBanner />
</>
<NavbarLayout>
<NavbarContent />
</NavbarLayout>
);
}

View file

@ -9,7 +9,7 @@ Get up and running with Hindsight in 60 seconds.
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeSnippet from '@site/src/components/CodeSnippet';
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
import {ClientsGrid} from '@site/src/components/SupportedGrids';
{/* Import raw source files */}
import quickstartPy from '!!raw-loader!@site/examples/api/quickstart.py';
@ -107,7 +107,7 @@ curl -fsSL https://hindsight.vectorize.io/get-cli | bash
## Integrations
<IntegrationsGrid />
Browse all supported integrations in the [Integrations Hub](/integrations).
## Next Steps

View file

@ -3,7 +3,7 @@ sidebar_position: 1
slug: /
---
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
import {ClientsGrid} from '@site/src/components/SupportedGrids';
# Overview
@ -122,7 +122,7 @@ These settings only affect the `reflect` operation, not `recall`.
## Integrations
<IntegrationsGrid />
Browse all supported integrations in the [Integrations Hub](/integrations).
## Next Steps