AGENTS.md · appwrite/appwrite
AGENTS.md from appwrite/appwrite: 335 lines covering Commands, Stack, Layout, Console and more.
Template by appwrite
Install
Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.
curl -fsSL https://raw.githubusercontent.com/appwrite/appwrite/main/AGENTS.md -o AGENTS.md
Read it and adapt it to your project before use.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: prompt-engineering
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
What's in it
An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.
- For
- Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
- Length
- 335 lines
- File
AGENTS.md
Sections
- Commands
- Stack
- Layout
- Console
- Libraries
- Modules
- HTTP actions
- Lifecycle
- Reuse
- Conventions
- Collections
- Tests
- SDK specs
- Releases
First lines (shown under the repo's BSD-3-Clause license)
# Appwrite
Self-hosted Backend-as-a-Service. Hybrid monolithic-microservice architecture on PHP 8.5+ and Swoole 6, delivered as Docker containers.
## Commands
| Command | Purpose |
|---------|---------|
| `docker compose up -d --force-recreate --build` | Build and start all services (combined worker + scheduler by default) |
| `docker compose -f docker-compose.yml -f docker-compose.separate.yml --profile separate up -d` | Start per-queue worker and scheduler containers instead |
| `docker compose exec appwrite test tests/e2e/Services/[Service]` | Run E2E tests for a service |
| `docker compose exec appwrite test tests/e2e/Services/[Service] --filter=[Method]` | Run a single test method |
| `docker compose exec appwrite test tests/unit/` | Run unit tests |
| `composer format` | Auto-format code (Pint, PSR-12) |
| `composer format <file>` | Format a specific file |
| `composer lint <file>` | Check formatting of a file |
| `composer analyze` | Static analysis (PHPStan 2, level 4) |
| `composer check` | Same as `analyze` |
| `composer refactor:check` | Rector dry-run over `tests/` (CI "Refactor" check) |
| `composer refactor` | Apply Rector fixes |
| `bin/monorepo validate` | Check every `packages/<name>` against the standard shape and the root autoload wiring |
| `bin/monorepo check <name> [--fix]` | Pint, PHPStan (package `phpstan.neon`) and Rector for one package |
| `bin/monorepo test <name> [--linked]` | Package unit tier (`composer test`), plus `test:e2e` against its compose file when defined |
| `bin/monorepo absorb <name> [url]` | Import a library with history, strip hoisted QA, write mirror plumbing |
| `bin/monorepo split <name> --dry-run` | Synthesize the mirror history and print its head without pushing |
| `bin/monorepo release <name> <version>` | Tag `<name>/<version>` and push it; CI mirrors the tag and publishes the release |
`composer check` / `composer analyze` over the whole project is very slow. Prefer specific files during development.
## Stack
- PHP 8.5+, Swoole 6.x (async runtime, replaces PHP-FPM)
- Utopia PHP (HTTP routing, CLI, DI, queue)
- PostgreSQL (default platform DB); adapters: postgresql, mariadb, mongodb via utopia-php/database. DocumentsDB defaults to mongodb; VectorsDB to postgresql
- Redis 7.x (cache, queue, pub/sub); Docker + Traefik 3.x
- PHPUnit 12, Pint 1 (PSR-12), PHPStan 2 (level 4), Rector 2
## Layout
- **src/Appwrite/** -- domain libraries (one directory per problem). Key libraries:
- **Auth** -- keys, OAuth, MFA
- **Event** -- queue publishers (functions, mails, webhooks, deletes, …)
- **Network** -- CORS, origin, DNS, client platforms
- **SDK** -- spec and SDK method metadata
- **Migration** -- versioned data migrations
- **GraphQL** -- schema and resolvers
- **Messaging**, **Realtime**, **PubSub** -- realtime fan-out
- **Database** -- platform/project DB factory
- **Vcs** -- Git provider helpers
- **Deployment** -- build and deploy helpers
- **Usage** -- metrics
- **Utopia** -- extensions of Utopia libraries, `src/Appwrite/Utopia/{Lib}` (`Database`, `Fetch`, `Messaging`, `Request`, `Response`, `WebSocket`, …); see [Libraries](#libraries)
- **Extend** -- shared exceptions
- **src/Appwrite/Platform/** -- HTTP modules, workers, CLI tasks. Register modules in `src/Appwrite/Platform/Appwrite.php`. See [Modules](#modules).
- **src/Executor/** -- Open Runtimes executor HTTP client (create/run/delete function and site runtimes)
- **packages/** -- Utopia libraries absorbed into this repository and autoloaded directly (`agents`, `bus`); each is an independent Composer package mirrored to `utopia-php/<name>`, managed with `bin/monorepo`. See [rfc/monorepo.md](rfc/monorepo.md)
- **apps/** -- deployable applications with their own runtime, image, and release (`console`: the web Console, Bun + TanStack Start, shipped as `appwrite/new`). Not Utopia packages: no Composer autoload, no split mirror. Do not confuse with `app/`, the PHP server. See [apps/README.md](apps/README.md) and [Console](#console).
- **app/config/** -- static product config (collections, locales, SDKs, runtimes, scopes, errors, OAuth, storage)
- **app/assets/** -- bundled data (fonts, common-password dictionary)
- **app/views/** -- server-side templates (installer, errors, proxy)
- **app/init.php** -- bootstrap; **app/init/** -- constants, models, registers, resources, span, database filters/formats
- **app/http.php**, **app/worker.php**, **app/realtime.php**, **app/cli.php** -- process entry harnesses
- **app/controllers/** -- leftover HTTP controllers; new endpoints go in modules
- **bin/** -- CLI entry points (`worker`, `worker-*`, `schedule`, `schedule-*`, `queue-*`, plus `doctor`, `install`, `migrate`, `realtime`, …)
- **docs/** -- references, tutorials, SDK getting-started notes, [release process](docs/releases.md)
- **tests/e2e/**, **tests/unit/** -- tests; **public/** -- fonts, images, generated SDKs
## Console
Console and UI work uses the code in `apps/console`. Follow [apps/console/AGENTS.md](apps/console/AGENTS.md) for that app's agent guidance.
## Libraries
`src/Appwrite/` is domain libraries, not a dumping ground. Each directory solves **one problem**. Do not grow a library into a second concern; add a new directory instead. See [Layout](#layout) for the current set.
Keep Appwrite-specific domain here (product events, SDK specs, GraphQL, usage, migrations, platform modules). If a library is **generic enough to build any kind of app** — validators, storage, cache, queues, HTTP, databases, locks, DNS — it is a Utopia package, not `src/Appwrite/` code. Packages already absorbed live under `packages/<name>` in the standard shape described in [rfc/monorepo.md](rfc/monorepo.md) and are loaded directly through the root autoload; the rest are still Composer dependencies until their absorb PR lands.
Code that extends, subclasses, adapts or wraps a Utopia library goes in `src/Appwrite/Utopia/{Lib}/` (namespace `Appwrite\Utopia\{Lib}`), mirroring the library name: [`Utopia/Database/Validator`](src/Appwrite/Utopia/Database/Validator), [`Utopia/Database/Documents/User.php`](src/Appwrite/Utopia/Database/Documents/User.php), [`Utopia/Request`](src/Appwrite/Utopia/Request), [`Utopia/Response`](src/Appwrite/Utopia/Response). Appwrite-domain logic stays in its own domain namespace or platform module, not under `Utopia/`. Behavior any app would need belongs in the Utopia library itself: fix the library instead of adding an app-side gap-filler.
## Modules
Each module under `src/Appwrite/Platform/Modules/` owns one domain: HTTP endpoints, optional workers, and rarely CLI tasks. Generally each API service is its own module; put related code under one roof. Register new modules in `src/Appwrite/Platform/Appwrite.php`.
A module contains:
- `Module.php` -- registers services from `Services/`
- `Http/` -- HTTP endpoints
- `Services/` -- `Http.php`, optionally `Workers.php` / `Tasks.php`
- `Workers/` -- optional module-specific workers
- `Tasks/` -- optional; most CLI tasks live in `src/Appwrite/Platform/Tasks/`
Directly under `Http/` there are only service directories. A single-service module uses one directory named after the service (`Modules/Account/Http/Account`). A multi-service module uses one per service (`Modules/Databases/Http/Databases` and `Modules/Databases/Http/TablesDB`).
Nest resources and properties as directories. Top-level resources in the same module are **siblings**, not nested under the parent resource folder. Template deployments live at `Modules/Functions/Http/Deployments/Template/Create.php` (`Deployments/` is a sibling of `Functions/`; `template` is a property). Action file names and constructor methods: [HTTP actions](#http-actions). Init/shutdown/error hooks: [Lifecycle](#lifecycle).
```
src/Appwrite/Platform/Modules/Functions
├── Module.php
├── Workers
│ └── Builds.php
├── Http
│ ├── Functions
│ │ ├── Create.php
│ │ ├── XList.php
│ │ ├── Update.php
│ │ ├── Delete.php
│ │ └── Get.php
│ └── Deployments
│ ├── XList.php
│ ├── Delete.php
│ ├── Get.php
│ └── Template
│ └── Create.php
└── Services
├── Http.php
└── Workers.php
```
## HTTP actions
Action files must be `Get.php`, `Create.php`, `Update.php`, `Delete.php`, or `XList.php` (`List` is reserved). Model non-CRUD work as a property update (`Teams/Http/Memberships/Status/Update.php` → `PATCH /v1/teams/:teamId/memberships/:membershipId/status`). Never RPC-style files (`Verify.php`, `Block.php`).
| REST verb | HTTP | File | SDK `name` | Example |
|-----------|------|------|------------|---------|
| `create` | POST | `Create.php` | `create` | `POST /v1/account/verifications` |
| `get` | GET | `Get.php` | `get` | `GET /v1/teams/:teamId` |
| `list` | GET | `XList.php` | `list` | `GET /v1/teams` |
| `update` | PATCH / PUT | `Update.php` | `update` | `PATCH /v1/account/sessions/:sessionId` |
| `delete` | DELETE | `Delete.php` | `delete` | `DELETE /v1/teams/:teamId` |
Path, directory, action class, `getName()`, and SDK `Method` `name` describe the same REST operation. SDK `name` is a REST verb, plus a qualifier when needed (`createStringColumn`, `updateStatus`). Never RPC verbs (`verify`, `block`, `send`). `getName()` is a stable registered id (legacy values like `createTeam` exist); new code should match the REST verb (+ qualifier).
Skeleton (full example: `src/Appwrite/Platform/Modules/Teams/Http/Teams/Create.php`):
```php
class Create extends Action
{
public static function getName(): string { return 'create'; }
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/teams')
->label('scope', 'teams.write')
->inject('response')->inject('dbForProject')
->callback($this->action(...));
}
}
```
Common injections: `$response`, `$request`, `$dbForProject`, `$dbForPlatform`, `$user`, `$project`, `$queueForEvents`, `$queueForMails`, `$queueForDeletes`.
HTTP actions `use Utopia\Platform\Scope\HTTP`. Constructor methods (chain on `$this`):
| Method | Role |
|--------|------|
| `setHttpMethod()` | `HTTP_REQUEST_METHOD_GET` / `POST` / `PATCH` / `PUT` / `DELETE` |
| `setHttpPath()` | Route, with `:param` segments (`/v1/teams/:teamId`) |
| `httpAlias()` | Extra path that hits the same action (legacy URLs) |
| `desc()` | Short human description |Signals
- Stars
- 57,761
- Forks
- 5,822
- Open issues
- 368
- Last commit (this folder)
- Oct 15, 2026 (14 days ago)
- Last release
- Oct 24, 2026 (5 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- BSD-3-Clause
- Repository
- github.com/appwrite/appwrite
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from appwrite
Cite this page
AGENTS.md · appwrite/appwrite. Agent Mart. https://agentmart.dev/templates/appwrite-appwrite-agents-md (last updated 2026-10-24)