Skip to content

About

Production-ready TypeScript template for AI-powered browser extensions with React, Manifest V3, feature flags, and multi-provider server-side AI analysis.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

Column Extension Template

This repository is a reusable starter architecture for TypeScript browser-extension products with AI analysis and a default server-side execution boundary. It is a template for creating independent product repositories, not a multi-product platform or a shared application monorepo.

Each product created from the template gets its own repository, implementation, release lifecycle, and product decisions. The three packages are the internal structure of one generated product:

Origin

Originally created by Mikhail Perepletchikov.

packages/core       Browser/server-safe contracts, schemas, pure processing, and analysis types
packages/extension  Browser extension runtime and React side panel
packages/server     Default server-side API, analysis application, and provider concerns

Current status

The repository contains project scaffolding only. The package boundaries, strict TypeScript setup, multi-browser Manifest V3 builds, typed runtime/build-time configuration, security defaults, CI workflow, and architecture documentation are ready. The server includes a deployment-ready health endpoint, a generic analysis boundary, and a product-neutral registry with OpenAI and Anthropic adapters. Page capture, extraction, concrete analysis schemas/prompts, product API routes, and UI behavior must be implemented by the product repository created from this template.

Requirements

  • Node.js 22.12.0 or newer;
  • pnpm 10.18.3;
  • Chrome or Edge for the Chromium build, or Firefox for the Firefox build.

The package manager and Node version are declared in package.json and .nvmrc.

Setup

pnpm install
pnpm check

pnpm check runs formatting, linting, strict typechecking, tests, and package builds. The scaffold includes focused configuration, analysis boundary, provider, and health endpoint tests.

Useful individual commands:

pnpm format         # Format files
pnpm format:check   # Check formatting
pnpm lint           # Run ESLint
pnpm typecheck      # Typecheck workspace packages
pnpm test           # Run Vitest
pnpm build          # Build workspace packages

Use pnpm for this workspace. The configured test script is pnpm test; there is no test:run script.

Create a product from this template

  1. Enable Template repository in the GitHub repository's Settings page.
  2. Choose Use this template and create a new product repository.
  3. Clone the new repository and install dependencies with pnpm install.
  4. Complete the bootstrap checklist below.

Bootstrap checklist

  • Rename the root package, extension manifest name/description, HTML title, and README.
  • Update the Firefox manifest's browser_specific_settings.gecko.id and data collection declaration for the product before signing or publishing it.
  • Fill in docs/product.md with the product's problem, first workflow, data handling, and runtime needs.
  • Copy .env.example to .env and set only the local values the product needs.
  • Keep credentials in the ignored .env file or the hosting provider's secret store; never put them in VITE_ variables or extension code.
  • Keep the default server runtime, or document an alternative analysis runtime before removing the server package and deployment adapter.
  • Add product-owned analysis input/output schemas, prompt, model configuration, and API route; select a built-in provider or add a tested adapter to the server registry.
  • Configure a public Flagsmith environment key only if the product uses remote feature flags.
  • Implement the smallest product workflow and add product-specific contracts, tests, and ADRs.
  • Run pnpm check before the first release.

The package names core, extension, and server are private workspace names and can remain generic. Rename them only if the product needs a different internal convention; they are not published libraries.

Feature flags

The extension includes a neutral Flagsmith/OpenFeature provider boundary because generated products may need this capability. Configure the public Flagsmith environment key in the local environment when a product wires the provider into its entry point:

VITE_FLAGSMITH_ENV_KEY=your_public_environment_key

The template does not define feature names, payload schemas, hooks, or product defaults. Add those in the generated product and validate remote flag payloads with Zod. Without an environment key, the provider uses an empty in-memory implementation for local development and tests. Initialize it from the product's extension entry point with configureFeatureFlags(). Never bundle a Flagsmith admin or server key.

Extension build

Build both unpacked extension targets with:

pnpm build

The build writes packages/extension/dist/chrome for Chrome and Edge and packages/extension/dist/firefox for Firefox. To build one target, use:

pnpm --filter extension build:chrome
pnpm --filter extension build:firefox

For Chrome or Edge, open the extensions page, enable Developer mode, choose Load unpacked, and select packages/extension/dist/chrome. For Firefox, open about:debugging, choose This Firefox, select Load Temporary Add-on, and open packages/extension/dist/firefox/manifest.json.

The Firefox manifest contains a template extension ID and a none data collection declaration. Replace both with the product's stable Firefox ID and actual data flows before publishing to addons.mozilla.org. Keep browser API calls behind packages/extension/src/platform; product entry points can use the exported extensionPlatform contract without importing chrome.* or browser.* directly.

Railway deployment

The root railway.json provides a minimal single-service deployment path for the default server package. Railway's Railpack builds the server workspace and starts it with the package's start script. The configuration does not assume a database, Redis, persistent volume, custom domain, or product-specific service name.

Create a Railway service from this repository and deploy it. Railway supplies the PORT environment variable; the server listens on that port on 0.0.0.0. The /health endpoint returns HTTP 200 with {"status":"ok"} and is used by Railway's health check. Add product-specific environment variables in Railway after the product adds the corresponding server behavior. The committed .env.example is for local development and documents the baseline variable expectations.

Architecture rules

  • Keep domain contracts and deterministic processing independent of Chrome APIs, React, Express, Node-only modules, and AI SDKs.
  • Keep browser API calls behind the extension platform boundary and emit separate manifests for browser families whose background or panel APIs differ.
  • Capture and clean page content locally where the browser has access to the rendered page.
  • Never send raw DOM objects or unbounded raw HTML through extension messages or to a server.
  • Perform deterministic cleanup, normalization, budgeting, and fingerprinting before semantic AI analysis.
  • Keep provider credentials, prompt construction, and provider HTTP/SDK details behind the default server-side application boundary. A different analysis runtime requires an explicit product decision.
  • Bound and strictly parse server JSON request bodies before product route validation; use the application service's caller-owned cancellation signal for stale or abandoned extension work.
  • Validate untrusted JSON, environment values, messages, persisted state, and AI output at runtime with Zod.
  • Keep the service worker responsible for extension job lifecycle and the side panel responsible for presentation.
  • Prefer session-only page state and avoid durable history until a product requirement justifies it.
  • Add an abstraction only when a second implementation or a clear test boundary makes it useful.

Environment

The committed .env.example is a neutral template for server/API and extension build-time settings. The server configuration parses NODE_ENV, PORT, provider selection, model, credential, timeout, and output-token values; the extension configuration parses VITE_API_BASE_URL and the public Flagsmith key. To create a local file:

cp .env.example .env

.env is ignored by Git and must never be committed. Provider credentials belong only in the ignored .env file or the hosting provider's secret store; they must never enter extension code. AI_MODEL and AI_API_KEY are fallback values for the selected provider, while OPENAI_* and ANTHROPIC_* values are provider-specific overrides.

AI provider boundary

The server's provider contract, registry, and built-in provider adapters keep vendor request formats out of product application services. Products provide their own input/output schemas and prompt through AiProviderAdapterOptions, then resolve the configured provider in their server composition root:

const provider = createConfiguredAiProvider(
  createDefaultAiProviderRegistry<AnalysisInput>({
    openai: { systemInstruction: productPrompt },
    anthropic: { systemInstruction: productPrompt },
  }),
  config.ai,
);

Keep the resulting provider on the server. The application service still validates model output against the product-owned Zod schema before returning it to the extension. Products may also attach an optional content-free usage diagnostics sink to record provider, model, request-size, latency, and available token metadata without logging prompts, responses, or page content. The template does not choose prompts, schemas, failover, routing, or diagnostics retention policy for a generated product.

Documentation and CI

Renaming this repository

The intended GitHub repository name is column-extension-template. Renaming the GitHub repository does not require renaming the local folder, but a matching local folder can make the workspace less confusing. After the GitHub rename, update the local remote if GitHub has not already redirected it:

git remote set-url origin git@github.com:persys-au/column-extension-template.git

The root package name matches the intended repository name. The internal package names remain generic and private. The lockfile changes only when package names or dependency resolution changes; build output should be regenerated with pnpm build and should not be committed.

About

Production-ready TypeScript template for AI-powered browser extensions with React, Manifest V3, feature flags, and multi-provider server-side AI analysis.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages