# How to Contribute to the A2UI Project: A Step-by-Step Developer Guide

> Learn how to contribute to the A2UI project with this step-by-step developer guide. Fork the repository, create a branch, and submit a pull request.

- Repository: [Google/A2UI](https://github.com/google/A2UI)
- Tags: how-to-guide
- Published: 2026-03-13

---

**Contributing to A2UI requires forking the Google repository, creating a feature branch that follows Google style guides for Python or TypeScript, and submitting a pull request that passes automated linting, unit tests, and specification validation.**

A2UI (Agent-to-User Interface) is an open-source framework that enables LLM agents to describe user interfaces declaratively in JSON. To successfully contribute to the A2UI project, you must understand its architecture—spanning the JSON protocol specification, transport-agnostic renderers, and language-specific SDKs—while adhering to the standardized GitHub workflow enforced by the maintainers.

## Understanding the A2UI Architecture

Before writing code, study how A2UI separates concerns between agents and clients.

### Declarative JSON Protocol

Agents emit JSON payloads that describe a flat list of components, each requiring an `id`, `type`, and optional `properties`. This contract is defined in [`docs/specification/v0.9-a2ui.md`](https://github.com/google/A2UI/blob/main/docs/specification/v0.9-a2ui.md), which serves as the source of truth for component schemas and data binding rules. All renderer implementations must consume payloads compliant with this specification.

### Renderer Pipeline and Component Registry

The Lit renderer in `renderers/lit/src/0.8/ui/` demonstrates the three-stage pipeline:

- **Resolution**: Parsing JSON into internal model objects
- **Mapping**: Converting abstract types like `text-field` to concrete UI widgets  
- **Theming**: Consuming theme objects (e.g., `theme.components.Video`) for styling

Renderers expose supported types through a `ComponentRegistry` located in [`renderers/lit/src/0.8/ui/component-registry.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/component-registry.ts). Adding any new component requires registration here.

### Data Binding Patterns

Primitive values support literal strings, literal numbers, or dynamic paths resolved via `A2uiMessageProcessor`. The `Video` component in [`renderers/lit/src/0.8/ui/video.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/video.ts) (lines 52-80) demonstrates both direct URL literals and path-based lookups using `this.processor.getData`.

## The Contribution Workflow

The project follows a standard GitHub pull-request model with strict quality gates.

### Repository Setup and Syncing

Start by forking `google/A2UI` via the GitHub interface. Configure your local clone to track upstream:

```bash
git remote add upstream https://github.com/google/A2UI.git
git fetch upstream && git rebase upstream/main

```

Regular rebasing prevents merge conflicts against the rapidly evolving `main` branch.

### Coding Standards and Style Guides

All submissions must comply with Google style guides:

- **Python**: Google Python Style Guide (enforced in `agent_sdks/python/`)
- **TypeScript**: Google TypeScript Style Guide (enforced in `renderers/lit/src/`)

Every source file requires the standard Google license header. Missing headers trigger immediate CI failure.

### Testing Requirements

Add or update unit tests alongside your changes. For Lit components, place tests adjacent to implementation files (e.g., [`badge.test.ts`](https://github.com/google/A2UI/blob/main/badge.test.ts) for [`badge.ts`](https://github.com/google/A2UI/blob/main/badge.ts)). Run the full suite locally before pushing:

```bash
npm test        # For TypeScript/Lit renderers

pytest          # For Python SDK changes

```

CI rejects PRs that break coverage thresholds or fail lint checks.

### Pull Request Submission

1. Create a short-lived feature branch: `git checkout -b my-feature`
2. Write clear commit messages using the format: `<type>: <short description>\n\n<optional body>`
3. Push to your fork and open a PR against `google/A2UI:main`
4. Complete the PR template, linking relevant issues
5. Address reviewer feedback through amended commits

The full checklist is documented in [`CONTRIBUTING.md`](https://github.com/google/A2UI/blob/main/CONTRIBUTING.md).

## Implementing New Components: A Practical Example

Extend the Lit renderer by adding a Badge component following the existing patterns in [`video.ts`](https://github.com/google/A2UI/blob/main/video.ts).

### Creating the Badge Component

Create [`renderers/lit/src/0.8/ui/badge.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/badge.ts) with this implementation:

```typescript
import { html, css, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { Root } from "./root.js";
import * as Primitives from "@a2ui/web_core/types/primitives";
import { classMap } from "lit/directives/class-map.js";
import { styleMap } from "lit/directives/style-map.js";

@customElement("a2ui-badge")
export class Badge extends Root {
  @property()
  accessor label: Primitives.StringValue | null = null;

  static styles = [
    css`
      :host {
        display: inline-block;
        padding: 0.2em 0.5em;
        border-radius: 0.5em;
        background: var(--badge-bg, #e0e0e0);
        color: var(--badge-fg, #000);
        font-size: var(--badge-size, 0.75rem);
      }
    `,
  ];

  #renderLabel() {
    if (!this.label) return nothing;
    if (typeof this.label === "object" && "literalString" in this.label) {
      return html`${this.label.literalString}`;
    }
    return html`(invalid)`;
  }

  render() {
    return html`<span
      class=${classMap(this.theme.components.Badge)}
      style=${this.theme.additionalStyles?.Badge
        ? styleMap(this.theme.additionalStyles?.Badge)
        : nothing}
      >${this.#renderLabel()}</span
    >`;
  }
}

```

### Component Registration and Specification Updates

Register the component in [`renderers/lit/src/0.8/ui/component-registry.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/component-registry.ts):

```typescript
registry.register("badge", Badge);

```

Optionally update [`docs/specification/v0.9-a2ui.md`](https://github.com/google/A2UI/blob/main/docs/specification/v0.9-a2ui.md) to define the `"badge"` type with its `label` property schema. Add comprehensive unit tests in [`badge.test.ts`](https://github.com/google/A2UI/blob/main/badge.test.ts) to verify rendering logic and data binding.

## Critical File Paths for Contributors

Navigate the codebase efficiently using these canonical locations:

- [`README.md`](https://github.com/google/A2UI/blob/main/README.md): Architecture overview and demo instructions (Restaurant Finder sample)
- [`CONTRIBUTING.md`](https://github.com/google/A2UI/blob/main/CONTRIBUTING.md): Complete contribution checklist and CLA requirements  
- [`docs/specification/v0.9-a2ui.md`](https://github.com/google/A2UI/blob/main/docs/specification/v0.9-a2ui.md): JSON protocol schema and component catalog
- [`renderers/lit/src/0.8/ui/video.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/video.ts): Reference implementation showing data binding
- [`renderers/lit/src/0.8/ui/component-registry.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/component-registry.ts): Component registration interface
- `agent_sdks/python/tests/`: SDK test patterns for payload construction
- `samples/restaurant_finder/`: End-to-end integration examples

## Summary

- **Fork and sync** the repository using `upstream` remote configuration to prevent merge conflicts.
- **Follow Google style guides** strictly; missing license headers or formatting violations block CI.
- **Understand the architecture**: A2UI uses a declarative JSON protocol, transport-agnostic renderers, and a component registry pattern.
- **Test locally** using `npm test` or `pytest` before submitting to avoid automated rejection.
- **Register components** in [`component-registry.ts`](https://github.com/google/A2UI/blob/main/component-registry.ts) and follow the `Video` component pattern for data binding.

## Frequently Asked Questions

### What license and CLA requirements apply to A2UI contributions?

All contributors must sign the Google Contributor License Agreement (CLA) before submitting pull requests. Every file must include the standard Google open-source license header. The full legal requirements are detailed in [`CONTRIBUTING.md`](https://github.com/google/A2UI/blob/main/CONTRIBUTING.md) at the repository root.

### How do I add support for a new UI component type in A2UI?

Create a concrete implementation in the appropriate renderer directory (e.g., `renderers/lit/src/0.8/ui/`), extend the base `Root` class, and register the component in [`component-registry.ts`](https://github.com/google/A2UI/blob/main/component-registry.ts). Update the protocol specification in [`docs/specification/v0.9-a2ui.md`](https://github.com/google/A2UI/blob/main/docs/specification/v0.9-a2ui.md) if introducing new schema elements, and provide unit tests following the patterns in [`video.ts`](https://github.com/google/A2UI/blob/main/video.ts) or `agent_sdks/python/tests/`.

### Why does my pull request fail automated checks?

CI failures typically result from three issues: missing Google license headers, style guide violations (enforced by `npm run lint` or equivalent), or insufficient test coverage. The repository runs GitHub Actions that validate the specification schema, lint all TypeScript and Python code, and execute unit tests. Run these checks locally before pushing to identify failures early.

### Which renderer should I use as a reference when contributing new components?

The Lit renderer serves as the reference web implementation. Study [`renderers/lit/src/0.8/ui/video.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/ui/video.ts) to understand how components handle literal values versus dynamic data paths via `A2uiMessageProcessor`. This implementation demonstrates the theming system, property binding, and the integration points required for the `ComponentRegistry`.