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

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, 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. 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 (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:

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 for badge.ts). Run the full suite locally before pushing:

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.

Implementing New Components: A Practical Example

Extend the Lit renderer by adding a Badge component following the existing patterns in video.ts.

Creating the Badge Component

Create renderers/lit/src/0.8/ui/badge.ts with this implementation:

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:

registry.register("badge", Badge);

Optionally update docs/specification/v0.9-a2ui.md to define the "badge" type with its label property schema. Add comprehensive unit tests in badge.test.ts to verify rendering logic and data binding.

Critical File Paths for Contributors

Navigate the codebase efficiently using these canonical locations:

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 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 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. Update the protocol specification in docs/specification/v0.9-a2ui.md if introducing new schema elements, and provide unit tests following the patterns in 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 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.

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 →