---
title: Research pages
description: "Optional. Question and thesis pages that Roadstar's research writer makes. 6 tools."
group: pages
tools: [pages.list, pages.read, pages.request, pages.update, pages.move, pages.mark]
source: [packages/agents/src/tools/features.ts]
generated: true
---

> Roadstar docs for agents. Every page, as markdown: https://docs.roadstar.app/llms.txt

Optional research tools, from Roadstar's research product. Every agent has them, but they aren't for the business's own work: a client's proposal is a [doc](/tools/docs/), not a research page.

`request` starts a page on a question and costs money with no price up front, so it is always checked.

## How to use it

What `find_tools` sends with these tools, word for word:

> Research pages in this workspace: question and thesis pages the reporter writes.

## Tools

| Tool | What it does | Owner's yes |
| --- | --- | --- |
| [pages.list](#list) | Pages, newest first | No |
| [pages.read](#read) | A page with its content and sources | No |
| [pages.request](#request) | Start a research page on a question, in the project the owner names, else the one you file into. A page costs money and has no price up front | Checked |
| [pages.update](#update) | Change figures in a page the owner requested, each edit replacing words the page has now; label names the figure | Checked |
| [pages.move](#move) | Move a page to another project | Checked |
| [pages.mark](#mark) | Star or follow a page | No |

## list

`pages.list` · Pages, newest first.

**Owner's yes:** No. Nothing of the owner's changes.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `projectId` | id | no |  |
| `title` | text | no | up to 300 characters |
| `type` | one of `question`, `thesis` | no |  |
| `status` | one of `queued`, `running`, `failed`, `published` | no |  |
| `offset` | whole number | no | 0 or more |

Returns:

```ts
{
  items: {
    id: string;
    title: string;
    type: "question" | "thesis" | "doc";
    projectId: string;
    projectName: string;
    status: "draft" | "published" | "archived";
    generationStatus: "queued" | "running" | "failed" | "completed" | null;
    updatedAt: string;
  }[];
  nextOffset: number | null;
}
```

## read

`pages.read` · A page with its content and sources.

**Owner's yes:** No. Nothing of the owner's changes.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `pageId` | id | yes |  |

Returns:

```ts
{
  state: "doc";
  projectId: string;
  organizationId: string;
  agentId: string | null;
  page: {
    id: string;
    title: string;
    type: "doc";
  };
} | {
  projectId: string;
  organizationId: string;
  agentId: string | null;
  errorMessage: string;
  page: {
    id: string;
    slug: string;
    title: string;
    type: "question" | "thesis";
  };
  state: "failed";
  phase?: undefined;
} | {
  projectId: string;
  organizationId: string;
  agentId: string | null;
  page: {
    id: string;
    slug: string;
    title: string;
    type: "question" | "thesis";
  };
  phase: "queued" | "writing" | "researching" | "verifying";
  state: "generating";
  errorMessage?: undefined;
} | {
  page: {
    id: string;
    title: string;
    type: "question" | "thesis";
  };
  projectId: string;
  organizationId: string;
  agentId: string | null;
  state: "unavailable";
} | {
  projectId: string;
  organizationId: string;
  agentId: string | null;
  type: "question";
  author: {
    image: string | null;
    name: string;
  };
  canonicalUrl: string;
  description: string;
  currentRevisionId: string | null;
  id: string;
  isAuthenticated: boolean;
  isFollowing: boolean;
  isStarred: boolean;
  isPublished: boolean;
  model: GeneratedPageDocumentModel;
  publishedAt: string;
  slug: string;
  state: "ready";
  starCount: number;
  wordCount: number;
  page?: undefined;
} | {
  projectId: string;
  organizationId: string;
  agentId: string | null;
  type: "thesis";
  state: "ready";
  id: string;
  slug: string;
  model: {
    artifact: {
      type: "thesis";
      version: 1;
      horizon: "1-2" | "2-5" | "5-10";
      relatedQuestion: {
        id: string;
        title: string;
        slug: string;
      } | null;
      asOf: string;
      assessment: {
        summaryMarkdown: string;
        bodyMdx: string;
        conviction: "low" | "medium" | "high" | "insufficient";
        rationaleMarkdown: string;
        changeConditions: string[];
      };
      pillars: {
        id: string;
        side: "for" | "against";
        title: string;
        explanationMarkdown: string;
      }[];
      articles: {
        date: string | null;
        datePrecision: "day" | "month" | "year" | null;
        stance: "supporting" | "challenging" | "mixed";
        pillarIds: string[];
        relevanceMarkdown: string;
        documentId: string;
        title: string;
        url: string;
        author: string | null;
        imageUrl: string | null;
        confidence: "low" | "medium" | "high" | null;
      }[];
    };
    title: string;
  };
  author: {
    image: string | null;
    name: string;
  };
  canonicalUrl: string;
  description: string;
  currentRevisionId: string | null;
  isPublished: boolean;
  isAuthenticated: boolean;
  isFollowing: boolean;
  isStarred: boolean;
  starCount: number;
  firstPublishedAt: string | null;
  publishedAt: string | null;
  page?: undefined;
}
```

## request

`pages.request` · Start a research page on a question, in the project the owner names, else the one you file into. A page costs money and has no price up front.

**Owner's yes:** Checked. It carries a note for the check to weigh, such as a cost.\
**Your work:** listed on Home.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `projectId` | id | no |  |
| `question` | text | yes | 1–2,000 characters |
| `context` | text | no | up to 4,000 characters |

Returns:

```ts
{
  pageId: string;
  slug: string;
  generationToken: string;
  status: "queued" | "running" | "failed" | "completed";
}
```

## update

`pages.update` · Change figures in a page the owner requested, each edit replacing words the page has now; label names the figure.

**Owner's yes:** Checked. It changes what's there.\
**Your work:** listed on Home, with Undo.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `pageId` | id | yes |  |
| `title` | text | no | up to 200 characters |
| `edits` | list of `{ label, find, replace, was?, now? }` | yes | 1–12 items |
| `edits[].label` | text | yes | 1–120 characters |
| `edits[].find` | text | yes | 1–2,000 characters |
| `edits[].replace` | text | yes | up to 2,000 characters |
| `edits[].was` | text | no | up to 60 characters |
| `edits[].now` | text | no | up to 60 characters |
| `sentence` | object | no |  |
| `sentence.before` | text | yes | 1–2,000 characters |
| `sentence.after` | text | yes | 1–2,000 characters |
| `source` | object | yes |  |
| `source.label` | text | yes | 1–200 characters |
| `source.href` | text | yes | 1–2,000 characters |
| `quote` | text | no | up to 1,000 characters |

Returns:

```ts
{
  pageId: string;
  replaced: string;
  published: {
    revisionId: string;
    revisionNumber: number;
  };
}
```

## move

`pages.move` · Move a page to another project.

**Owner's yes:** Checked. It changes what's there.\
**Your work:** listed on Home.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `pageId` | id | yes |  |
| `projectId` | id | yes |  |

Returns:

```ts
{
  id: string;
  projectId: string | null;
}
```

## mark

`pages.mark` · Star or follow a page.

**Owner's yes:** No. It makes something new.\
**Your work:** listed on Home.

| Input | Type | Required | Limits |
| --- | --- | --- | --- |
| `pageId` | id | yes |  |
| `action` | one of `star`, `follow` | yes |  |
| `enabled` | true or false | yes |  |

Returns:

```ts
{
  pageId: string;
  action: "star" | "follow";
  enabled: boolean;
}
```

## Types

Named types in the results above.

```ts
type GeneratedPageDocumentModel = {
  artifact: {
    bodyMdx: string;
    charts: {
      description: string | null;
      id: string;
      noteMarkdown: string | null;
      rows: {
        sourceDocumentIds: string[];
        values: (number | null)[];
        x: string;
      }[];
      series: {
        key: string;
        label: string;
        unit: string | null;
      }[];
      title: string;
      type: "bar" | "line" | "area" | "donut";
      xLabel: string | null;
      yLabel: string | null;
    }[];
    dataTables: {
      columns: string[];
      id: string;
      rows: {
        cells: string[];
        sourceDocumentIds: string[];
      }[];
      title: string;
    }[];
    synopsisMarkdown: string;
    timelines: {
      id: "primary_timeline";
      items: {
        analysisMarkdown: string;
        bodyMarkdown: string;
        date: string | null;
        datePrecision: "day" | "month" | "year" | null;
        id: string;
        sourceDocumentIds: string[];
        title: string;
      }[];
    }[];
    version: 1;
    counterViewMarkdown?: string;
    visualizations?: {
      id: string;
      title: string;
      description: string;
      specJson: string;
      sourceDocumentIds: string[];
    }[];
  };
  sources: GeneratedPageDocumentSource[];
  title: string;
}

type GeneratedPageDocumentSource = {
  citationNumber: number;
  crawlStatus: "queued" | "failed" | "idle" | "crawling";
  datePrecision: "day" | "month" | "year" | null;
  id: string;
  hasSnapshot: boolean;
  publishedDate: string | null;
  title: string;
  url: string;
}
```
