Plansmith self-hosted Git broker
Let Plansmith read a Git server inside your network, without opening a firewall port and without giving us your credentials.
When you need one
If your GitLab, GitHub Enterprise or Bitbucket server is reachable from the internet, you do not need this. Register it directly and skip this page. The managed broker exists for the other case: a server that only answers inside your network, behind a VPN or a corporate firewall.
Self-hosted Git servers, including the broker, are available on the Team and Enterprise plans.
How it works
You run a small container inside your network. It dials out to Plansmith over TLS and asks for work. When a planning session needs to read your repository, we put a request on a queue; your broker picks it up, adds your own Git credential, calls your server, and posts the response back.
Every connection starts at the broker. Inside your network, the plansmith-broker container opens an outbound HTTPS connection to app.plansmith.co and asks for work; Plansmith answers on that connection with one allowlisted read; the broker calls your Git server with your own credential, gets the file, and posts the response back. Nothing connects inward.
One broker reaches one server. The container is configured with a single target URL, so if you have two internal Git servers you run two brokers, each with its own token. Plansmith enforces this: a broker that already reaches a server cannot be chosen for a second one.
What your security team will ask
- Inbound ports: none. The broker makes outbound connections only. There is no firewall rule to add, no inbound route, and no VPN access for us.
- Where credentials live: only in your network. Your Git token is an environment variable on your container. Plansmith never receives it, never stores it, and cannot read it. The broker overwrites the authorization header on every request with your token, so nothing we send can substitute a credential of ours.
- What can be reached: whatever the service account or API token you create allows. You set the reach in your own Git server, and Plansmith cannot exceed it: the broker holds no credential of its own, so an account with read access to two projects is an integration with read access to two projects. The container narrows it further, to the handful of read-only API calls Plansmith actually makes; a request outside that set is refused before it reaches your server, and the refusal is logged. No write endpoint is reachable through the broker at all.
- Audit: one JSON line per relayed request to the container log, recording timestamp, method, path, decision, status, duration and byte counts. Never request bodies, never file contents, never tokens.
- What we store, and for how long. What your broker returns is the context the planning agent works from, so it lives in that plan's chat for as long as the chat does. Getting it there uses a queue in our database, and those rows are deleted as they are read; anything a failed request leaves behind is scrubbed within the hour, and revoking a broker deletes its queued rows on the spot. Archive a plan and it is deleted 30 days later, its chats and everything read into them included.
Setting up your server
Select the git server you run.
The setup takes about fifteen minutes across three places, and each step names where you are. You will need:
- Owner access to the GitLab group or project you want to plan against, for steps 1 to 3
- A Plansmith owner on the Team or Enterprise plan for step 4
- A host inside your network with Docker, able to reach the GitLab server and to make outbound HTTPS to
app.plansmith.co, for step 5.
In GitLab: create a service account. A service account is GitLab's non-human account for exactly this: it has no password and no inbox, nobody can sign in as it, its reads appear in your audit logs under its own name, and it holds exactly the access Plansmith needs and nothing else.
- Open the group whose projects your team plans against. For a single repository, open that project instead.
- In the left sidebar, go to Settings → Service accounts.
- Select Add service account and name it
plansmith.
Create it on the group when several projects should be available; a project-level service account covers that one project. Creating one takes an owner of the group or project.
If Settings → Service accounts is not in your sidebar, your GitLab is older or on the Free tier. The fallback works the same way: an administrator creates a dedicated regular user in the Admin area (Overview → Users → New user), signs in as it once, and mints the token under Edit profile → Access tokens. Steps 2 and 3 are unchanged.
In GitLab: give it read access to the right projects. A service account starts with access to nothing, and its token can only see what the account can see. Membership is where you decide which code Plansmith can read; nothing outside it is reachable, whatever the token says.
- In the group (or project), go to Manage → Members and select Invite members.
- Invite the service account. Search for the name you gave it; it appears with a generated username
like
@service_account_…. - Give it the role Reporter.
- Repeat for any other group you want available. Subgroups and their projects inherit the membership.
Reporter is the floor. On a private project the Guest role can see that the project exists but cannot read its files, so a Guest membership passes every screen here and then produces empty file lists in step 6.
In GitLab: create the access token. Tokens for a service account are managed from the same page you created it on. You never sign in as the account.
- Back in Settings → Service accounts, open the ⋮ menu on the
plansmithrow and select Manage access tokens. - Select Add new token.
- Name it
plansmith-broker, pick an expiry your policy allows, and tick both scopes: read_api and read_repository. - Create it and copy the
glpat-value straight away. GitLab shows it once.
Both scopes, deliberately. The broker talks to the GitLab REST API, and the scope that opens it
is read_api. A token with only read_repository looks right, is accepted here, and then fails
step 6 with 403: that scope covers Git operations, not the API. Both scopes are read-only.
In Plansmith: add the server and get a pairing token.
- In Plansmith, open Settings → Connectors. You need to be an owner, on the Team or Enterprise plan.
- Under Self-hosted, select Add instance and pick GitLab.
- Where it asks whether the server is reachable from the internet, answer behind a firewall or VPN.
- Enter the server URL, for example
https://gitlab.example.internal. This is how the server appears in Plansmith; traffic goes wherever your container is configured to reach, so use the same URL here and inTARGET_GITLAB_BASE_URLin step 5. Private addresses and internal hostnames are fine. - Select Add managed broker and name it after where it will run, for example
dc-frankfurt. Thepsbk_pairing token is shown once, with the command for step 5 pre-filled.
Keep this tab open: the broker flips to Online here the moment the container makes its first poll.
On your host: run the container. On the Docker host inside your network, run the pre-filled command from step 4. It looks like this:
docker run -d --name plansmith-broker --restart on-failure:5 \
-e PLANSMITH_URL=https://app.plansmith.co \
-e PLANSMITH_BROKER_TOKEN=psbk_… \
-e TARGET_GITLAB_BASE_URL=https://gitlab.internal \
-e TARGET_GITLAB_TOKEN=glpat-… \
ghcr.io/braingridai/plansmith-broker:0.3.0PLANSMITH_URL: always https://app.plansmith.co. Not the API or MCP host, which serve a different
surface and will not answer a broker poll (the container refuses to start if you point it at one).
PLANSMITH_BROKER_TOKEN: the psbk_ token from step 4.
TARGET_GITLAB_BASE_URL: your GitLab as reachable from this container, the same URL you entered
in step 4.
TARGET_GITLAB_TOKEN: the glpat- token from step 3. It never leaves your network.
HTTPS_PROXY / NO_PROXY: optional, honoured if your egress goes through a proxy.
NODE_EXTRA_CA_CERTS: optional, point it at your CA bundle if a proxy terminates TLS or your server
uses a private CA.
AUDIT_LOG_PATH: optional. The audit log always goes to stdout; this also writes it to a file.
Verify end to end. Within a few seconds of the container starting, the broker shows
Online in Plansmith. Finish saving the instance: Plansmith verifies it by asking your broker to
call GET /user on your GitLab, with your token, from inside your network. When that succeeds, pick
the repositories your team should plan against. The list you are choosing from is the service
account's membership from step 2.
For a final check, attach one of those repositories to a plan and ask the planning agent something
about the code. The answer arrives through the broker, and docker logs plansmith-broker shows one
JSON audit line per file read.
If something is wrong
Everything below is about a running broker, so it is the git server's path.
- A startup error naming the host.
PLANSMITH_URLpoints at the API or MCP host. Useapp.plansmith.co. - Polls return 404. The pairing token was revoked, or mistyped. Add a new managed broker (step 4) and restart the container with its token.
- It stays Offline. Outbound HTTPS to
app.plansmith.cois blocked, or your proxy variables are not set on the container. - Verification fails with 403 on a fresh token. Two different halves fail identically from outside: the token is missing the scope that opens your server's REST API, or the account it belongs to is not a member of the group or project. Check both; your product's tab above names the scope and the role.
- Repositories are missing from the picker, or file lists come back empty. The account's membership does not cover them, or covers them at a level that can see a project exists but not read its files. Widen the membership; a broader token will not fix it, because the token can only ever see what the account can.
allowlist_deniedin the log. Working as designed: the container relays a fixed set of read-only API calls, and something outside it was requested and refused before reaching your server. Send us the line if you think that call should be allowed.- TLS errors. Set
NODE_EXTRA_CA_CERTSto your CA bundle. - Your monitoring shows requests with no response status. Expected. An idle broker holds a poll open for up to 25 seconds waiting for work, and some tools log the open request with an empty status. It completes as an ordinary 200.
Upgrading and shutting down
Pin a version tag or an image digest and redeploy to upgrade. To stop a broker for good, revoke it in Plansmith: its token stops working immediately, whatever version the container is running, and anything still queued for it is deleted.
To move a server to a different broker, start the new broker, then add the server again in Plansmith with the same URL and pick the new broker. Same URL means it updates the server you already have rather than creating a second one, and the repositories you have already linked keep working, so there is nothing to re-link.