If the content for your docs site already lives in a GitHub repository, this post is for you.

I do this a lot. The project is in git, and the docs sit right next to it. Usually a `docs/` folder. A handful of markdown files. A pull request when something changes.

Datalumo can ingest content a few ways. There is a [WordPress](/docs/wordpress) plugin. A [Shopify](/docs/shopify) app. A [Laravel](/docs/laravel) package. You can push pages through the API.

Those usually pull from a database. A WordPress post. A Laravel model. Rows that already live in the app.

This is different. The content is files. Markdown sitting in a GitHub repo. I wanted a way to get those into Datalumo without copying them into a dashboard, and keep search and chat up to date when I push?

That is what the GitHub Action is for.

## Set it up

In Datalumo, add a source of type **API**. Give it a slug you will remember, like `docs`.

Create an organisation API key with `pages.write` and `pages.read`. Limit it to that source if you can. Read is only there so the action can delete a page when a file leaves the folder.

You also need the organisation public id. That is the UUID, not the handle.

In the docs repo, add two secrets (`DATALUMO_TOKEN`, `DATALUMO_ORG`) and a workflow:

```yaml
name: Sync docs to Datalumo

on:
  push:
    branches: [main]
    paths:
      - "docs/**"
      - ".github/workflows/datalumo.yml"

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: datalumo/github-action@v1
        with:
          api_key: ${{ secrets.DATALUMO_TOKEN }}
          organisation: ${{ secrets.DATALUMO_ORG }}
          source: docs
          path: docs
          base_url: https://example.com/docs
```

`path` is the folder to upload. `base_url` is the public docs prefix, so a citation for `install.md` becomes `https://example.com/docs/install`.

Pin `@v1` and you get compatible updates. That is the whole setup.

## What happens on push

The action walks the folder and pushes `.md`, `.mdx`, `.html`, and `.txt`.

Each file gets a stable id: the path relative to `path`, without the extension. `install.md` stays `install`. `guides/install.md` stays `guides/install`. The next push updates the same page. It does not create a duplicate.

If you delete a file, that page is removed from the source. An empty folder fails the job. I did not want a typo in `path` to wipe a knowledge base.

Then Datalumo indexes in the background. Watch the source until it says Ready.

If your markdown has YAML frontmatter, `title` becomes the page name. `draft: true` or `hidden: true` stores the file but keeps it out of search and chat. Extra keys such as `tags` land on the page as metadata.

## Search and chat

Once the source is ready, open a [search](/docs/search) or [chat](/docs/chat) widget and point it at that source. One snippet. Preview it. Add your docs domain to the widget's website list.

People can ask a real question. The answer cites the page. If you add chat, they can follow up without leaving the docs.

## We use it too

This site's docs folder syncs the same way. When I change a page in `resources/docs`, the action updates the source the public search and chat read from. If it is good enough for our own docs, it should be good enough for yours.

The action lives here:

→ **[github.com/datalumo/github-action](https://github.com/datalumo/github-action)**

API details if you want to push pages yourself:

→ **[API push](/docs/api-push)**