DocTheCode Guide
DocTheCode v0.4.1 Hosting examples README GitHub

Documentation that keeps up with every pull request

DocTheCode is a self-hosted documentation hub that signs you in with GitHub. Connect a doc space to a code repository, and every pull request opens a matching doc PR. An AI agent drafts it, and the code PR can't merge until someone approves the docs.

Current version
0.4.1
Ships as
One Docker image with PostgreSQL built in
License
Apache 2.0, open source

What DocTheCode does

Open a PRA developer opens a pull request on GitHub.
Doc PR appearsDocTheCode opens a doc PR in the connected doc space.
Agent draftsThe AI agent reads the diff and updates the pages.
ReviewA teammate approves the doc PR or asks for changes.
Check turns greenDocTheCode / documentation approved passes, and the code PR can merge.
  • Sign in with GitHub: GitHub.com (including Enterprise Cloud) or GitHub Enterprise Server.
  • Doc spaces are wikis: page trees organized like Confluence, independent of how the code is laid out.
  • Members come from GitHub: anyone with access to the connected repository gets the matching role automatically.
  • Any AI provider: Anthropic, OpenAI, Google Gemini, GitHub Copilot, or any OpenAI-compatible endpoint.
  • Runs where you want: a VM, Kubernetes, or any cloud container service. Nothing is configured before it starts; setup happens in the browser.
  • Your data stays yours: docs, code and names stay on your server. The only thing that can leave it is optional, anonymous usage statistics, which admins can switch off.

Get the code

The source, Dockerfile and README are in the GitHub repository. You only need the code if you build the image yourself.

DocTheCode is open source under the Apache 2.0 license, at github.com/tahseenadit/docthecode.

git clone https://github.com/tahseenadit/docthecode.git
cd docthecode

Check the version you have: it's VERSION in backend/app/config.py, and once DocTheCode is running it's shown next to the title of the setup page.

01Get the image

Use the prebuilt image, or build your own. Building never needs Node, Python or PostgreSQL on your machine: the build fetches them.

Option A: the prebuilt image

Every release is published to GitHub Container Registry. Use it directly as the image your host runs, or pull it:

docker pull ghcr.io/tahseenadit/docthecode:0.4.1

Option B: build with Docker on your computer

  1. Install Docker: Docker Desktop on macOS or Windows, or Docker Engine on Linux. Podman also works; type podman wherever you see docker.

  2. Build from the docthecode folder:

    docker build --platform linux/amd64 -t docthecode:0.4.1 .

Option C: build in your fork with GitHub Actions

Fork the repository. The included workflow .github/workflows/build-image.yml runs the tests and publishes ghcr.io/<account>/docthecode on every push to main and every version tag such as v0.4.1. Packages start out private: give your host a token with read:packages, or make the package public.

Option D: your cloud's build service

Most clouds can build a Dockerfile for you and store the result in their own registry, so nothing runs on your machine. The Google Cloud Run example shows this with Cloud Build.

02Host it

DocTheCode runs anywhere that runs containers: a VM with Docker, Kubernetes, or a cloud container service.

What any host needs

RequirementWhy
Persistent storage at /data (1 GB is plenty to start)The database, doc repositories and secret key live there
Exactly one instance, always runningOne database; background jobs and the agent must keep running
An HTTPS address forwarding to port 8080 (or $PORT if the host sets one)People open DocTheCode there
Outgoing internet access to GitHub and your AI providerDocTheCode calls their APIs
About 1 GB of memoryDocTheCode and PostgreSQL together

Push the image to a registry

Skip this if you use the prebuilt image, built with GitHub Actions, or build on the host itself. Otherwise push to any registry your host can pull from, such as Docker Hub, GitHub Container Registry, or your cloud's registry:

docker tag docthecode:0.4.1 REGISTRY/docthecode:0.4.1
docker push REGISTRY/docthecode:0.4.1

Run it

On a machine with Docker:

docker run -d --name docthecode --restart unless-stopped \
  -p 8080:8080 -v docthecode-data:/data ghcr.io/tahseenadit/docthecode:0.4.1

Use your own registry path instead if you built the image yourself.

Then put HTTPS in front of it: your load balancer, an ingress, or a reverse proxy such as Caddy or nginx. docker compose up -d with the included docker-compose.yml does the same.

Hosts without persistent disks

Some container services wipe the container's disk on every restart. There, mount a bucket or network folder at /backup instead. DocTheCode writes a consistent snapshot there within about 30 seconds of every change and on shutdown, and restores it automatically when a new container starts. Never point /data itself at a bucket: PostgreSQL needs a real disk. DocTheCode logs a warning at startup if it finds neither.

Step-by-step for a specific platform

See Hosting examples. More platforms will be added over time.

03First-run setup

There's no config file. Everything is entered in the browser and stored encrypted.

  1. Open DocTheCode's address. Until setup is finished, the first person to open it gets the setup page. Its title shows the version (it should say 0.4.1) and the address DocTheCode detected from your browser.

  2. 1. Connect GitHub. Choose Create automatically (recommended) or I already have an app.

  3. Install the app on the repositories you want documented, using Install app on repositories ↗.

  4. 2. Choose the AI for the documentation agent (step 7). You can also do this later under Admin.

  5. 3. Sign in with GitHub. Whoever signs in here becomes DocTheCode's first admin. Everyone else just opens the same address and signs in.

Reachable from the internet before setup?

Start the container with DOCTHECODE_SETUP_TOKEN=some-long-secret. The setup page then asks for that token first, so a stranger can't take over setup. On a private network or behind a login proxy you don't need it.

04Create the GitHub App from DocTheCode

The quickest way: DocTheCode sends GitHub a ready-made app definition, and GitHub hands the keys straight back. Nothing to copy or paste.

  1. On the setup page (or Admin → Create a new GitHub App), select Create automatically.

  2. Choose GitHub.com (also for GitHub Enterprise Cloud) or GitHub Enterprise Server. For Enterprise Server, enter its address, such as https://github.your-company.com. DocTheCode suggests a short id and a sign-in button name from it.

  3. Fill in the form:

    FieldWhat to enter
    Create under organization optionalYour organization's name, as in github.com/your-org. Recommended for teams, so the app belongs to the organization. You must be an owner or GitHub App manager there. Leave it empty to create the app under your personal account.
    App nameAny name up to 34 characters that's unique on GitHub. DocTheCode suggests DocTheCode plus a random suffix.
    GitHub can reach this addressTick it only if GitHub can reach DocTheCode over the internet. If DocTheCode is private (behind a VPN, firewall or login proxy), untick it and see step 9.
    Allow other accounts to installLeave unticked, unless your code is in organizations other than the one that owns the app.
  4. Click Create the GitHub App on GitHub.com →. GitHub shows the app it's about to create; confirm with Create GitHub App.

  5. GitHub returns you to DocTheCode, which saves the App ID, client secret, webhook secret and private key, encrypted. Click Install app on repositories ↗ and choose the repositories.

DocTheCode sets the callback URL, permissions and events for you. They're the same ones listed in step 6.

One GitHub.com connection at a time

If DocTheCode is already connected to GitHub.com, the GitHub.com option is unavailable. To switch to a different app, click Remove on the existing connection first. You can add GitHub Enterprise Server connections alongside it with Connect GitHub Enterprise Server too.

05Use an existing GitHub App

Use this when your organization already created a DocTheCode app, or when you created one by hand (step 6).

  1. On GitHub, open the app's settings: Settings → Developer settings → GitHub Apps → your app → Edit. For an organization's app, start from the organization's Settings.

  2. Set the Callback URL to your DocTheCode address followed by /api/auth/callback, for example https://docs.example.com/api/auth/callback. The setup page shows the exact value. Save.

  3. In DocTheCode, select I already have an app (or Admin → Add an existing GitHub App) and fill in:

    FieldWhere to find it
    Id, NameYou choose. Keep github / GitHub for GitHub.com.
    GitHub URLhttps://github.com, or your Enterprise Server address. Leave API URL empty.
    App IDA number in the About box on the app's General tab.
    App slugThe last part of the app's public link: github.com/apps/this-part.
    Client IDStarts with Iv, in the About box.
    Client secretClient secrets → Generate a new client secret. GitHub shows it only once.
    Webhook secretThe Webhook → Secret field. If it's empty there, type the same long random text in both places and save on GitHub.
    Private key (.pem)Private keys → Generate a private key downloads a .pem file; pick it in DocTheCode.
  4. Click Save GitHub App, then make sure the app is installed on your repositories.

Need a webhook secret without webhooks?

The field is still required. Any long random text works, for example the output of openssl rand -hex 32.

06Create the app on GitHub by hand

For organizations that create GitHub Apps themselves, or when the automatic flow isn't allowed.

  1. Open New GitHub App: your profile Settings → Developer settings → GitHub Apps → New GitHub App, or the organization's Settings → Developer settings → GitHub Apps → New GitHub App. On Enterprise Server, the same menus are on your server.

  2. Fill in the basics:

    SettingValue
    GitHub App nameAny unique name, such as DocTheCode Acme
    Homepage URLYour DocTheCode address
    Callback URLhttps://YOUR-DOCTHECODE/api/auth/callback
    Expire user authorization tokensOn
    Request user authorization (OAuth) during installationOff
    Webhook → ActiveIf GitHub can reach DocTheCode: on, with URL https://YOUR-DOCTHECODE/api/webhooks/github/github (the last part is the connection's Id in DocTheCode) and a long random secret.
    If DocTheCode is private: off (see step 9).
    Where can this app be installed?Only on this account
  3. Set the permissions:

    PermissionAccessUsed for
    Repository → ChecksRead & writeThe DocTheCode / documentation approved check
    Repository → Pull requestsRead & writeReading PRs and commenting the link to the doc PR
    Repository → ContentsRead-onlyReading the changed code for the agent
    Repository → MetadataRead-onlyRequired by GitHub
    Repository → AdministrationRead & write optionalMaking the check required in branch protection
    Organization → MembersRead-onlyInheriting team and organization members
    Organization → Copilot RequestsRead-only optionalOnly if the agent uses GitHub Copilot
  4. If the webhook is active, subscribe to the events Pull request, Check run and Member.

  5. Click Create GitHub App. On the next page, generate a client secret and generate a private key, and note the App ID, Client ID and slug.

  6. Install App (left menu) → choose the account → pick the repositories.

  7. Enter everything in DocTheCode as in step 5.

07Choose the AI provider

The agent works the same with every provider. Only the model behind it changes. Set it during setup or under Admin → Documentation agent.

ProviderYou needNotes
AnthropicAPI keyClaude models
OpenAIAPI keyPick a model with Load models
Google GeminiGemini API keyUses Gemini's OpenAI-compatible endpoint
GitHub CopilotNo keyUses DocTheCode's GitHub App and is billed to the organization that owns the code. Give the app Copilot Requests (read) and allow Copilot requests from GitHub Apps in the organization's Copilot policies.
Other (OpenAI-compatible)Base URL, plus a key if requiredAzure AI Foundry, OpenRouter, Ollama, vLLM, LiteLLM and similar gateways
  1. Select the provider and paste the key.

  2. Click Load models and pick one. It must support tool (function) calling.

  3. Click Test. It runs a one-tool round trip to confirm the model works with DocTheCode, then save.

08Doc spaces & the merge gate

  1. On the dashboard, click New repository to create a doc space. Organize its pages like a wiki; they don't need to follow the code's folders.

  2. In the space's Settings, click Connect a GitHub repository and pick one the app is installed on. Everyone with access to it becomes a member with the matching role (GitHub admin → admin, maintain/write → write, triage/read → read).

  3. Tick Make the DocTheCode check required on the default branch. This needs admin rights on the GitHub repository. Without them, ask an admin to add DocTheCode / documentation approved as a required status check in the branch protection rules.

  4. Open a pull request on GitHub. DocTheCode opens the doc PR, the agent drafts it, and reviewers approve it or request changes. A change request can go back to the agent to redraft.

Doc PRCheck on the code PR
Agent drafting, or waiting for reviewIn progress (blocks the merge)
Approved on its latest commit✅ Success: the code PR can merge
Changes requested❌ Failure
Docs changed after approvalIn progress again: the approval is stale
Closed❌ Failure

When the code PR merges, the doc PR merges into the docs. When the code PR is closed, the doc PR closes too, and it can be reopened only while its code PR is open. Settings per connected repository include required approvals, whether the code PR's author may approve, and custom agent instructions.

GitHub Free

On GitHub Free, branch protection, which is what actually blocks the merge, works only on public repositories.

09When GitHub can’t reach DocTheCode

For DocTheCode on a private network, behind a firewall, VPN or login proxy.

GitHub usually notifies DocTheCode of new pull requests through webhooks, which need DocTheCode to be reachable from the internet. When it isn't:

  • Create the app with GitHub can reach this address unticked, or turn the webhook off in a manually created app.
  • Click ↻ Check GitHub for changes on the dashboard or on a doc space's Pull requests tab. DocTheCode asks GitHub what was opened, updated, merged or closed, and reacts exactly as it would to webhooks. Nothing runs on a timer.

Everything DocTheCode sends to GitHub works either way: the check on pull requests, comments, and approvals turning the check green immediately.

10Updating

  1. Take the new release's image, for example ghcr.io/tahseenadit/docthecode:0.4.2, or pull the new code with git pull and build and push a new tag. Releases are listed on GitHub.

  2. Replace the running container with the new image, keeping the same /data volume (or /backup mount). Database tables are created automatically.

  3. Open the setup page or Admin to confirm the new version number.

Optional environment variables

None are needed. They only override defaults.

VariableDefaultUse it to
DOCTHECODE_PUBLIC_URLLearned from the browserPin the address (also editable in Admin)
DOCTHECODE_SECRET_KEYGenerated in /data/.secret_keyKeep the encryption key in a secret manager
DATABASE_URLBuilt-in PostgreSQLUse an existing PostgreSQL database
DOCTHECODE_SETUP_TOKENNoneRequire a token to run setup
DOCTHECODE_TELEMETRYonoff disables anonymous usage data

Hosting examples

Step-by-step walkthroughs for specific platforms. DocTheCode isn't tied to any of them: each one is the general Host it step applied to one platform. More examples will be added over time.

PlatformCovers
Google Cloud RunBuild with Cloud Build or Docker, push to Artifact Registry, run privately behind Identity-Aware Proxy (IAP)

ExampleGoogle Cloud Run (private, with IAP)

A private Cloud Run service that people reach by signing in with their Google account. This also works where an organization policy forbids public services.

Replace the placeholders PROJECT_ID, REGION (such as europe-west1), AR_REPO, SERVICE, BUCKET and USER_EMAIL with your own values. You need the gcloud CLI, or Cloud Shell in the browser, which has it already.

1. Build and push to Artifact Registry

  1. Sign in, choose the project and turn on the services used here:

    gcloud auth login
    gcloud config set project PROJECT_ID
    gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com \
      run.googleapis.com iap.googleapis.com
  2. Create a Docker repository, once:

    gcloud artifacts repositories create AR_REPO \
      --repository-format=docker --location=REGION \
      --description="DocTheCode images"
  3. Either let Cloud Build build and push the image, from the docthecode folder (nothing to install locally):

    gcloud builds submit --region=REGION \
      --tag REGION-docker.pkg.dev/PROJECT_ID/AR_REPO/docthecode:0.4.1

    or push an image you built with Docker (step 1):

    gcloud auth configure-docker REGION-docker.pkg.dev
    docker tag docthecode:0.4.1 REGION-docker.pkg.dev/PROJECT_ID/AR_REPO/docthecode:0.4.1
    docker push REGION-docker.pkg.dev/PROJECT_ID/AR_REPO/docthecode:0.4.1

2. Create a backup bucket

Cloud Run has no persistent disk, so DocTheCode keeps its data safe through a Cloud Storage bucket mounted at /backup (see Hosts without persistent disks in step 2).

gcloud storage buckets create gs://BUCKET --location=REGION --uniform-bucket-level-access

# Let the service's runtime account read and write the bucket
PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)')
gcloud storage buckets add-iam-policy-binding gs://BUCKET \
  --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
  --role=roles/storage.objectUser

If you run the service as a custom service account, grant the role to that account instead.

3. Deploy the service

gcloud run deploy SERVICE \
  --image=REGION-docker.pkg.dev/PROJECT_ID/AR_REPO/docthecode:0.4.1 \
  --region=REGION \
  --no-allow-unauthenticated --iap \
  --min-instances=1 --max-instances=1 --no-cpu-throttling \
  --cpu=1 --memory=2Gi --execution-environment=gen2 --port=8080 \
  --add-volume=name=backup,type=cloud-storage,bucket=BUCKET \
  --add-volume-mount=volume=backup,mount-path=/backup
FlagWhy
--no-allow-unauthenticated --iapKeeps the service private and lets people in through Google sign-in (next step).
--min-instances=1 --max-instances=1Exactly one instance, always running.
--no-cpu-throttlingKeeps the CPU on between requests, so the agent and backups can finish.
--memory=2GiCloud Run holds the container's disk in memory, and the database lives there. 1 GiB works for small teams; 2 GiB leaves room for growth.
--execution-environment=gen2Needed for the Cloud Storage volume mount.

Print the service's address:

gcloud run services describe SERVICE --region=REGION --format='value(status.url)'

Opening it now gives Error: Forbidden. That's expected until you finish the next step.

4. Make it reachable with IAP (fixes “Forbidden”)

A private Cloud Run service only accepts requests that carry an identity it trusts. A browser doesn't send one, so you get “Error: Forbidden. Your client does not have permission to get URL / from this server.” Identity-Aware Proxy (IAP) fixes this: it signs people in with their Google account, checks they're allowed in, then calls the service on their behalf. It needs two permissions:

WhoRoleGranted onWithout it
IAP service agent
service-PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com
roles/run.invoker
Cloud Run Invoker
The Cloud Run service“Forbidden” for everyone
Each person or group using DocTheCoderoles/iap.httpsResourceAccessor
IAP-secured Web App User
IAP for the serviceIAP's “You don't have access” page

With gcloud:

  1. Turn IAP on for the service. Skip this if you deployed with --iap.

    gcloud run services update SERVICE --region=REGION --iap
  2. Make sure IAP's service agent exists, then let it call the service:

    gcloud services identity create --service=iap.googleapis.com --project=PROJECT_ID
    
    PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)')
    gcloud run services add-iam-policy-binding SERVICE --region=REGION \
      --member="serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-iap.iam.gserviceaccount.com" \
      --role=roles/run.invoker
  3. Let people in. Repeat for each person, or grant a whole group or domain at once:

    gcloud iap web add-iam-policy-binding \
      --member=user:USER_EMAIL \
      --role=roles/iap.httpsResourceAccessor \
      --region=REGION --resource-type=cloud-run --service=SERVICE
    
    # Alternatives for --member: group:docs-team@company.com   domain:company.com
  4. Open the service's address. Google asks you to sign in, then DocTheCode's setup page loads. Role changes can take a minute or two to apply.

Or in the Google Cloud console:

  1. Cloud Run → your service → Security tab.

  2. Under Authentication, choose Require authentication and tick Identity-Aware Proxy (IAP). Click Save, then View diff & redeploy → Deploy changes.

  3. Still on the Security tab, under IAP, click Edit policy. Add each person, group or domain as a principal with the role IAP-secured Web App User, and save.

  4. Turning IAP on in the console usually grants the IAP service agent Cloud Run Invoker for you. If you still see “Forbidden”, grant it with step 2 of the gcloud list above, and redeploy once if it persists.

5. Finish setup

Continue with First-run setup. GitHub's webhooks can't pass IAP, so untick GitHub can reach this address when creating the GitHub App and use ↻ Check GitHub for changes (step 9).

If something goes wrong on Cloud Run

“Error: Forbidden — Your client does not have permission to get URL /”

Cloud Run rejected the request before it reached DocTheCode. Either IAP isn't on for the service, or the IAP service agent lacks roles/run.invoker. Follow part 4, and redeploy the service once if it persists.

IAP says “You don't have access”

You're signed in to Google, but that account lacks IAP-secured Web App User. Grant it as in part 4, and check you're signed in with the right Google account.

Data disappeared after a restart

The service started without the backup bucket. Check that /backup is mounted (part 3), that the runtime service account has roles/storage.objectUser on the bucket (part 2), and that --max-instances=1 is set. DocTheCode logs a warning at startup when it finds no storage.

The setup page shows an older version after an update

The service is still running the previous image. Deploy the new tag as below and reload the page.

Updating on Cloud Run

Build and push a new tag as in part 1, then point the service at it. IAP, the backup volume and all other settings stay as they are:

gcloud run services update SERVICE --region=REGION \
  --image=REGION-docker.pkg.dev/PROJECT_ID/AR_REPO/docthecode:0.4.2

To set optional environment variables, add --set-env-vars, or keep DOCTHECODE_SECRET_KEY in Secret Manager with --set-secrets.