> For the complete documentation index, see [llms.txt](https://docs.controltheory.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.controltheory.com/controltheory-documentation/dstl8-docs/code-graph/cli.md).

# CLI Reference

Full reference for dstl8 graph build, push, repos, and status

`dstl8 graph` extracts a [code graph snapshot](/controltheory-documentation/dstl8-docs/code-graph.md) from a repo and pushes it to Dstl8. Extraction always runs locally; `build` never uploads anything, and `push` uploads only the metadata artifact.

```bash
dstl8 graph build --dry-run          # audit: print every byte that would be sent
dstl8 graph build -o graph.json      # write the artifact for inspection
dstl8 graph push                     # extract + upload (run from the repo root)
dstl8 graph push ~/src/checkout      # ... or point at a repo
dstl8 graph repos                    # repos with pushed graphs
dstl8 graph status github.com/acme/checkout
```

`push`, `repos`, and `status` need credentials: a logged-in profile (`dstl8 login`), or `DSTL8_API_TOKEN` + `DSTL8_API_URL` in headless environments. `build` works fully offline.

## `dstl8 graph build [path]`

Extracts the snapshot without uploading. `path` defaults to the current directory. Prints a human summary; the artifact itself goes wherever you point it:

* `--dry-run` — summary on **stderr**, the full artifact JSON on **stdout** (so it pipes cleanly into `jq`). Writes nothing.
* `-o graph.json` — write the artifact to a file.
* `--json` — summary on stderr, artifact JSON on stdout.
* none of the above — summary only, with a reminder that nothing was uploaded.

**Flags** (all of these are shared with `push`):

| Flag                  | Description                                                                                                                                                                                                  |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--repo`              | Repo identity override (`owner/name` or full remote URL; default: detected from git)                                                                                                                         |
| `--commit`            | Commit SHA override (full 40-char; default: git `HEAD`)                                                                                                                                                      |
| `--branch`            | Branch name override (identity fallback for gitless environments)                                                                                                                                            |
| `--default-branch`    | Default branch override (default: `origin/HEAD`, falling back to the current branch)                                                                                                                         |
| `--commit-time`       | Commit time override, epoch seconds (gitless environments; default: from git)                                                                                                                                |
| `--service name=glob` | Service mapping (repeatable; wins over [service detection](/controltheory-documentation/dstl8-docs/code-graph/configuration.md) for that name)                                                               |
| `--exclude glob`      | Exclude glob, gitignore syntax (repeatable; applied last — see [evaluation order](/controltheory-documentation/dstl8-docs/code-graph/configuration.md#excluding-files-dstl8ignore))                          |
| `--no-diff`           | Skip diff computation against the previous snapshot                                                                                                                                                          |
| `--include-tests`     | Index test sources too. They are excluded by default so a runtime pattern never resolves to a fixture — see [test sources](/controltheory-documentation/dstl8-docs/code-graph/configuration.md#test-sources) |
| `--no-symbols`        | Skip the deep graph (symbols, import/dependency edges, external deps)                                                                                                                                        |
| `--json`              | Print the artifact (`build`) or push result (`push`) as JSON                                                                                                                                                 |

**`build`-only flags:**

| Flag           | Description                                                 |
| -------------- | ----------------------------------------------------------- |
| `-o, --output` | Write the artifact JSON to a file                           |
| `--dry-run`    | Print summary + full artifact JSON without writing anything |

`--service` accepts repeated `name=glob` pairs; repeating a name merges its globs, and a bare name (no `=`) declares the service with no path scope:

```bash
dstl8 graph build --service checkout='cmd/checkout/**' \
                  --service checkout='payments/**' \
                  --service checkout-worker='cmd/worker/**'
```

## `dstl8 graph push [path]`

Builds the snapshot (or loads one with `--file`) and uploads it. Before uploading, the server's latest snapshot is checked:

* **Hash skip:** if the server already has a hash-equal snapshot collected less than 30 days ago, the upload is skipped entirely. An older identical snapshot *is* re-pushed on purpose, so the server refreshes it back into the retention window.
* **Diff baseline:** the server's latest snapshot is the baseline for the per-push diff. If the previous snapshot can't be fetched (aged out, network), the push degrades to a files-only diff and proceeds with a warning.
* **Branch gate:** only the repo's default branch is tracked. A push from any other branch prints the server's message as a skip (`Skipped: …`) and **exits 0** — a mis-wired PR trigger never fails a build.

After a *new* snapshot is stored, a `ci` platform event (`reason=codegraph.pushed`) is dropped on the [events timeline](/controltheory-documentation/dstl8-docs/events.md), deduplicated by commit SHA. Suppress it with `--no-event`.

**`push`-only flags** (plus all shared flags above):

| Flag                | Description                                                                        |
| ------------------- | ---------------------------------------------------------------------------------- |
| `--file graph.json` | Upload a previously built artifact instead of extracting (validated before upload) |
| `--no-event`        | Don't emit the `codegraph.pushed` platform event                                   |

Push output distinguishes the three server outcomes:

```
Pushed github.com/acme/checkout@9f2c1ab4e5d6 (main)         # new snapshot stored
Refreshed github.com/acme/checkout@9f2c1ab4e5d6 (unchanged graph, retention window renewed)
Server already has github.com/acme/checkout@9f2c1ab4e5d6 (unchanged graph)
```

With `--json`, the push result (created/refreshed flags, repo, commit, branch) prints as one JSON object for scripts.

## `dstl8 graph repos`

Lists every repo in your org with a pushed code graph: branch, file and log-site counts, latest commit, and collection time. `--json` prints one JSON object per repo (NDJSON).

## `dstl8 graph status <repo>`

Shows the latest snapshot for one repo — services (with how each was detected), latest commit, graph hash, counts, and extractor version. The repo key is the normalized remote, e.g. `github.com/acme/checkout`. `--json` for machine output.

## Exit codes

| Situation                                                                   | Behavior                                                                            |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Clean run                                                                   | Exit 0                                                                              |
| Parse errors in individual files                                            | **Warnings, exit 0** — files stay in the inventory, counted in `stats.parse_errors` |
| Push from a non-default branch                                              | Prints the server's `Skipped:` message, **exit 0**                                  |
| Server already has the graph (hash skip)                                    | Prints the skip reason, exit 0                                                      |
| Total failure — unresolvable repo identity, zero files, auth/network errors | Exit 1                                                                              |

## Examples

### Local audit before adopting

```bash
dstl8 graph build --dry-run | jq '.log_sites | length'
dstl8 graph build --dry-run | jq '.files[].path' | head
```

### Write the artifact for security review, push the reviewed bytes

```bash
dstl8 graph build -o graph.json
# ... review graph.json ...
dstl8 graph push --file graph.json
```

### Headless CI push

```bash
export DSTL8_API_TOKEN="dstl8_…"                 # from your secrets store
export DSTL8_API_URL="https://acme.app.dstl8.ai"
dstl8 graph push --json
```

No profile, no browser login, no `~/.config/dstl8` — the environment pair alone authenticates. Setting only one of the two is an error. See [CI integration](/controltheory-documentation/dstl8-docs/code-graph/ci.md) for full pipeline recipes.

### Monorepo with explicit service globs

```bash
dstl8 graph push \
  --service checkout='services/checkout/**' \
  --service billing='services/billing/**' \
  --service shared-web='web/**'
```

A `--service` declaration wins over any detected mapping with the same name (it carries the same trust tier as an explicit `.dstl8.yaml` entry); detected services with other names are kept. Without the flag, services come from `.dstl8.yaml`, helm/k8s manifests, or docker-compose — see [Configuration](/controltheory-documentation/dstl8-docs/code-graph/configuration.md).

### Gitless environment (exported tarball, no `.git`)

```bash
dstl8 graph push /srv/src/checkout \
  --repo acme/checkout \
  --commit 9f2c1ab4e5d6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 \
  --commit-time 1765731200 \
  --branch main --default-branch main
```

Normally all five values are detected from git; the flags exist for environments where git isn't available. Without git, the walk also can't use `git ls-files`, so `.gitignore` is not applied — rely on [`.dstl8ignore`](/controltheory-documentation/dstl8-docs/code-graph/configuration.md) and `--exclude` there.

### Leaner artifacts

```bash
dstl8 graph push --no-symbols      # log sites only: skip symbols, import edges, external deps
dstl8 graph push --no-diff         # skip the diff against the previous snapshot
```

`--no-symbols` still gives you pattern→source resolution and deploy diffs of log statements; it disables symbol search, code impact, and dependency answers for this repo. `--no-diff` disables per-deploy change sets — Dstl8 never diffs server-side.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.controltheory.com/controltheory-documentation/dstl8-docs/code-graph/cli.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
