DEV Community

SurfaceDocs
SurfaceDocs

Posted on

SurfaceDocs + Gemini: From LLM Output to Shareable Doc in 30 Seconds

You just built a Gemini pipeline. It generates great output — structured analysis, technical breakdowns, research summaries. Now you need to share it with someone who doesn't have a terminal open.

Your options: copy-paste into Google Docs (fight with formatting), save to a file and Slack it (watch it disappear in 20 minutes), or build a custom viewer (spend a week on something that isn't your actual project).

Or: three lines of code.

The Setup

pip install google-genai surfacedocs
Enter fullscreen mode Exit fullscreen mode

You'll need two API keys:

The Minimal Example

import os
from google import genai
from surfacedocs import SurfaceDocs, SYSTEM_PROMPT, GEMINI_DOCUMENT_SCHEMA

# Initialize clients
client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
docs = SurfaceDocs(api_key=os.environ["SURFACEDOCS_API_KEY"])

# Generate structured content with Gemini
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Write a technical overview of WebSocket protocol vs HTTP polling",
    config={
        "system_instruction": SYSTEM_PROMPT,
        "response_mime_type": "application/json",
        "response_schema": GEMINI_DOCUMENT_SCHEMA,
    },
)

# Publish to SurfaceDocs
result = docs.save(response.text)
print(result.url)  # https://app.surfacedocs.dev/d/...
Enter fullscreen mode Exit fullscreen mode

That's it. Gemini generates structured content, SurfaceDocs renders and hosts it. Click the URL and you've got a formatted, shareable document.

What's happening under the hood

The key is three things the SurfaceDocs SDK provides:

  • SYSTEM_PROMPT — Instructions that tell Gemini how to structure its output into document blocks (headings, paragraphs, code blocks, tables, lists)
  • GEMINI_DOCUMENT_SCHEMA — A JSON schema specifically shaped for Gemini's response_schema parameter, so output is guaranteed to be valid structured JSON
  • docs.save() — Takes that JSON, pushes it to SurfaceDocs, returns a URL

The SDK ships with both GEMINI_DOCUMENT_SCHEMA (for Gemini's native structured output) and OPENAI_DOCUMENT_SCHEMA (for OpenAI's response_format). Same idea, different shapes for each provider's API.

A More Realistic Example: Multi-Step Pipeline

In practice, you probably have a pipeline that does real work — not just a single generation call. Here's a two-step pattern: generate raw analysis, then format it as a publishable document.

import os
from google import genai
from surfacedocs import SurfaceDocs, SYSTEM_PROMPT, GEMINI_DOCUMENT_SCHEMA

client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
docs = SurfaceDocs(api_key=os.environ["SURFACEDOCS_API_KEY"])

# Step 1: Generate raw analysis (unstructured)
raw = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=(
        "Compare FastAPI, Flask, and Django for building REST APIs in 2026. "
        "Cover performance, developer experience, ecosystem, and when to pick each."
    ),
)

print(f"Generated {len(raw.text)} chars of analysis")

# Step 2: Format as a SurfaceDocs document
formatted = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=f"Turn this analysis into a well-structured document:\n\n{raw.text}",
    config={
        "system_instruction": SYSTEM_PROMPT,
        "response_mime_type": "application/json",
        "response_schema": GEMINI_DOCUMENT_SCHEMA,
    },
)

# Step 3: Publish
result = docs.save(formatted.text)
print(f"Published → {result.url}")
Enter fullscreen mode Exit fullscreen mode

Why two steps? Your first call does the actual thinking — analysis, comparison, research. It can be freeform, messy, detailed. The second call just reshapes that output into SurfaceDocs' block format. You get the best of both worlds: unconstrained reasoning followed by clean formatting.

This also means you can plug SurfaceDocs into any existing pipeline. Whatever your agent or chain produces, just add a formatting step at the end and save it.

Organizing with Folders

As your pipeline generates more documents, you'll want to organize them. Pass a folder_id to route documents into specific folders:

# Publish to a specific folder
result = docs.save(
    formatted.text,
    folder_id="your-folder-id"
)
Enter fullscreen mode Exit fullscreen mode

Create folders in the SurfaceDocs dashboard and grab the ID from the URL. Useful for pipelines that produce daily reports, per-client analyses, or categorized research.

When This Clicks

This pattern works best when:

  • Your pipeline runs on a schedule — Daily market analysis, weekly reports, automated monitoring summaries. Each run produces a document with a permanent URL.
  • You're sharing with non-technical stakeholders — Your PM, your client, your CEO doesn't want to cat output.json. They want a link.
  • Your agent produces work products — Research agents, analysis agents, documentation generators. The agent does work, and that work needs to live somewhere.
  • You're prototyping fast — You're iterating on a Gemini pipeline and want to see formatted output without building a viewer. SurfaceDocs becomes your instant preview layer.

The Full Pattern

Here's the general flow for any Gemini pipeline:

Your pipeline (any logic)
        │
        ▼
Raw LLM output (unstructured)
        │
        ▼
Gemini + SYSTEM_PROMPT + GEMINI_DOCUMENT_SCHEMA
        │
        ▼
docs.save() → Shareable URL
Enter fullscreen mode Exit fullscreen mode

The structured output step can go anywhere — at the end of a chain, after post-processing, or directly as your only generation call. SurfaceDocs doesn't care what your pipeline does upstream. It's just the output layer.

Get Started

pip install google-genai surfacedocs
Enter fullscreen mode Exit fullscreen mode

Free tier gives you 10 documents/month with 90-day retention — plenty to try it out. Pro ($19/month) bumps that to 1,000 docs with unlimited retention when your pipeline goes to production.

The full code examples from this article are on GitHub.


SurfaceDocs is the output layer for AI pipelines. pip install surfacedocs and stop building custom viewers.

Top comments (0)