---
title: Documentation Lookup for a Coding Agent | Tabstack
description: Give a coding agent a tool that reads current documentation instead of answering from training data. Uses /extract/markdown for a known URL and /research when the right page is unknown.
---

A coding agent’s worst answers come from documentation it learned two model versions ago: a renamed flag, a removed option, a breaking change it never saw. The fix is not a bigger model, it is letting the agent read the current page.

This example wires two tools into an agent loop. `readDocs` takes a URL the agent already has and returns the page as clean markdown. `findInDocs` takes a question when the agent does not know which page holds the answer, and returns a cited answer. Both are one call.

- [TypeScript](#tab-panel-6)
- [Python](#tab-panel-7)
- [CLI](#tab-panel-8)

```
import Tabstack from "@tabstack/sdk";


const client = new Tabstack();


/** The agent has a URL. Return the current page as markdown. */
async function readDocs(url: string) {
  const result = await client.extract.markdown({
    url,
    // Documentation sites change. Skip the shared cache for anything
    // version-sensitive, at the cost of a slower fetch.
    nocache: true,
  });


  return result.content;
}


/** The agent has a question but not a URL. Return a cited answer. */
async function findInDocs(question: string) {
  const stream = await client.agent.research({
    query: question,
    mode: "fast",
  });


  for await (const event of stream) {
    if (event.event === "error") {
      throw new Error(event.data.error?.message ?? "Documentation lookup failed");
    }


    if (event.event === "complete") {
      const sources = (event.data.metadata.citedPages ?? []).map((p) => p.url);
      return { answer: event.data.report, sources };
    }
  }


  throw new Error("Stream ended before the complete event");
}


// The agent already knows where to look.
const page = await readDocs("https://docs.tabstack.ai/guides/research");
console.log(page.slice(0, 500));


// The agent does not.
const { answer, sources } = await findInDocs(
  "What is the current default value of the Tabstack research mode parameter?",
);
console.log(answer);
console.log("Sources:", sources);
```

```
from tabstack import Tabstack


client = Tabstack()




def read_docs(url: str) -> str:
    """The agent has a URL. Return the current page as markdown."""
    result = client.extract.markdown(
        url=url,
        # Documentation sites change. Skip the shared cache for anything
        # version-sensitive, at the cost of a slower fetch.
        nocache=True,
    )
    return result.content




def find_in_docs(question: str) -> dict:
    """The agent has a question but not a URL. Return a cited answer."""
    for event in client.agent.research(query=question, mode="fast"):
        if event.event == "error":
            message = event.data.error.message if event.data.error else "Documentation lookup failed"
            raise RuntimeError(message)


        if event.event == "complete":
            sources = [p.url for p in (event.data.metadata.cited_pages or [])]
            return {"answer": event.data.report, "sources": sources}


    raise RuntimeError("Stream ended before the complete event")




# The agent already knows where to look.
page = read_docs("https://docs.tabstack.ai/guides/research")
print(page[:500])


# The agent does not.
result = find_in_docs(
    "What is the current default value of the Tabstack research mode parameter?"
)
print(result["answer"])
print("Sources:", result["sources"])
```

Terminal window

```
# Read a page you already have the URL for
tabstack extract markdown https://docs.tabstack.ai/guides/research --nocache


# Ask when you do not know which page holds the answer
tabstack agent research "What is the current default value of the Tabstack research mode parameter?" --mode fast
```

## How it works

- **Two tools, not one.** Reading a known URL and finding an unknown one are different jobs with different costs. `/extract/markdown` is 10 credits and deterministic; `/research` runs several actions and bills for each. Giving the agent both lets it pick the cheap path when it can.
- **Markdown is what a model wants.** `/extract/markdown` strips navigation, ads, and boilerplate before the content reaches your context window, so a long page costs what its prose costs rather than what its markup costs.
- **`nocache: true` matters here specifically.** Page content is cached by URL, effort, and region rather than by account. For documentation that changes between releases, a cached copy is the exact failure you were trying to avoid. See [Data Handling](/trust/data-handling#caching/index.md).
- **The citations are the point.** When the agent answers from `findInDocs`, `citedPages` gives you the URLs behind the claim, so a reviewer can check the answer instead of trusting it.

## Wiring it into an agent

If your agent runs on a framework, skip the hand-rolled tools: the maintained packages expose `extract_page_content` and `research_question` with the same names across languages. See [LangChain (Python)](/integrations/langchain-python/index.md), the [Vercel AI SDK](/integrations/vercel-ai/index.md), or the [Hermes plugin](/integrations/hermes/index.md).

For a coding agent in a terminal, the [CLI](/getting-started/cli/index.md) is often enough. It prints human-readable output in a terminal and switches to JSON when piped.

## Installation

- [TypeScript](#tab-panel-9)
- [Python](#tab-panel-10)

Terminal window

```
npm install @tabstack/sdk
```

Terminal window

```
pip install tabstack
```

Set your API key before running:

Terminal window

```
export TABSTACK_API_KEY=your_api_key
```
