xray

xray is a read-only extractor that produces a portable engineering-metrics artifact from a client's git, GitHub, CI, and error-tracker systems.
- Captures: commits, PRs, reviews, CI runs, deploys, incidents — structural data and declared configuration / tooling manifests, never application logic.
- Produces: a single
.tar.gz (SQLite + JSON manifest) — verifiable SHA256, no secrets.
- Touches: GitHub, GitHub Actions, CircleCI, Sentry, Bugsnag, Honeycomb — read-only, even when tokens hold write scope.
- Doesn't do: application-logic capture, per-individual rankings, daemon mode, scheduled runs.
[!IMPORTANT]
xray runs inside a customer environment against the customer's own
credentials. The artifact contains no source code and no secrets.
Security review: docs/security.md ·
docs/threat-model.md. Vulnerability
disclosure: SECURITY.md.
Design
xray is engineered against five non-negotiable constraints. The Trust documents below show how the implementation upholds each.
- Independent. Runs buyer-side under the customer's operator and credentials. No vendor telemetry, no sales channel, no daemon mode.
- System-level over time. Team-level and system-level granularity, enforced in the schema. No per-individual rollups anywhere.
- Hypothesis-anchored. The window and connector set are chosen against a stated question;
extraction_provenance records what was asked of every endpoint.
- Brackets the AI-adoption inflection.
harness_artifacts.first_seen_at records when each AI-tool config file (CLAUDE.md, .cursor/rules, .github/copilot-instructions.md) first appeared in repo history. Flow metrics join against the inflection inside one extract.
- Source-free. Reads declared configuration and tooling manifests; never application logic.
Trust
xray is intended to be run inside the customer's environment by the
customer's own operator, against the customer's own credentials, and the
artifact it produces is meant to survive a security review. The four
documents below describe what the binary does, what it cannot do, and
what a representative run actually looks like.
docs/security.md — what is captured, what is
not, and the guarantees the binary makes (read-only, no application
logic, no secrets in the artifact, team-level only, logs).
docs/threat-model.md — one-page trust
boundaries, attack surface, malicious-binary and leaked-artifact
analysis.
docs/sample-manifest.json — a real
manifest.json from a clean single-repo run against
goreleaser/chglog, the same target /ready uses for smoke. Real
row counts, real extraction_provenance block. Failure-mode
endpoint states are documented in
docs/security.md
rather than reproduced here.
docs/sample-run.log — the matching .log
file demonstrating no tokens, per-phase logs, and the post-run
artifact summary.
docs/operator-setup.md — operator-side
setup walkthrough: install, probe, configure, validate, and run.
docs/engagement-guide.md — the
consultant-side counterpart: what happens to the artifact after
you send it. Public so the methodology stays auditable.
Install
macOS
brew tap kmcd/xray https://github.com/kmcd/xray
brew install kmcd/xray/xray
Linux
curl -sSfL https://raw.githubusercontent.com/kmcd/xray/main/scripts/install.sh | sh
The script detects OS and architecture, downloads the latest release
archive, verifies its sha256 against checksums.txt, and installs to
/usr/local/bin/xray. Set XRAY_INSTALL_DIR=$HOME/.local/bin to install
without sudo — make sure that directory is on your PATH. Set
XRAY_VERIFY_COSIGN=1 to additionally verify the cosign signature
(requires cosign on PATH).
Windows
scoop bucket add xray https://github.com/kmcd/xray
scoop install xray
Manual download
Pick the archive for your platform from
the releases page and
extract xray onto your PATH. For air-gapped or security-team
installs, verify the cosign signature first — see
Verifying the binary. For corporate proxy,
custom CA, and firewall configuration, see
docs/enterprise.md.
Go developers
go install github.com/kmcd/xray/cmd/xray@latest
Prerequisites
xray shells out to the system git binary for repository clones over
HTTPS. Make sure git has credentials for github.com before running
xray check or xray run. If gh is installed, the one-liner is:
gh auth setup-git
Otherwise, configure a credential helper (git credential-osxkeychain,
git-credential-manager, or an embedded PAT in ~/.git-credentials).
xray check reports a fix hint when this step is missing.
Usage
The default flow: configure → validate → run → export.
Set tokens for each connector, then run xray init --probe to discover live
connector state and generate a pre-populated config:
export GITHUB_TOKEN="ghp_..." # required
export CIRCLECI_TOKEN="..." # optional
export BUGSNAG_AUTH_TOKEN="..." # optional
export HONEYCOMB_API_KEY="..." # optional (or HC_API_KEY)
xray init --from-org my-org --probe
To scaffold from repo names only (no connector discovery), set
GITHUB_TOKEN first (the API call to list repos still requires it):
export GITHUB_TOKEN="ghp_..."
xray init --from-org my-org
Hand-edit the generated xray.toml: verify the window, paste any connector
tokens not already set as env vars, and split repos into teams. See
docs/operator-setup.md for the full walkthrough,
PAT scope requirements, and per-connector examples. The config stays on the
operator's machine — never committed to git, never shared back to the
consultant.
2. Validate and check
# Syntactic + schema check, offline. Defaults to ./xray.toml; pass an
# explicit path to point at a different config.
xray validate
# Live preflight against configured connectors (auth, rate limits, scope).
xray check
3. Run
# Full extraction. Produces ./xray-export-<UTC-timestamp>.tar.gz with a
# sibling .log file mirroring stderr (suppress with --no-run-log). See
# the sample-run block below the code for live TTY output.
xray run
# Machine-readable output. One NDJSON event per progress tick, terminated
# by a {"kind":"run_summary",...} object on stdout. See docs/spec.md.
xray run --output json | jq .
# Quiet success: only the artifact path is written to stdout.
xray run --output quiet
Sample run (live TTY output)
On a TTY, the default (--output auto) renders a live (repo × connector) status grid:
xray run · elapsed 04:12 · ETA 14:47 ±2m · 3/4 workers
repo clone github gh_actions sentry
kmcd/foo ✔ done ✔ 4213 rows ● gh_actions ✔ 312 rows
kmcd/bar ✔ done ● prs ▢ pending 🔒 inaccessible
kmcd/baz ● clone ▢ pending ▢ pending ▢ pending
Non-TTY (CI, pipe to file) falls back to a stderr log with one line per phase boundary; force the log explicitly with --output log.
On a long run (1+ hour), rate-limit waits appear as rate limited, waiting Ns, primary limit low, waiting Ns, or adaptive pacing, waiting Ns lines — these are normal and the run resumes automatically. Run under tmux or screen to keep the process alive if you close your terminal.
Exit codes: 0 clean, 1 config / pre-flight error, 2 partial run
(artifact produced, connector error recorded in manifest), 3 fatal.
See docs/spec.md → xray run → "Exit codes".
4. Inspect (optional)
Before sending the artifact, verify it is structurally intact:
xray inspect xray-export-<UTC-timestamp>.tar.gz
This runs five checks: end-to-end tar/gzip CRC, manifest shape, SQLite
integrity, row-count reconciliation, and schema-version compatibility. All
five must pass before the artifact is accepted by the analyser.
PASS tar_integrity 2 members, 48.3 MB read
PASS manifest_shape tool_version=0.4.8 schema_version=2 run_id=...
PASS sqlite_integrity
PASS row_counts 12 tables reconciled
PASS schema_version schema_version=2 (xray 0.3.0, 0.4.0, ...)
PASS
For machine-readable output: xray inspect <artifact> --json.
Exit codes: 0 all checks pass, 1 one or more failed, 2 usage error.
Full check descriptions: docs/spec.md → xray inspect.
5. Export
The run produces two files in the working directory:
xray-export-<UTC-timestamp>.tar.gz — the artifact (SQLite + JSON manifest)
xray-export-<UTC-timestamp>.log — the run log (mirrors stderr)
Inspect manifest.json inside the archive before sending — it lists every
connector's status, row counts, and per-endpoint errors. No source content,
no secrets. Sample: docs/sample-manifest.json.
Send the consultant the .tar.gz, the .log, and the output of xray version.
Do not send the config file — it contains your token.
Common handover channels are Slack DM, a download link your consultant
provides, or a private file share. The artifact is typically 10–200 MiB for a
multi-repo engagement.
The full configuration reference and behaviour spec live in docs/spec.md. The output schema is documented in docs/schema.md. Agent-facing constraints (invariants, non-goals, schema-versioning rules) live in CLAUDE.md.
Compatibility
Pre-1.0, the schema is unstable; minor version bumps may introduce breaking schema changes. The analyser refuses to load artifacts at an unknown schema_version. Per-release changes that affect downstream consumers are tracked in CHANGELOG.md.
| xray version |
schema_version |
| 0.1.0 |
1 |
| 0.2.0 |
1 |
| 0.2.1 |
1 |
| 0.2.2 |
1 |
| 0.3.0 |
2 |
| 0.4.0 |
2 |
| 0.4.1 |
2 |
| 0.4.2 |
2 |
| 0.4.3 |
2 |
| 0.4.4 |
2 |
| 0.4.5 |
2 |
| 0.4.6 |
2 |
| 0.4.7 |
2 |
| 0.4.8 |
2 |
| 0.4.9 |
2 |
0.3.0 is the first release at schema_version = 2. Analysers pinned to schema_version = 1 will refuse to load 0.3.0+ artifacts — see the CHANGELOG for the author-handle semantics shift driving the bump.
Verifying the binary
Verify the cosign signature on checksums.txt, then verify the archive
against the checksum.
VERSION=0.4.9
OS=linux # or darwin, windows
ARCH=amd64 # or arm64 (not available on windows)
base=https://github.com/kmcd/xray/releases/download/v${VERSION}
curl -LO ${base}/xray_${VERSION}_${OS}_${ARCH}.tar.gz
curl -LO ${base}/checksums.txt
curl -LO ${base}/checksums.txt.sig
curl -LO ${base}/checksums.txt.pem
cosign verify-blob \
--certificate-identity-regexp 'https://github.com/kmcd/xray/.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate checksums.txt.pem \
--signature checksums.txt.sig \
checksums.txt
sha256sum -c --ignore-missing checksums.txt
tar -xzf xray_${VERSION}_${OS}_${ARCH}.tar.gz
sudo mv xray /usr/local/bin/
Verifying provenance
Each release ships a single SLSA L3 build provenance attestation
(xray.intoto.jsonl) generated by the
SLSA GitHub generator.
The file lists every release artifact as a subject (binaries, archives, SBOMs)
so one download verifies any platform you pick. Each archive also ships an
SPDX-JSON SBOM (*.spdx.json). Verify the attestation with
slsa-verifier:
curl -LO ${base}/xray.intoto.jsonl
slsa-verifier verify-artifact \
--provenance-path xray.intoto.jsonl \
--source-uri github.com/kmcd/xray \
--source-tag "v${VERSION}" \
"xray_${VERSION}_${OS}_${ARCH}.tar.gz"
Security
Report vulnerabilities privately — see SECURITY.md.
License
Apache-2.0. See LICENSE.
xray is a read-only extraction tool. It never writes to any remote system and
never stores credentials or source content in the output artifact.
FAQ
Where do I run this?
On your laptop. xray is a ~30 MiB static binary; it clones repos to a temp
directory, writes a SQLite file, and packages it into a .tar.gz. No install,
no daemon, no system dependencies. macOS, Linux, and Windows are supported.
Keep ~5 GiB of disk free for the temp clones (varies with repo
sizes). To run on a server instead, copy the binary, config, and token env var
— nothing else is needed.
Can I run this against repositories with sensitive history?
Yes. xray reads git metadata — SHAs, timestamps, author handles, file paths, numstat — plus declared configuration and tooling manifests (workflow YAML, dependency manifests, AI-harness config files). It never reads application logic. No diff text, no commit bodies, no application source is read or stored. See the full capture inventory in docs/security.md.
What if a provider returns 403 on a required endpoint?
The endpoint records accessible: false with the reason and emits no rows. The analyser treats absence as unknown, not no signal — a critical distinction for analyses that depend on data presence. The run continues. See docs/security.md.
What happens if I revoke the token mid-run?
The next API call returns 401. The connector records accessible: false on that endpoint and continues; subsequent calls are recorded identically. The run completes with exit code 2 (partial — artifact produced, errors in manifest). See docs/security.md.
How do I verify the artifact has no secrets in it before sending?
Unpack the .tar.gz. manifest.json contains row counts, endpoint status, and provenance metadata — no credentials. A real example is at docs/sample-manifest.json.
What is in manifest.json vs. the SQLite database?
manifest.json is the run summary: schema version, extraction window, connector versions, per-endpoint access status, row counts, and errors. The SQLite DB is the metrics: commits, PRs, reviews, CI builds, error rates, observability signals. Full schema: docs/schema.md.
Does the tool need network access from inside my VPC?
Outbound HTTPS to configured providers (GitHub, Sentry, etc.) and to github.com for repo cloning. No inbound ports, no callbacks. Egress-only. See docs/spec.md for the full connector list.
Can I keep the temp clones for inspection?
Pass --keep-clones to skip cleanup; clone paths are logged to stderr and recorded in the .log file. By default, clones are deleted after each repo finishes. See docs/spec.md → xray run → flags.
Why does xray run finish in under a second for Honeycomb on repeat runs?
The Honeycomb markers API returns the full marker history on every call with no server-side date filter. After the first run, xray caches the response under $UserCacheDir/xray/honeycomb/ (macOS: ~/Library/Caches/xray/honeycomb/; Linux: ~/.cache/xray/honeycomb/) with a 24-hour TTL. Pass --no-cache to force a full re-fetch.
Why a static binary instead of a script or container?
A single static binary has one thing to verify: one file, one SHA256, one cosign signature. No runtime dependencies to audit — no pip, no npm, no base image. See docs/threat-model.md.
Build from source
See CONTRIBUTING.md.