What Carrick covers
What Carrick scans, the requirements a repo needs to scan cleanly, the framework and protocol story, and the cases that fall outside MVP scope.
Carrick statically scans TypeScript services to extract operations, outbound client calls, and request/response type definitions. It maintains an index of cross-service interfaces that powers diagnostics in your editor, your AI coding agent, and your pull requests.
Supported protocols
Carrick indexes operations and communication patterns across four primary protocols:
REST and HTTP
Carrick extracts route handlers on the producer side and matching client calls (such as fetch, axios, got, and ky) on the consumer side. It pairs producers with consumers based on HTTP method and path patterns, resolving complete TypeScript request and response types for both sides.
GraphQL
Carrick parses Schema Definition Language (SDL) schemas (.graphql, .gql, and gql/graphql tagged template literals) to identify producer fields, and scans executable documents (queries and mutations in .graphql files or tagged templates) to identify consumer operations. Extraction uses a deterministic parser rather than model inference.
Code-first schemas, persisted query manifests, and Relay compiled artefacts are supported when a generated schema.graphql is committed to the repository.
WebSockets
Carrick indexes bidirectional realtime events by event name and direction:
- Producers: Event listeners such as
socket.on("event_name", ...). - Consumers: Event emitters such as
socket.emit("event_name", ...).
While Socket.IO is the most widely tested client, Carrick supports any realtime library using standard on/emit call shapes. Event names must be string literals. Dynamic event names, custom namespaces (io.of(...)), and reserved lifecycle events (connect, disconnect) are excluded from contract tracking.
Pub/sub
Carrick extracts topic-based messaging operations across message brokers including Kafka, NATS, Redis pub/sub, and BullMQ:
- Subscribers: Handlers registered for a specific topic act as producers.
- Publishers: Client calls sending messages to a topic act as consumers.
Operations match on literal topic strings. When a topic payload is decoded using a declared TypeScript type, Carrick extracts and compares the payload shape.
Framework support
Carrick detects REST frameworks by analyzing imported symbols and call shapes rather than relying strictly on package manifest names. It supports major Node and Deno web frameworks:
- Express: Comprehensive producer and consumer extraction across Express 4 and Express 5, including path parameters, query parameters, request bodies, and response types.
- Koa, Fastify, Hapi, and NestJS: Supported with dedicated end-to-end test fixtures validating route extraction and contract matching.
- Hono: Supported across standard routing patterns.
- Custom routers: In-house routers following Express-style routing conventions (
app.get,router.use, route decorators) are extracted automatically.
Repository requirements
Repositories must meet the following criteria to scan cleanly:
TypeScript source
Carrick relies on TypeScript compiler APIs to resolve request, response, and payload types. While JavaScript repositories can produce endpoint route maps, their parameter and payload types resolve to unknown.
Project manifest
Node projects must define a package.json. Deno projects must define a deno.json or deno.jsonc and require Deno 2.9.4 or newer on PATH, which the GitHub Action configures automatically.
During scans, Carrick prepares dependencies using the project’s lockfile (npm, pnpm, Yarn, Bun, or deno install --frozen --node-modules-dir=none) with lifecycle scripts disabled. You can disable this step by setting install-dependencies: false in the scan configuration.
Statically discoverable routes
Routes must be defined as string literals or resolvable expressions in source code. Routes constructed dynamically at runtime from databases, external configuration files, or arbitrary runtime loops cannot be discovered statically.
Configuration and initial scan
Each repository requires a carrick.json at its root defining service boundaries and classifying environment variables. The initial index is compiled by running carrick index locally, after which the Carrick GitHub Action updates the index automatically on default-branch pushes.
Monorepos
Carrick natively supports both single-service repositories and multi-service monorepos:
- Workspace monorepos: Monorepos managed with npm, pnpm, Yarn, or Deno workspaces are split into distinct services automatically based on workspace package manifests.
- Single-package monorepos: Repositories containing multiple services under a single root
package.jsondefine aservicesarray incarrick.json. Carrick scans, type-checks, and indexes each service independently, evaluating contracts between services within the same repository.
Limitations and unsupported patterns
The following patterns fall outside the scope of static analysis:
Non-TypeScript languages
Carrick does not scan Python, Go, Rust, Java, or Ruby services. In polyglot environments, Carrick indexes the TypeScript services while non-TypeScript services remain unindexed.
Deno runtime scope limits
Carrick resolves modules using Deno’s standard module graph (deno.window and deno.ns scopes). Worker scopes, arbitrary runtime library combinations, and ambient Node types omitted by deno types require explicit declarations.
Binary and RPC protocols
gRPC, tRPC over WebSockets, and custom binary RPC protocols are not indexed.
Advanced broker queue topologies
While topic names in message queues like BullMQ are indexed for pub/sub matching, broker-specific operational semantics (such as consumer groups, delayed job retries, exchange bindings, and dead-letter queues) are not modelled.
Dynamic runtime routing
Routes registered through dynamic runtime execution cannot be indexed:
- Routes evaluated from remote feature flags or database queries at startup
- Routes registered in dynamic loops with non-literal string concatenation
- Plugin architectures that register handlers after application bootstrap
Pre-compiled and generated code
Carrick scans original TypeScript source files. It does not scan .d.ts-only packages without source, pre-compiled bundles, or build output in .gitignore unless generated source files are checked into version control.
Related
- Introduction outlines Carrick’s three core surfaces and indexing model.
- carrick.json explains service configuration, monorepos, and environment variable classification.