Technologies Used in the Development of CommonGrants: A Deep Dive into the Simpler Grants Protocol Stack

CommonGrants is built on a TypeSpec-first architecture using pnpm workspaces, TypeScript and Python SDKs with Zod and Pydantic validation, an Astro/React documentation site, and GitHub Actions with Changesets for automated releases.

The hhs/simpler-grants-protocol repository implements CommonGrants as a modern, multi-language ecosystem. The technologies used in the development of CommonGrants reflect an API-first approach, leveraging declarative specification tools and polyglot SDK generation to ensure type safety across TypeScript and Python implementations.

Core API Definition and Versioning Technologies

TypeSpec for API-First Design

At the heart of the stack lies TypeSpec (formerly Cadl), a declarative language for defining APIs that generates OpenAPI specifications, JSON-Schema, and client libraries. In lib/core/lib/main.tsp, the CommonGrants API is defined as a versioned namespace that imports core models from core/index.tsp and api.tsp. This single source of truth ensures that TypeScript and Python SDKs, along with documentation, remain synchronized as the API evolves.

The TypeSpec compiler (tsp CLI) processes these definitions through scripts defined in the workspace configuration, outputting artifacts to tsp-output/@typespec/openapi3/ for downstream consumption by the documentation site and client generators.

Semantic Versioning with @typespec/versioning

The protocol implements semantic versioning via the @typespec/versioning library. The main.tsp file decorates the CommonGrants namespace with three distinct versions (v0_1, v0_2, v0_3), allowing SDK clients to pin to specific API versions while the specification evolves. This ensures backward compatibility and predictable deprecation cycles across the TypeScript and Python implementations.

SDK Development Technologies

TypeScript SDK Stack

The TypeScript SDK (lib/ts-sdk/) provides an idiomatic client for Node.js and browser environments. Key technologies include:

  • Zod: Runtime schema validation for request/response data, ensuring type safety beyond compile-time checks.
  • Ajv + ajv-formats: JSON-Schema validation for generated models, providing an alternative validation path.
  • Native fetch API: Core HTTP transport implemented in lib/ts-sdk/src/client/client.ts, handling timeouts, retries, and automatic pagination via the fetchMany method.

The Client class in lib/ts-sdk/src/client/client.ts abstracts HTTP requests, automatically appending authentication headers via Auth helpers and implementing fetchMany for auto-pagination across large result sets.

import { Client, Auth } from "@common-grants/sdk";

const client = new Client({
  baseUrl: process.env.CG_BASE_URL ?? "http://localhost:8000",
  auth: Auth.apiKey(process.env.CG_API_KEY ?? "<your-api-key>"),
  timeout: 5000,
  pageSize: 10,
});

async function listAll() {
  // `fetchMany` handles pagination automatically.
  const result = await client.fetchMany("/common-grants/opportunities", {
    maxItems: 50,
    schema: client.opportunities.opportunitySchema, // optional Zod validation
  });

  console.log(`Fetched ${result.items.length} opportunities`);
  result.items.forEach(o => console.log(o.title));
}
listAll();

Python SDK Stack

The Python SDK (lib/python-sdk/) mirrors the TypeScript implementation using Python 3.11+ and modern async patterns:

  • Pydantic v2: Typed data models with validation and (de)serialization, generated from the same TypeSpec source as the TypeScript SDK.
  • marshmallow: Alternate schema library used in some generated models for flexibility.
  • httpx: Async-compatible HTTP client used by the Python Client class in common_grants_sdk/client/client.py, supporting both synchronous and asynchronous request patterns.
import os
from common_grants_sdk.client import Client, Auth

client = Client(
    base_url=os.getenv("CG_BASE_URL", "http://localhost:8000"),
    auth=Auth.api_key(os.getenv("CG_API_KEY", "<your-api-key>")),
)

opp = client.opportunities.get("opp-123")
print(opp.title)   # Pydantic model with type‑checked fields

Developer Tooling and Monorepo Management

pnpm Workspaces

The repository uses pnpm workspaces to manage multiple packages (core, cli, ts-sdk, python-sdk, website) under a single lockfile. This enables fast, disk-space-efficient installs and consistent dependency management across the TypeScript portions of the codebase. The workspace configuration is defined in pnpm-workspace.yaml and the root package.json.

CLI and Build Tools

The CLI package (lib/cli/) provides developer tooling built with Node.js and TypeScript. It exposes commands to run TypeSpec compilation, generate OpenAPI specifications, and manage package publishing. This tool abstracts the tsp compiler invocations, providing a unified interface for code generation tasks across the monorepo.

Build quality is enforced through ESLint, Prettier, Vitest (for unit testing), cspell (for spell checking), and the tsp CLI for TypeSpec compilation. These tools are configured as devDependencies across the various package.json files in the workspace.

Documentation Website Architecture

Astro and React Foundation

The documentation site (website/) is built with Astro v5, a static-site generator optimized for content-driven sites. Astro handles the build process, producing optimized static assets while allowing selective hydration of interactive components. It incorporates React v18 via @astrojs/react to render dynamic UI elements.

Interactive API Components

The documentation site features several specialized libraries for API exploration:

  • JSONForms: Renders JSON-Schema-driven forms for custom fields and the API Playground, allowing users to interact with data models directly.
  • Swagger-UI-React: Embeds live API exploration interfaces, rendering the generated OpenAPI specifications for interactive testing.
  • OpenAPI-Sampler: Generates example request/response bodies for the API documentation, providing concrete data samples alongside schema definitions.

The website runs scripts that compile TypeSpec to OpenAPI and serve it through Swagger UI, as defined in website/package.json:

{
  "scripts": {
    "typespec:openapi": "tsp compile src/specs/main.tsp && cp tsp-output/@typespec/openapi3/** public/openapi"
  }
}

CI/CD and Release Automation

GitHub Actions Pipelines

Continuous integration and deployment are handled via GitHub Actions, with workflow definitions in .github/workflows/*.yml. These pipelines automate testing (Vitest for TypeScript, pytest for Python), linting (ESLint, Prettier), TypeSpec compilation, and deployment previews for the documentation site. Specific workflows like ci-lib-ts-sdk.yml target individual packages for targeted testing.

Changesets for Version Management

Changesets manages changelog generation and version bumping across the pnpm workspaces. Configuration in .changeset/config.json ensures consistent semantic versioning across all packages (core, cli, ts-sdk, etc.), automating the release process and maintaining accurate release notes without manual version synchronization.

Summary

  • TypeSpec serves as the single source of truth for API definitions in lib/core/lib/main.tsp, generating OpenAPI and JSON-Schema artifacts used across all consumers.
  • pnpm workspaces unify the monorepo structure, while Node.js and Python 3.11+ power the respective SDK implementations.
  • TypeScript SDK leverages Zod, Ajv, and native fetch for runtime validation and HTTP transport in lib/ts-sdk/src/client/client.ts.
  • Python SDK utilizes Pydantic v2, marshmallow, and httpx for type-safe async operations in common_grants_sdk/client/client.py.
  • Astro and React drive the documentation site, enhanced with JSONForms and Swagger UI for interactive API exploration.
  • GitHub Actions and Changesets automate testing, publishing, and version management across the entire ecosystem.

Frequently Asked Questions

What is TypeSpec and why does CommonGrants use it?

TypeSpec is a declarative language for defining APIs that generates OpenAPI specifications, JSON-Schema, and client libraries from a single source of truth. CommonGrants uses TypeSpec in lib/core/lib/main.tsp to ensure that TypeScript and Python SDKs, along with documentation, remain synchronized and type-safe as the API evolves through semantic versions.

How does CommonGrants handle API versioning?

The protocol implements semantic versioning via the @typespec/versioning library, defining three distinct versions (v0_1, v0_2, v0_3) in the main.tsp namespace. This allows SDK clients to pin to specific API versions while the specification evolves, ensuring backward compatibility and predictable deprecation cycles across the TypeScript and Python implementations.

What validation libraries are used in the CommonGrants SDKs?

The TypeScript SDK uses Zod for runtime schema validation and Ajv with ajv-formats for JSON-Schema validation, ensuring type safety beyond compile-time checks. The Python SDK leverages Pydantic v2 for typed data models and validation, with marshmallow used as an alternate schema library in some generated models, providing comprehensive data integrity across both language implementations.

How is the CommonGrants documentation website built?

The documentation site utilizes Astro v5 as the static-site generator, providing optimized static asset builds with selective hydration of interactive components. It incorporates React v18 via @astrojs/react to render JSONForms for schema-driven forms, Swagger-UI-React for live API exploration, and OpenAPI-Sampler for generating example request/response bodies, creating a comprehensive interactive documentation experience.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →