DEV Community

Willen Gitonga
Willen Gitonga

Posted on AI-assisted

Build and publish a developer docs site with Thally

What you'll build

Thally is a documentation platform that builds and hosts docs sites from a GitHub repository. In this article you'll publish a documentation site for your own project with Thally: an introduction, a quickstart, a practical guide and an API reference, live at a thally.app address, with its source in a GitHub repository you own.

I built mine for a small FastAPI helper that sends M-Pesa STK Push payment prompts. You can see the result at mpesa-stk-helper.thally.app and its source at github.com/willen-gitonga/mpesa-stk-service. Setup and publishing took me about an hour and a half, and most of the effort went into writing and checking content, not configuring Thally.

Along the way I hit a few obstacles. Each one is described where it happened, with how I resolved it.

Prerequisites

  • A Thally Cloud account. A new workspace gets a one-time trial that covers up to three sites.
  • A GitHub account with permission to install the Thally GitHub App on the account that will own the docs repository.
  • A project to document, ideally in its own GitHub repository.
  • Git and Node.js for editing and previewing the site locally. You don't need them to publish Thally's starter site. I used Node.js v22.23.3. You'll also want a plain text file open for notes. Writing down each problem as it happens makes the troubleshooting sections much easier to write later.

Step 1: Create the site in Thally Cloud

Thally's recommended path creates the site, its GitHub repository and the first deployment for you, with no local setup.

  1. Go to app.thally.io, sign in, and select Create a site.
  2. Enter a site name and choose your thally.app address. Thally checks that the address is available.
  3. Choose Create a new docs repository. When GitHub asks you to install the Thally GitHub App, the quickstart tells you to grant access to All repositories, so the app can set up the repository it creates. If your organization only allows access to selected repositories, the quickstart describes an alternative using an existing Thally repository.
  4. Under Product sources, connect your project's repository or choose I'll do this later. Skip Knowledge surfaces for now.
  5. Review the details and select Publish site. When the Home page shows the site as Live, open View live site.

Obstacle: I expected Thally to write my docs

I connected my project's repository as a product source, so I assumed the published site would contain documentation about my project. It showed Thally's starter pages instead, and I thought I'd missed a step.

Product sources feed Thally Track, which watches your project for merged changes and suggests documentation updates. When I connected my helper repo, Track also generated a first draft from a snapshot of it: Thally's GitHub app opened a pull request ("Generate product documentation") in my docs repo, with 15 changed files and a deploy preview.

How I resolved it: I treated the starter site as a working shell and the generated pull request as a first draft to check, not finished documentation. If you connected a product source, look for the same pull request in your docs repository and open its deploy preview from the Thally bot comment. Then either merge it and correct the pages afterwards, as I did, or check out its branch and fix the pages before merging. Step 3 covers what I found.

Step 2: Configure the site locally

Open the repository shown in your site summary, clone it, and start the local preview:

git clone https://github.com/YOUR-ACCOUNT/YOUR-DOCS-REPO.git
cd YOUR-DOCS-REPO
npm install
npm run dev
Enter fullscreen mode Exit fullscreen mode

Three files control almost everything:

File What it controls
src/content/*.mdx Each page's content, with its title and description in frontmatter
docs.json Tabs, sidebar groups and page order
src/data/site.ts Product name, description and links

Set your product name and links in site.ts first. Then plan the sidebar in docs.json. Each page is listed by its path inside src/content/, without the .mdx extension, and the groups sit inside the tabs entry. Here's the structure I ended up with:

"groups": [
  { "group": "Getting Started", "pages": ["introduction", "quickstart"] },
  { "group": "Guides", "pages": ["guides/sandbox-callbacks"] },
  { "group": "API Reference", "pages": ["api/stk-push", "api/payment-status", "api/callbacks"] },
  { "group": "Reference", "pages": ["configuration"] }
]
Enter fullscreen mode Exit fullscreen mode

The order follows how a reader moves through the docs: get started, complete a real task, then look up details.

Obstacle: edits to pages didn't hot reload

With npm run dev running, saving a change to an .mdx page didn't update the preview. I had to stop and restart the dev server to see each change.

I didn't find the cause within my time budget. Restarting the server worked as a workaround. If you hit this, check whether your project folder is synced by iCloud, OneDrive or Dropbox, since file watchers often miss changes in synced folders. Moving the project outside the synced folder is the usual fix.

Step 3: Write the content

Plan your pages around what a new reader needs, in the order they need it:

  • Introduction: what the project does, who it's for, and what it doesn't do.
  • Quickstart: the shortest path to a real result, with the expected output after each step.
  • Guide: one complete task, with an example and troubleshooting.
  • Reference: the details readers look up later, such as endpoints and settings. Each page is an MDX file with frontmatter at the top:
---
title: Quickstart
description: Run the helper in mock mode and send your first payment prompt.
---

In this quickstart you'll run the helper locally and send an STK Push.
Enter fullscreen mode Exit fullscreen mode

For sequences, Thally's Steps component numbers each step and keeps its commands together:

<Steps>
  <Step title="Start the server">
    Run `uvicorn app.main:app --reload` from the project root.
  </Step>
</Steps>
Enter fullscreen mode Exit fullscreen mode

MDX treats curly braces and angle brackets in normal text as code, so keep things like {PUBLIC_BASE_URL} inside backticks or code blocks.

Obstacle: the generated draft was confidently wrong

The pages Thally generated from my repository were well structured and mostly accurate. But when I checked each claim against the code, I found problems a reader would have hit:

  • A description saying tokens refresh automatically. The code only fetches a new token when the cached one is close to expiring.
  • A dependency table with a wrong FastAPI version, duplicating requirements.txt.
  • Setup steps that named the virtual environment virtual, which .gitignore didn't ignore, so readers would have committed it.
  • Expected server output that didn't match what the server actually prints.
  • A claim that valid Kenyan numbers starting with 2546 were rejected, and an unverified claim that Safaricom retries callbacks.
  • No practical guide at all, only reference pages. How I resolved it: In a follow-up pull request, I rewrote the introduction and quickstart, moved the sandbox setup into a new guide, and deleted the generated changelog. Track's draft also included a reference page for each API endpoint, and I kept those after checking them against the code.

Testing my own commands caught one more problem. I ran uvicorn main:app out of habit and got Could not import module "main", because the app lives in app/main.py. The correct command is uvicorn app.main:app, run from the project root. I added the error to the quickstart's troubleshooting table, since readers will make the same mistake.

The lesson: treat generated docs as a first draft, and only publish output you've seen in your own terminal.

Step 4: Publish your changes

Thally publishes whatever is on your production branch, so work on a separate branch and merge through a pull request.

  1. Create a branch and commit each logical change separately:
   git checkout -b rewrite-docs
   git add src/content/introduction.mdx
   git commit -m "Rewrite introduction for accuracy and audience"
Enter fullscreen mode Exit fullscreen mode
  1. Before pushing, validate the site and make sure it builds:
   npx --yes @thallylabs/cli@latest check
   npm run build
Enter fullscreen mode Exit fullscreen mode

The check catches problems such as a page listed in docs.json that doesn't exist.

  1. Push the branch and open a pull request into your production branch:
   git push -u origin rewrite-docs
Enter fullscreen mode Exit fullscreen mode
  1. Before merging, open the deploy preview. Thally posts it as a bot comment on the pull request, and it's easy to miss under the CI checks. I missed it, and the comment's link was removed once I merged, so I checked my changes locally with npm run dev instead.
  2. Merge the pull request. Thally builds and publishes the new version, and the deployment appears in your site's deployment history. My live site updated after the merge. Finally, open your live site and click through every page and link once more.

What I'd tell you before you start

  • Keep notes as you go. Every obstacle in this article came from a note I wrote in the moment. They became my troubleshooting rows.
  • Test your quickstart in a fresh folder. Reading it isn't enough. Running the commands myself is how I caught the import error.
  • Keep it small. An introduction, one quickstart and one guide are enough for a useful site. Add reference pages only where readers will look things up. You now have a live documentation site and a workflow for updating it: edit on a branch, check, preview and merge. My finished site is at mpesa-stk-helper.thally.app if you want to compare.

Top comments (0)