Licensing & the trial
Four paths, one rule each:
| You are running on | Identity needed | Network calls | Cost |
|---|---|---|---|
| A public repo | none | public check only (see below) | free forever |
| A private repo, trial | dacip login |
one allow-check per run | free for 1 private repo |
| A private repo, licensed | RSA license file | none (renewal only) | paid |
| The GitHub App (PR gating) | App installation | server-side by nature | free tier / Team |
Public repos: free forever
Before scan, investigate, diff, baseline, or verify touches a private-path decision, DACIP checks locally whether the repo is public. Three steps:
git remote get-url originmust parse togithub.com/<owner>/<repo>.- An unauthenticated
GET https://api.github.com/repos/<owner>/<repo>must return 200 with"private": false. git ls-remoteagainst that URL must list your localHEADcommit among its ref SHAs. This is the anti-spoof step: pointingoriginat some unrelated public repo fails, because your commits don't exist there.
All three pass → no login, no ping, no meter. The check itself sends nothing about your code except one commit SHA; the analysis pipeline makes no network calls at all (there is no LLM in it — see /docs/determinism/).
Stale checkouts: ls-remote returns branch and tag tips only. If your HEAD is behind the remote — or ahead with unpushed commits — step 3 fails and the repo is treated as private. Pull (or push) and rerun. Any failure is treated as non-public by design, including DACIP_OFFLINE=1, no remote, or a non-GitHub host.
dacip login
Private repos need a GitHub sign-in. It's the standard device flow:
$ dacip login
To sign in, open https://github.com/login/device and enter code: ABCD-1234
Signed in as ana. Free trial: 1 private repo.
The OAuth scope is empty on purpose: the token can read your username and nothing else. DACIP never receives repo access, so it cannot read your code even in principle. The GitHub token is exchanged once for a DACIP session token and discarded; the session lands in ~/.dacip/session.json (mode 0600). dacip logout deletes it; dacip whoami prints your login.
The trial meter
On a non-public repo with a session and no license, each run sends exactly one request:
{ "session": "...", "repo_id": "r_<sha256 of the origin URL, truncated>" }
The repo_id is an opaque one-way hash — it lets the server count distinct repos per user (the free tier is 1 private repo, matching the App) without knowing which repo it is. The ping contains no source, no file names, no routes, no findings. What we can see: that user ana scanned some private repo, and how many times. What we never see: everything else — and public-repo runs and licensed runs never ping at all.
Over the cap, DACIP refuses with a pointer to pricing. It never degrades output silently.
Licensed binaries
A license is a signed JSON file (customer, plan, expires) verified fully offline against a public key embedded in the binary — no phone-home on the paid path. Default location ~/.dacip/license.json (override with DACIP_LICENSE). Licenses are issued for 30 days; renewal is one command against your customer token:
curl -H 'Authorization: Bearer <your token>' \
https://dacip-app.fly.dev/license -o ~/.dacip/license.json
States, in order: valid → expiring (≤14 days left, runs with a warning) → grace (expired ≤14 days, runs with a loud warning) → hard stop, exit 3. dacip license prints the current state and is never gated itself.
Team seats
The Team tier is $15 per active contributor per month, unlimited private repos. A seat is any unique PR author whose PR DACIP gated in the billing month — counted automatically from webhook events, never self-reported. Bot logins (*[bot], plus dependabot, renovate, github-actions) are excluded. If a seat limit is hit, new contributors' PRs are visibly ungated — never blocked, never silently skipped. Details in /docs/github-app/.
The honest ceiling
Because DACIP never uploads source, it can never fully prove a local working tree is private. A determined user can spoof the public check by patching the binary. We accept that: the check raises the bar from "rename a remote" to "publish your code or patch the binary", and we stop there rather than adding phone-home to the paid path. More on this trade-off in the FAQ.
New to DACIP? Start at /docs/quickstart/ — no account needed on a public repo.

