Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 119 additions & 35 deletions quill/home.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,130 @@
slug: /
title: Quill Documentation
sidebar_label: Home
# Hides the duplicate "Home" entry from the sidebar — the "Quill" category header already links here.
Comment thread
mateuszbartosik marked this conversation as resolved.
# Cloud and the main docs apply the same `hidden` class via `className` on an explicit sidebar item;
# the Quill sidebar is autogenerated, so the class has to come from the doc's own frontmatter.
sidebar_class_name: hidden
sidebar_position: 0
pagination_next: null
pagination_prev: null
wrapperClassName: quillHomePage
hide_title: true
hide_table_of_contents: true
description: "Quill gives your PostgreSQL, SQL Server, or MySQL database an AI agent that answers your users from a live copy of your data, through a chat widget on your site or a Telegram, Slack, or Discord bot. Start here."
---

import CardWithImage from "@site/src/components/Common/CardWithImage";
import ColGrid from "@site/src/components/ColGrid";

# Quill: AI agents for the database you already have
AI conversations for your users, answered from a live copy of your SQL data.

Quill gives your PostgreSQL, SQL Server, or MySQL database AI agents, without changing the database itself.
It runs as a single Docker container beside your database, mirrors the tables you select into an internal database
of its own, and lets the agents talk with your users through a chat widget on your site or a bot in Telegram,
Slack, or Discord.
Your data, your workflows, and your applications remain unchanged.

* **Mirroring** - Quill keeps a live copy of the tables you select, and keeps it current as your data changes.
* **Agents** - AI agents query the mirrored data, compose the replies, and phrase them with the LLM provider you
connect.
* **Channels** - A chat widget on your site, or a Telegram, Slack, or Discord bot, carries the conversations between
your users and your agents.

### Start here
Signing up starts a 90-day free trial. From there, Getting Started walks you through setting Quill up, and the
Overview explains what you are setting up.

<ColGrid colCount={3}>
<CardWithImage title="Sign up for Quill" description="Open the sign-up form on ravendb.net and start your free trial." url="https://ravendb.net/quill/start" imgSrc="/img/quill/home_card-sign-up.svg" imgAlt="Sign up for Quill" />
<CardWithImage title="Getting Started" description="From signing up to a chat widget on your site, step by step." url="/quill/getting-started/overview" imgSrc="/img/quill/home_card-getting-started.svg" imgAlt="Getting Started" />
<CardWithImage title="Overview" description="What Quill is, how its parts work together, and how a running Quill is managed." url="/quill/overview" imgSrc="/img/quill/home_card-overview.svg" imgAlt="Overview" />
</ColGrid>

### Documentation

<ColGrid colCount={3}>
<CardWithImage title="Dashboard" description="Manage a running Quill: your apps, the AI connection strings your agents use, and your license." url="/quill/dashboard/my-apps" imgSrc="/img/quill/home_card-dashboard.svg" imgAlt="Dashboard" />
<CardWithImage title="Security & Architecture" description="How Quill routes and protects connections, and how operators and programs authenticate." url="/quill/security-and-architecture/network-architecture" imgSrc="/img/quill/home_card-security.svg" imgAlt="Security & Architecture" />
<CardWithImage title="Developer access" description="Reach an app from your own code: through a channel and its agent, or straight to the mirrored data." url="/quill/developer-access/overview" imgSrc="/img/quill/home_card-developer-access.svg" imgAlt="Developer access" />
</ColGrid>
import QuillHero from "@site/src/components/Quill/QuillHero";
import QuillWidgetDemo from "@site/src/components/Quill/QuillWidgetDemo";
import { QuillFlow } from "@site/src/components/Quill/QuillHowItWorks";
import CardWithIcon from "@site/src/components/Common/CardWithIcon";

<QuillHero
title="AI agents for the database you already have"
lead="Quill gives your PostgreSQL, SQL Server, or MySQL database AI agents, without changing the database itself. It runs as a single Docker container beside your database, mirrors the tables you select into an internal database of its own, and lets the agents talk with your users through a chat widget on your site or a bot in Telegram, Slack, or Discord. Your data, your workflows, and your applications remain unchanged."
primary={{ label: "Start your free trial", url: "https://ravendb.net/quill/start", external: true }}
secondary={{ label: "Set up Quill", url: "/quill/getting-started/overview" }}
visual={<QuillWidgetDemo />}
/>

## How it works

<QuillFlow
nodes={[
{
icon: "database",
title: "Your SQL database",
description: "PostgreSQL, SQL Server, or MySQL. Read by Quill, never modified.",
url: "/quill/overview#your-sql-database",
},
{
icon: "sql-replication",
title: "Mirroring",
description: "Quill keeps a live copy of the tables you select, and keeps it current as your data changes.",
url: "/quill/overview#mirroring",
},
{
icon: "ai-agents",
title: "AI agent",
description: "AI agents query the mirrored data, compose the replies, and phrase them with the LLM provider you connect.",
url: "/quill/overview#ai-agent",
},
{
icon: "notifications",
title: "Channels",
description: "A chat widget on your site, or a Telegram, Slack, or Discord bot, carries the conversations between your users and your agents.",
url: "/quill/overview#channels",
},
]}
/>

## Explore the documentation

### Learn

<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
<CardWithIcon
title="Overview"
icon="book"
description="What Quill is, how its parts work together, and how a running Quill is managed."
url="/quill/overview"
/>
<CardWithIcon
title="Getting Started"
icon="rocket"
description="From signing up to a chat widget on your site, step by step."
url="/quill/getting-started/overview"
/>
<CardWithIcon
title="Security & Architecture"
icon="shield"
description="How Quill routes and protects connections, and how operators and programs authenticate."
url="/quill/security-and-architecture/network-architecture"
/>
</div>

### Operate

<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
<CardWithIcon
title="Dashboard"
icon="dashboard"
description="Manage a running Quill: your apps, the AI connection strings your agents use, and your license."
url="/quill/dashboard/my-apps"
/>
<CardWithIcon
title="Networking & DNS"
icon="server-topology"
description="The DNS records created for your Quill, what they point at, and how to repoint them when your IP changes."
url="/quill/networking-and-dns"
/>
<CardWithIcon
title="Updating Quill"
icon="refresh"
description="Replace the Docker container while keeping its data volume, and recover from an expired build."
url="/quill/updating-quill"
/>
</div>

### Build

<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
<CardWithIcon
title="Developer access"
icon="code"
description="Reach an app from your own code: through a channel and its agent, or straight to the mirrored data."
url="/quill/developer-access/overview"
/>
<CardWithIcon
title="Embed the chat widget"
icon="integrations"
description="Place the widget on your site with an iframe, restrict which sites may load it, and style it."
url="/quill/developer-access/embed-the-chat-widget"
/>
<CardWithIcon
title="RavenDB.Client access"
icon="database-client-configuration"
description="Connect an application directly to the mirrored database with a scoped client certificate."
url="/quill/developer-access/ravendb-client-access"
/>
</div>
53 changes: 53 additions & 0 deletions src/components/Common/ShineBorder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { type CSSProperties, type HTMLAttributes, type ReactNode } from "react";
import clsx from "clsx";

export interface ShineBorderProps extends HTMLAttributes<HTMLDivElement> {
/** Width of the animated ring, in pixels. */
borderWidth?: number;
/** One lap of the highlight, in seconds. */
duration?: number;
/** The color, or colors, that sweep along the ring. Any CSS color works, `var(...)` included. */
shineColor?: string | string[];
}

/**
* An animated border highlight, after Magic UI's ShineBorder (MIT). Place it as the last child of a
* `relative` parent whose radius it inherits: two masks composited with `exclude` cut the gradient down
* to a ring `borderWidth` wide along the parent's edge, and the gradient's position loops so a highlight
* travels around the frame. Stays still under reduced motion. Decorative and inert to the pointer.
*/
export default function ShineBorder({
borderWidth = 0.5,
duration = 30,
shineColor = "#ff775f",
className,
style,
...props
}: ShineBorderProps): ReactNode {
const colors = Array.isArray(shineColor) ? shineColor.join(",") : shineColor;
return (
<div
aria-hidden="true"
style={
{
"--shine-border-width": `${borderWidth}px`,
"--shine-duration": `${duration}s`,
backgroundImage: `radial-gradient(transparent, transparent, ${colors}, transparent, transparent)`,
backgroundSize: "300% 300%",
mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
WebkitMaskComposite: "xor",
maskComposite: "exclude",
padding: "var(--shine-border-width)",
...style,
} as CSSProperties
}
className={clsx(
"pointer-events-none absolute inset-0 size-full rounded-[inherit] will-change-[background-position]",
"motion-safe:animate-shine",
className
)}
{...props}
/>
);
}
35 changes: 35 additions & 0 deletions src/components/Quill/ChannelRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { type CSSProperties, type ReactNode } from "react";
import clsx from "clsx";
import styles from "./IntegrationBlobField.module.css";
import { CHANNELS } from "./channels";

const ROW_GLOW = 0.35;

/**
* The narrow-screen stand-in for the blob field: one centred row of the same channel chips at 40px, with
* no blur and no drift. Below `md` the card is full-bleed and there are no gutters left to float anything
* in, so this is where the channels show.
*/
export default function ChannelRow({ className }: { className?: string }): ReactNode {
return (
<ul
aria-label={`Channels: ${CHANNELS.map((channel) => channel.name).join(", ")}`}
className={clsx("!mt-4 !p-0 !list-none flex flex-wrap justify-center gap-3 pt-8", className)}
>
{CHANNELS.map((channel) => (
<li key={channel.id} className="!m-0">
<span
role="img"
aria-label={channel.name}
className={styles.rowChip}
style={{ "--tint": channel.tint, "--glow": ROW_GLOW } as CSSProperties}
>
<span className={styles.glow} />
<span className={styles.glass} />
<channel.Icon className={styles.rowMark} />
</span>
</li>
))}
</ul>
);
}
77 changes: 77 additions & 0 deletions src/components/Quill/IntegrationBlobField.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* The field's coordinate box: the whole hero. Slots in blobPositions.ts are offsets from the card, placed
into this box by IntegrationBlobField and clamped to its edges. */
.box {
position: absolute;
inset: 0;
}

/* The drifting wrapper carries the drift transform; the chip inside carries scale, blur, and opacity.
Centring uses negative margins rather than a translate, so the drift keyframe does not wipe it. */
.drift {
position: absolute;
width: 64px;
height: 64px;
margin: -32px 0 0 -32px;
will-change: transform;
}

.chip {
position: relative;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}

/* Glow, then glass, then the mark: document order puts the tinted glow behind the disc. */
.glow {
position: absolute;
inset: -28%;
border-radius: 9999px;
background: radial-gradient(circle, var(--tint), transparent 68%);
opacity: var(--glow);
}

/* Glass on dark, not solid white. No backdrop-filter: on a near-black ground the flat translucent gradient
is visually indistinguishable, and a dozen backdrop-filtered, blurred elements cost real compositing. */
.glass {
position: absolute;
inset: 0;
border-radius: 9999px;
background: linear-gradient(160deg, rgb(255 255 255 / 0.14), rgb(255 255 255 / 0.05));
border: 1px solid rgb(255 255 255 / 0.18);
box-shadow:
0 10px 26px -10px rgb(0 0 0 / 0.85),
inset 0 1px 0 rgb(255 255 255 / 0.15);
}

:global([data-theme="light"]) .glass {
background: linear-gradient(160deg, rgb(255 255 255 / 0.95), rgb(255 255 255 / 0.7));
border-color: rgb(0 0 0 / 0.08);
box-shadow:
0 10px 26px -12px rgb(0 0 0 / 0.28),
inset 0 1px 0 rgb(255 255 255 / 0.9);
}

.mark {
position: relative;
width: 28px;
height: 28px;
}

/* Mobile fallback: the same chips at 40px in a centred row, no blur, no drift. */
.rowChip {
position: relative;
display: flex;
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
}

.rowMark {
position: relative;
width: 18px;
height: 18px;
}
Loading
Loading