syncanix
v0.1.0
Published
Syncanix CLI — scans your codebase, builds the API capability catalog, and uploads it to Syncanix cloud.
Readme
syncanix — Syncanix Command-Line Interface
The Syncanix CLI scans your codebase, builds the API capability catalog, and uploads it to Syncanix cloud. It's the entry point every customer runs in their backend repository to onboard.
syncanix init outputs
Alongside .syncanix/catalog.json, init also writes two shareable artifacts:
.syncanix/capability-map.html— a self-contained interactive graph of everything the scan found (open it in any browser, works offline). Skip with--no-map..syncanix/badge.json— a shields.io endpoint-badge JSON with your AI-ready capability count. Commit it, then add the printed snippet to your README to get a live badge:The snippet
initprints already carries your repo slug (derived from theoriginremote). The badge updates whenever a new scan is committed. If your default branch isn'tmain, adjust the URL.
syncanix drift — CI drift comments
syncanix drift re-scans the working tree (structural only — no LLM, no
network) and diffs the interface shape against the committed
.syncanix/catalog.json: added/removed capabilities and changed
method/path/params/body, with breaking changes called out. Enrichment fields
(descriptions, risk labels) and source line numbers are ignored, so only real
API drift registers.
--format text|markdown—markdownis PR-comment-ready and starts with the stable<!-- syncanix-drift -->marker so a workflow can update one comment instead of stacking new ones.--out <path>— write the report to a file.- Exit codes:
0no drift ·1drift detected ·64usage error (no committed catalog / no framework detected). --graphql-endpointintrospection typing is reconciled automatically: a committed introspection-typed GraphQL operation does not register as drift just because CI has no running server to introspect.
Copy-paste workflow — posts (or updates) one PR comment using only
GITHUB_TOKEN:
# .github/workflows/syncanix-drift.yml
name: Syncanix drift
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- name: Detect capability drift
run: npx syncanix drift --format markdown --out drift.md || true
- name: Upsert the PR comment
if: ${{ hashFiles('drift.md') != '' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
marker='<!-- syncanix-drift -->'
comment_id=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" --jq ".[] | select(.body | startswith(\"$marker\")) | .id" | head -n1)
if [ -n "$comment_id" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/$comment_id" -F [email protected]
else
gh api -X POST "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" -F [email protected]
fiThe || true keeps the job green so the comment always posts; drop it (and
if: on the step instead) to make drift fail the check.
Install
npx syncanix <command>
# or, after `syncanix login`:
syncanix <command>Node ≥ 20 is required.
Commands
| Command | What it does |
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
| syncanix init | Discover API endpoints in the current directory, enrich them (optional), upload to Syncanix cloud. |
| syncanix drift | Diff the working tree's capabilities against the committed catalog — exit 1 on drift (CI-friendly). |
| syncanix dev | Boot a local agent + catalog + widget harness against your dev backend (live-reloads on catalog change). |
| syncanix login | Interactively authenticate; writes your API key to ~/.syncanix/credentials (mode 0600). |
| syncanix logout | Remove ~/.syncanix/credentials. Idempotent. |
| syncanix doctor | Run diagnostic checks for common setup issues (Node version, framework detection, config validity, API key). |
| syncanix version | Print the long-form version: CLI version + Node version + commit SHA. |
| syncanix --help | Top-level help and subcommand list. |
Exit codes
| Code | Meaning | | ---: | -------------------------------------------------------- | | 0 | OK | | 1 | System error (network, FS, dependency unavailable) | | 64 | Usage error (invalid flag, unknown command, missing arg) |
Configuration
Two optional files in your repo root control what Syncanix scans:
| File | Purpose |
| ----------------- | ----------------------------------------------------------------------------------------- |
| .syncanixignore | Gitignore-style file-level exclusions, layered on the built-in defaults + .gitignore. |
| .syncanix.yaml | Per-capability rules (rename / description / internal / skip / priority) + scope renames. |
Generate starter files with:
syncanix init --init-configBoth files are commit-safe (no secrets). See
packages/cli/src/config/README.md for the full schema.
Local dev mode (syncanix dev)
syncanix dev boots a tiny loopback HTTP server that lets you exercise your
agent + catalog + widget end-to-end against your local dev backend before you
ship the embed to production:
syncanix dev # serves on http://127.0.0.1:4321 against http://localhost:3001
syncanix dev --port 4400 --backend http://localhost:3002The harness page:
- lists the capabilities from your local
.syncanix/catalog.jsonso you can confirm what the agent will reason over, - embeds the Syncanix widget (
data-env="development") pointed at your dev API origin, so the live agent runs against your backend, - live-reloads when the catalog changes — re-run
syncanix initin another terminal and any open page reloads automatically.
It serves / (harness page), /catalog.json (the discovered catalog), and
/healthz (used for live-reload change detection). The server binds loopback
only (127.0.0.1); it is a dev tool, not a public surface.
| Flag / env | Default | Purpose |
| ------------------------------------------ | ---------------------------- | ----------------------------------------- |
| -p, --port / SYNCANIX_DEV_PORT | 4321 | Harness server port. |
| -b, --backend / SYNCANIX_DEV_BACKEND | http://localhost:3001 | Dev Syncanix API origin the widget calls. |
| --widget-src / SYNCANIX_DEV_WIDGET_SRC | cdn.syncanix.com/widget.js | Widget bootstrap script URL. |
| -k, --key / SYNCANIX_DEV_KEY | a local pk_test_… key | Publishable key wired into the embed. |
| -c, --catalog | ./.syncanix/catalog.json | Catalog JSON to serve + watch. |
Missing catalog → exit 1 with a "run syncanix init first" hint.
API key resolution
syncanix resolves the API key from the first available source:
--api-key=<value>CLI flag (mostly for CI).SYNCANIX_API_KEYenvironment variable.~/.syncanix/credentials(written bysyncanix login).
API keys are issued by your workspace administrator in the dashboard
(Phase 2). Format: gak_<env>_<random> where <env> is dev, prod,
or test. Per-environment scoping is enforced server-side.
Enrichment modes
syncanix init runs LLM enrichment by default (local-keys mode — it uses the
ANTHROPIC_API_KEY + OPENAI_API_KEY in your local environment, ZDR-enforced;
enrichment runs from your machine, there is no Syncanix-hosted enrichment
service). Alternatives:
--mode=byok— bring your own single Anthropic or OpenAI key; the handler text goes directly from your machine to your provider; Syncanix cloud never sees it.--mode=skip— ship the catalog with extractor-only metadata. Enrich later from the dashboard.
(The mode was previously called managed; the old name is still accepted in
committed .syncanix.yaml / .syncanix/consent.json files and normalized to
local-keys.)
See packages/cli/src/enrich/README.md and ADR-0015 for the full trust
contract.
Quality gate
The discovery extractors are gated by F1 thresholds locked from the pass-10 spec:
| Framework | F1 threshold | | --------- | ------------ | | NestJS | 0.92 | | Express | 0.85 | | FastAPI | 0.92 | | Next.js | 0.92 | | GraphQL | 1.00 |
Run the benchmark locally:
pnpm --filter syncanix test:f1CI runs this on every PR. Any change that regresses below threshold blocks merge.
Subsystem docs
src/detect/— framework detection.src/extractors/— per-framework Capability extraction.src/config/—.syncanixignore+.syncanix.yamlparsers.src/enrich/— LLM enrichment (local-keys / BYOK / skip).src/output/— write.syncanix/catalog.json+ upload to the API.src/eval/— F1 benchmark against hand-labelled fixtures.src/ui/— progress bar, error renderer, doctor.
Related
plan/phase-1-discovery-cli/— pass specs.docs/decisions/0015-llm-enrichment-zdr-consent.md— ZDR contract.docs/runbooks/env-vars.md— env-var canonical table.
