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.
What DocTheCode does
DocTheCode / 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
Install Docker: Docker Desktop on macOS or Windows, or Docker Engine on Linux. Podman also works; type
podmanwherever you seedocker.Build from the
docthecodefolder: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
| Requirement | Why |
|---|---|
Persistent storage at /data (1 GB is plenty to start) | The database, doc repositories and secret key live there |
| Exactly one instance, always running | One 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 provider | DocTheCode calls their APIs |
| About 1 GB of memory | DocTheCode 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.
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.
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.
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.
1. Connect GitHub. Choose Create automatically (recommended) or I already have an app.
Install the app on the repositories you want documented, using Install app on repositories ↗.
2. Choose the AI for the documentation agent (step 7). You can also do this later under Admin.
3. Sign in with GitHub. Whoever signs in here becomes DocTheCode's first admin. Everyone else just opens the same address and signs in.
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.
On the setup page (or Admin → Create a new GitHub App), select Create automatically.
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.Fill in the form:
Field What to enter Create under organization optional Your 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 name Any name up to 34 characters that's unique on GitHub. DocTheCode suggests DocTheCodeplus a random suffix.GitHub can reach this address Tick 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 install Leave unticked, unless your code is in organizations other than the one that owns the app. Click Create the GitHub App on GitHub.com →. GitHub shows the app it's about to create; confirm with Create GitHub App.
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.
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).
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.
Set the Callback URL to your DocTheCode address followed by
/api/auth/callback, for examplehttps://docs.example.com/api/auth/callback. The setup page shows the exact value. Save.In DocTheCode, select I already have an app (or Admin → Add an existing GitHub App) and fill in:
Field Where to find it Id, Name You choose. Keep github/GitHubfor GitHub.com.GitHub URL https://github.com, or your Enterprise Server address. Leave API URL empty.App ID A number in the About box on the app's General tab. App slug The last part of the app's public link: github.com/apps/this-part.Client ID Starts with Iv, in the About box.Client secret Client secrets → Generate a new client secret. GitHub shows it only once. Webhook secret The 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 .pemfile; pick it in DocTheCode.Click Save GitHub App, then make sure the app is installed on your repositories.
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.
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.
Fill in the basics:
Setting Value GitHub App name Any unique name, such as DocTheCode AcmeHomepage URL Your DocTheCode address Callback URL https://YOUR-DOCTHECODE/api/auth/callbackExpire user authorization tokens On Request user authorization (OAuth) during installation Off Webhook → Active If 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 Set the permissions:
Permission Access Used for Repository → Checks Read & write The DocTheCode / documentation approvedcheckRepository → Pull requests Read & write Reading PRs and commenting the link to the doc PR Repository → Contents Read-only Reading the changed code for the agent Repository → Metadata Read-only Required by GitHub Repository → Administration Read & write optional Making the check required in branch protection Organization → Members Read-only Inheriting team and organization members Organization → Copilot Requests Read-only optional Only if the agent uses GitHub Copilot If the webhook is active, subscribe to the events Pull request, Check run and Member.
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.
Install App (left menu) → choose the account → pick the repositories.
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.
| Provider | You need | Notes |
|---|---|---|
| Anthropic | API key | Claude models |
| OpenAI | API key | Pick a model with Load models |
| Google Gemini | Gemini API key | Uses Gemini's OpenAI-compatible endpoint |
| GitHub Copilot | No key | Uses 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 required | Azure AI Foundry, OpenRouter, Ollama, vLLM, LiteLLM and similar gateways |
Select the provider and paste the key.
Click Load models and pick one. It must support tool (function) calling.
Click Test. It runs a one-tool round trip to confirm the model works with DocTheCode, then save.
08Doc spaces & the merge gate
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.
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).
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 approvedas a required status check in the branch protection rules.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 PR | Check on the code PR |
|---|---|
| Agent drafting, or waiting for review | In progress (blocks the merge) |
| Approved on its latest commit | ✅ Success: the code PR can merge |
| Changes requested | ❌ Failure |
| Docs changed after approval | In 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.
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
Take the new release's image, for example
ghcr.io/tahseenadit/docthecode:0.4.2, or pull the new code withgit pulland build and push a new tag. Releases are listed on GitHub.Replace the running container with the new image, keeping the same
/datavolume (or/backupmount). Database tables are created automatically.Open the setup page or Admin to confirm the new version number.
Optional environment variables
None are needed. They only override defaults.
| Variable | Default | Use it to |
|---|---|---|
DOCTHECODE_PUBLIC_URL | Learned from the browser | Pin the address (also editable in Admin) |
DOCTHECODE_SECRET_KEY | Generated in /data/.secret_key | Keep the encryption key in a secret manager |
DATABASE_URL | Built-in PostgreSQL | Use an existing PostgreSQL database |
DOCTHECODE_SETUP_TOKEN | None | Require a token to run setup |
DOCTHECODE_TELEMETRY | on | off 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.
| Platform | Covers |
|---|---|
| Google Cloud Run | Build 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
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.comCreate a Docker repository, once:
gcloud artifacts repositories create AR_REPO \ --repository-format=docker --location=REGION \ --description="DocTheCode images"
Either let Cloud Build build and push the image, from the
docthecodefolder (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
| Flag | Why |
|---|---|
--no-allow-unauthenticated --iap | Keeps the service private and lets people in through Google sign-in (next step). |
--min-instances=1 --max-instances=1 | Exactly one instance, always running. |
--no-cpu-throttling | Keeps the CPU on between requests, so the agent and backups can finish. |
--memory=2Gi | Cloud 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=gen2 | Needed 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:
| Who | Role | Granted on | Without it |
|---|---|---|---|
IAP service agentservice-PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com | roles/run.invokerCloud Run Invoker | The Cloud Run service | “Forbidden” for everyone |
| Each person or group using DocTheCode | roles/iap.httpsResourceAccessorIAP-secured Web App User | IAP for the service | IAP's “You don't have access” page |
With gcloud:
Turn IAP on for the service. Skip this if you deployed with
--iap.gcloud run services update SERVICE --region=REGION --iap
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
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
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:
Cloud Run → your service → Security tab.
Under Authentication, choose Require authentication and tick Identity-Aware Proxy (IAP). Click Save, then View diff & redeploy → Deploy changes.
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.
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 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.