# Contributing

> Repository layout, dev prerequisites, PR checklist, test surfaces (Go integration, Playwright e2e), and documentation update expectations.

- Repository: Paca-AI/paca
- GitHub: https://github.com/Paca-AI/paca
- Human docs: https://grok-wiki.com/public/docs/paca-ai-paca-f238b2ab3d25
- Complete Markdown: https://grok-wiki.com/public/docs/paca-ai-paca-f238b2ab3d25/llms-full.txt

## Source Files

- `CONTRIBUTING.md`
- `CODE_OF_CONDUCT.md`
- `docs/guides/local-development.md`
- `apps/e2e/README.md`
- `services/api/.golangci.yml`
- `.github/PULL_REQUEST_TEMPLATE.md`

---

---
title: "Contributing"
description: "Repository layout, dev prerequisites, PR checklist, test surfaces (Go integration, Playwright e2e), and documentation update expectations."
---

Paca is a monorepo with path-filtered PR CI per runtime area (`services/api`, `apps/web`, `apps/mcp`, `services/realtime`, `services/ai-agent`, `apps/e2e`). Each workflow runs lint, build, and tests appropriate to that stack; API changes additionally split unit/integration tests from Docker-backed Go E2E tests under `services/api/test/e2e/`.

## Repository layout

:::files
paca/
├── README.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── ROADMAP.md
├── .github/                    # CI workflows and PR templates
├── docs/                       # Architecture, guides, API, deployment, plugins
├── apps/
│   ├── web/                    # React + TanStack Start + shadcn/ui frontend
│   ├── mcp/                    # @paca-ai/paca-mcp MCP server (npm package)
│   └── e2e/                    # Playwright browser test suite (not deployed)
├── services/
│   ├── api/                    # Go + Gin application backend
│   ├── realtime/               # Node.js + Socket.IO real-time fan-out
│   └── ai-agent/               # Python + FastAPI + OpenHands SDK agent runtime
├── skills/                     # Claude Code slash-command skill definitions
├── scripts/                    # Install and plugin management scripts
└── deploy/
    ├── docker-compose.dev.yml  # Hot-reload dev stack
    ├── docker-compose.prod.yml
    ├── docker-compose.e2e.yml  # Fixed-credential stack for Playwright
    └── nginx/                  # Gateway config mounted into nginx container
:::

| Area | Role |
|---|---|
| `apps/web` | User-facing UI; Vite HMR in dev |
| `apps/mcp` | MCP server published as `@paca-ai/paca-mcp` |
| `apps/e2e` | Playwright tests that exercise `apps/web` against a running stack |
| `services/api` | System-of-record HTTP API, migrations, domain events |
| `services/realtime` | Socket.IO fan-out from Valkey events |
| `services/ai-agent` | OpenHands conversation runtime and Docker workspaces |
| `docs/` | Durable technical writing kept out of the root README |
| `deploy/` | Compose files and nginx gateway configuration |

<Note>
`apps/e2e` lives under `apps` because it versions alongside `apps/web` and directly exercises the web surface. It is not a deployable runtime.
</Note>

## Prerequisites

<Tabs>
<Tab title="Full containerized stack">

Docker with the Compose plugin is the only hard requirement. One command starts every service with hot-reload:

```bash
docker compose -f deploy/docker-compose.dev.yml up -d
```

Open `http://localhost`. Services watch local source files and reload automatically.

</Tab>
<Tab title="Host-side development">

For IDE debugging or faster iteration on a single service, start infra only and run the target service on the host:

| Toolchain | Version | Used by |
|---|---|---|
| Go | 1.26+ (`go.mod` pins `1.26.0`) | `services/api` |
| Bun | 1.x | `apps/web`, `services/realtime`, `apps/mcp`, `apps/e2e` |
| Python + uv | 3.12+ | `services/ai-agent` |
| Docker | Compose plugin | Postgres, Valkey, MinIO containers |

```bash
# Infra only
docker compose -f deploy/docker-compose.dev.yml up -d postgres valkey

# API (first time: cp .env.example .env)
cd services/api && make run

# Web (first time: bun install)
cd apps/web && bun run dev

# Realtime (first time: bun install)
cd services/realtime && bun run dev

# AI agent (first time: uv sync)
cd services/ai-agent && uv run uvicorn src.main:app --reload --port 8000
```

Default dev credentials (`admin` / `adminpassword`, `paca:paca@localhost:5432/paca`) are intentionally weak — never use them outside local development.

</Tab>
</Tabs>

## Contribution workflow

<Steps>
<Step title="Fork and branch">

Clone the repository and create a focused branch for one concern. Keep pull requests scoped — the PR template and `CONTRIBUTING.md` both require single-concern changes.

</Step>
<Step title="Set up the dev environment">

Follow the containerized or host-side setup above. For a complete walkthrough of ports, nginx routing, and migration behavior, see the local development guide.

</Step>
<Step title="Make and verify changes">

Run the lint and test commands for every area you touch before opening a PR. Path-filtered CI mirrors these commands but does not run Playwright browser tests automatically.

</Step>
<Step title="Update documentation">

When behavior, interfaces, or architecture change, update the matching `docs/` section. Explain non-obvious tradeoffs in the PR description.

</Step>
<Step title="Open a pull request">

Fill in `.github/PULL_REQUEST_TEMPLATE.md`: summary, change type, and checklist. CI runs automatically for paths under the changed area.

</Step>
</Steps>

## Code quality by area

| Area | Linter | Local command | CI workflow |
|---|---|---|---|
| `services/api` | golangci-lint v2 | `make lint` | `api-pr-ci` |
| `apps/web` | Biome | `bun run lint` | `web-pr-ci` |
| `apps/mcp` | Biome | `bun run lint` | `mcp-pr-ci` |
| `services/realtime` | Biome | `bun run lint` | `realtime-pr-ci` |
| `services/ai-agent` | ruff (lint + format) | `uv run ruff check src/` | `ai-agent-pr-ci` |
| `apps/e2e` | Biome | `bun run lint` | `e2e-ci` |

### API lint configuration

`services/api/.golangci.yml` enables `errcheck`, `govet`, `staticcheck`, `revive`, `gocritic`, `bodyclose`, `noctx`, `exhaustive`, and others. Formatters include `gofmt` and `goimports` with local prefix `github.com/Paca-AI/api`. Test files relax `errcheck` and `gocritic` rules.

## Test surfaces

Paca has four distinct test layers. Know which layer applies to your change before choosing commands.

### Go unit tests

Scattered through `services/api/internal/` (for example handler-level tests). Run with the race detector:

```bash
cd services/api
go test -race -timeout 60s ./...
# or
make test
```

CI excludes `test/e2e` and uploads a coverage artifact:

```bash
go test -race -timeout 60s -coverprofile=coverage.out $(go list ./... | grep -v '/test/e2e')
```

### Go HTTP integration tests

Package `integration_test` under `services/api/test/integration/` exercises HTTP handlers and services through in-memory fakes and `miniredis` — no external Postgres or Valkey required. These run as part of the standard `go test ./...` invocation and in the `api-pr-ci` unit job.

Coverage areas include auth, users, projects, tasks, views, attachments, documents, plugins, API keys, agent API keys, admin authorization, and cache behavior.

```bash
cd services/api
go test -race -timeout 60s ./test/integration/...
```

### Go API E2E tests (testcontainers)

`services/api/test/e2e/` spins up real Postgres, Valkey, and MinIO containers via `testcontainers-go`, applies migrations, wires the full service stack, and hits an in-process `httptest.Server`. Requires Docker and the `PACA_E2E=1` gate:

```bash
cd services/api
PACA_E2E=1 go test -v -timeout 300s ./test/e2e/...
```

<Warning>
Without `PACA_E2E=1`, e2e tests skip with `set PACA_E2E=1 to run e2e tests (requires Docker)`. CI sets this env var in the dedicated `test-e2e` job, which depends on the `build` job completing first.
</Warning>

Test files cover auth flows, user/project/task/view management, attachments, API keys, plugins, pagination, and global-role authorization.

### Web unit tests (Vitest)

`apps/web` uses Vitest for component and API-client tests:

```bash
cd apps/web
bun run test        # single run
bun run test:watch  # watch mode
```

CI runs `bun run lint`, `bun run test`, and `bun run build`.

### Playwright browser E2E tests

`apps/e2e/` is a Playwright suite that exercises the web UI against a live application stack. It is separate from Go API e2e tests.

**Prerequisites:** Bun ≥ 1.0 and a running stack. Use either the dev compose file or the dedicated E2E compose file with test-safe credentials:

<CodeGroup>
```bash title="Dev stack"
docker compose -f deploy/docker-compose.dev.yml up -d
```

```bash title="E2E stack (recommended for Playwright)"
docker compose -f deploy/docker-compose.e2e.yml up -d --build --wait
```
</CodeGroup>

Setup and run:

```bash
cd apps/e2e
bun install
bunx playwright install --with-deps   # first time only
cp .env.example .env
bun test
```

| Variable | Default | Purpose |
|---|---|---|
| `E2E_BASE_URL` | `http://localhost` | Running app URL |
| `E2E_USERNAME` | `admin` | Test account username |
| `E2E_PASSWORD` | `e2e-admin-password` | Test account password |

<Info>
The E2E compose file sets `ADMIN_PASSWORD: e2e-admin-password`. The dev compose file uses `adminpassword`. Match `.env` credentials to whichever stack you started.
</Info>

Additional Playwright commands:

| Command | Purpose |
|---|---|
| `bun run test:ui` | Interactive Playwright UI |
| `bun run test:headed` | Visible browser window |
| `bun run test:debug` | Step-through debugging |
| `bun run test:report` | Open last HTML report |

Test layout:

```
apps/e2e/
├── global-setup.ts         # logs in once, saves auth state
├── playwright.config.ts
├── fixtures/               # extended test fixture with page objects
├── pages/                  # Page Object Model classes
├── features/               # Gherkin specs mirroring coverage (not wired to a runner)
└── tests/
    ├── auth/
    ├── validation/
    ├── security/
    ├── session/
    └── ux/
```

`global-setup.ts` writes browser auth state to `playwright/.auth/user.json` (git-ignored). Session tests load it via `test.use({ storageState: AUTH_FILE })`; other suites start unauthenticated for isolated login flows.

On CI (`CI=true`), Playwright config uses 1 worker, 2 retries, and projects for Chromium, Firefox, WebKit, Pixel 5, and iPhone 12. The `e2e-ci` workflow currently runs Biome lint only — contributors must run the Playwright suite locally before merging UI changes.

### AI agent unit tests

`services/ai-agent/tests/` runs with pytest; no external services required:

```bash
cd services/ai-agent
uv sync
uv run pytest --tb=short
```

CI runs ruff lint/format check, pytest, and a Docker image build.

## Pull request checklist

Use `.github/PULL_REQUEST_TEMPLATE.md` and `CONTRIBUTING.md` as your gate before requesting review:

<Check>
The change is scoped to one concern.
</Check>
<Check>
Tests are added or updated for changed behaviour in the affected test layer (Go integration, Go e2e, Vitest, Playwright, or pytest).
</Check>
<Check>
Related `docs/` files are updated when behaviour, interfaces, or architecture change.
</Check>
<Check>
Non-obvious decisions and tradeoffs are explained in the PR description.
</Check>
<Check>
Premature abstraction is avoided — add reuse only when proven.
</Check>

PR change types from the template: Documentation, Repository structure, Architecture clarification, Scaffolding, or Other.

## Documentation update expectations

The `docs/` directory is the main technical documentation home. Principles from `docs/README.md`:

- Keep documents short and navigable.
- Document decisions before implementation details.
- Prefer stable concepts over framework-level churn.
- Keep the root README product-focused; put technical detail here.

When your change touches a surface, update the matching section:

| Change type | Update |
|---|---|
| HTTP API paths, envelopes, auth | `docs/api/` |
| Architecture, service boundaries, DB schema | `docs/architecture/` |
| Dev setup, MCP setup, design system | `docs/guides/` |
| Plugin system, SDK, marketplace | `docs/plugins/` |
| AI agent behaviour, streams, skills | `docs/ai-agent/` |
| Production compose, secrets, scaling | `docs/deployment/` |
| Product concepts and workflows | `docs/product/` |

<Tip>
If you add a new env var, endpoint, or extension point, update both the relevant `docs/` page and any `.env.example` in the affected service.
</Tip>

## Community standards

### Code of conduct

`CODE_OF_CONDUCT.md` applies to repository discussions, issues, pull requests, and other community spaces. Participants communicate respectfully, criticize ideas rather than people, and must not engage in harassment or discrimination. Report violations through private maintainer contact — not public GitHub issues.

### Security

Do not open public issues for security vulnerabilities. Use [GitHub Security Advisories](https://github.com/Paca-AI/paca/security/advisories/new) per `SECURITY.md`. Scope includes auth/authz risks, data exposure, unsafe agent actions, WASM sandbox escapes, supply chain issues, deployment misconfiguration, and injection risks.

## Discussion areas

Contributors are welcome to discuss:

- Product workflow and user experience
- Service responsibilities and system boundaries
- Plugin system design and extension points
- AI agent behaviour and collaboration model
- Open-source governance and contributor experience

## Related pages

<CardGroup>
<Card title="Local development" href="/local-development">
Dev Compose stack, hot-reload per service, host-side run commands, and nginx port map.
</Card>
<Card title="Platform architecture" href="/platform-architecture">
Monorepo runtime areas, service boundaries, and Valkey event decoupling.
</Card>
<Card title="Build a plugin" href="/build-plugin">
Plugin authoring workflow when contributing to the extension system.
</Card>
<Card title="REST API reference" href="/rest-api">
Endpoint catalog to cross-check when adding or changing API behaviour.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Common install and runtime failures during local contribution setup.
</Card>
</CardGroup>
