AGENTS.md
AGENTS.mdAGENTS.mdroot
Quality
81/100
Scores the file, not the repository.Length
2,445 words
58 headings · 10 code blocksRepository
28k
— · pushed 0 days agoLast changed
today
First indexed 2 days ago.1# Coding Agent Guidelines for Kestra Open Source Edition23This document provides essential information for AI coding agents working on the Kestra codebase.45**IMPORTANT — READ FIRST**67- **Act as a Senior Software Engineer and Software Architect.** Approach software development with:8 - **Pragmatism**: Favor simple solutions over clever ones9 - **Skepticism**: Question decisions that could cause technical debt or scalability issues10 - **Efficiency**: Only challenge when it genuinely matters11- **Think before coding**: explicitly state assumptions, compare alternatives, and justify choices.12- **Simplicity first (KISS)**: overengineering and "gas factories" are strictly forbidden.13- **Surgical changes only**: touch **only** what is strictly necessary to achieve the goal.14- **Goal-driven execution**: define what success looks like *before* writing the first line of code.15- **Preserve existing comments**: never delete any existing comment **unless** you are improving its clarity or usefulness.16- **Keep comments short and only where they earn their place**: a comment you write should be **one sentence**, or two at most when the *why* genuinely needs it (a non-obvious constraint, a workaround, a subtle ordering or concurrency requirement). Do **not** comment obvious code — no restating what the next line plainly says (`// increment the counter`), no narrating a self-explanatory getter, loop, or well-named call. If the code is readable, the comment is noise; if it isn't, prefer making the code clearer over explaining it.17- **Write clear, maintainable, and well-documented code**18- **Build & test are mandatory**1920## Project2122Monorepo built with Java (backend) and Vue (frontend), using Gradle as the build system.2324## Tech Stack25- **Backend:** Java 25, Micronaut Framework, Lombok26- **Frontend:** Vue 3, TypeScript, Vite, Element Plus, Pinia27- **Build:** Gradle 8.x with multi-project structure (77 submodules)28- **Testing:** JUnit 5, Mockito, AssertJ, Vitest, Playwright2930## Critical Code Patterns3132### Dependency Injection3334**DO**: Use constructor injection with final fields.3536```java37@Singleton38public class MyService {39 private final SomeDependency dependency;4041 @Inject42 public MyService(SomeDependency dependency) {43 this.dependency = Objects.requireNonNull(dependency);44 }45}46```4748**DON'T**: Use field injection (`@Inject` on fields directly). Always prefer constructor injection.4950### Class Structure5152```java53// 1. Package declaration and imports54// 2. Class-level annotations (@Slf4j, @Singleton, etc.)55// 3. Class declaration with Javadoc56// 4. Static constants (UPPER_SNAKE_CASE)57// 5. Injected fields (@Inject)58// 6. Constructors59// 7. Public methods60// 8. Protected methods61// 9. Private methods62// 10. Inner classes/records63```6465### Annotations66- **Micronaut:** `@Singleton`, `@Inject`, `@Controller`, `@Replaces`, `@Requires`67- **Validation:** `@Valid`, `@NotNull`, `@Nullable`68- **Lombok:** `@Slf4j`, `@Getter`, `@NoArgsConstructor`, `@AllArgsConstructor`69- Use `@Builder` for complex object creation7071### Error Handling7273**DO**:74- Use specific exception types — extend `KestraException` or `KestraRuntimeException`75- Use `Optional<T>` for potentially absent returned values76- Return empty collections (e.g., `List.of()`, `Collections.emptyList()`) for absent values77- Use try-with-resources for resource management78- Log errors before re-throwing: `log.error("message", exception)`79- Write exception messages as plain, complete sentences that state the fact and the actionable detail — build them with `String.formatted()`/`String.format()`, not string concatenation or em dashes, e.g. `"Cannot acquire lock on asset '%s': already locked by '%s' until %s.".formatted(id, owner, until)`8081**DON'T**: Use generic `Exception`. Don't return null for collections. Don't write terse or telegraphic exception messages (e.g. dropping articles/verbs) or string-concatenate message parts.8283### Java Language Features84- Use java records for simple data carriers8586### Naming Conventions87- Follow Java naming-convention best practices for Classes, Methods, Variables, Constants.88- Boolean methods: Start with `is`, `has`, `should`, `can` (e.g., `isReadOnly()`).8990### File Organization91- Use 4-space indentation (configured in .editorconfig)92- UTF-8 encoding with LF line endings93- No trailing whitespace9495### Utility Classes96* Mark utility classes as `final` with a private constructor97* Use static methods only98* Use existing utility classes (e.g., `ListUtils`, `MapUtils`) instead of creating new ones (`io.kestra.core.utils.*`)99100**MANDATORY — never hand-roll Pebble delimiter detection.** Pebble has two block delimiter pairs — print blocks (`{{ ... }}`) and execute/statement blocks (`{% ... %}`) — and code that only checks for `{{`/`}}` silently misses `{%`/`%}` blocks. Use `io.kestra.core.utils.PebbleUtil` (`containsOpeningBlockDelimiter`, `startsWithOpeningBlockDelimiter`, `endsWithClosingBlockDelimiter`, `openingBlockDelimiters()`/`closingBlockDelimiters()`) instead of writing a new delimiter regex or literal — it derives the delimiter pairs from Pebble's own `Syntax.Builder` defaults, so it never drifts from what Pebble actually parses.101102### Enums103- Use enums for fixed sets of constants, including internal fields not exposed over the API — prefer a typed enum over a raw `String`/`int` whenever the value is drawn from a closed set of known cases, even if the set may only ever have a couple of members104- Use `@JsonValue` for custom serialization if needed105- Use `UNKNOWN` enum value for unknown cases in deserialization106- Compare Constants From The Left (a.k.a., Yoda conditions)107- Use a static `fromString` method for case-insensitive lookups using `Enums` class.108109e.g.:110```java111public enum MyEnum {112 VALUE_ONE,113 VALUE_TWO,114 UNKNOWN;115116 @JsonCreator117 public static ResourceType fromString(final String value) {118 return Enums.getForNameIgnoreCase(value, MyEnum.class, UNKNOWN);119 }120}121```122123### Documentation124- Javadoc for all public classes and methods - be concise125- Use `@param`, `@return`, `@throws` appropriately126- Use `{@inheritDoc}` for inherited methods127- Include usage examples for complex methods128129## Webserver Constraints130- Put classes used by only controllers in the webserver module (not core)131- No business code/rule inside controllers - instead use a Service class132- All APIs must return a valid JSON object133- APIs should not return a response being a JSON array which cannot be evolved in a backwards-compatible way134- Unit tests must assert that a user can only access a given API if authorized to do so, and that access is denied otherwise135- APIs must be documented with OpenAPI annotations136- Use DTOs for requests/responses137- Always validate input parameters with `@Valid`138- Use `@ExecuteOn(TaskExecutors.IO)` for blocking operations139- Return meaningful error responses in controllers140141## Worker Constraints142- Never depend on repositories for code called by the workers - instead use MetaStore/StateStore facades143144## Executor Constraints145- Run the `H2RunnerTest` whenever you update part of the executor146147## Testing Guidelines148149### Java Tests150151**DO**:152- Place tests in same package structure as source code153- Simple unit test with mocks over complex integration tests when possible154- Add // Given-When-Then comments for clarity155- Test method naming: `should<ExpectedBehavior>When<ConditionOrAction>` (also `...Given<Input>`, `...For<Condition>`, `...If<Condition>`), e.g. `shouldThrowExceptionWhenDividingByZero()`156- Use `@MicronautTest` for tests that require Micronaut beans157- Use `@KestraTest` for tests that require running Kestra services (e.g., Executor, Scheduler)158-159```java160@KestraTest161class ServiceTest {162 @Inject163 private ServiceClass service;164165 @Test166 void shouldPerformActionWhenCondition() {167 // Given (setup)168169 // When (action)170171 // Then (assertions)172 assertThat(result).isNotNull();173 }174}175```176177**DON'T**: Use Nested classes for test organization. Avoid complex test hierarchies.178179**Assertions:**180- Use AssertJ: `assertThat().isEqualTo()`, `assertThat().isNotNull()`, `assertThatThrownBy()`, `assertThatObject()`181- Prefer descriptive assertion methods182- Use `@MockBean` for mocking dependencies183184**Test Categories:**185- Unit tests: Fast, isolated, no external dependencies186- Integration tests: Test component interaction, use `@Tag("integration")`187- Flaky tests: Use `@Tag("flaky")` for unreliable tests188189### Frontend Tests190- Unit tests with Vitest and `@vue/test-utils`191- E2E tests with Playwright192- Storybook component tests193- Use JSdom environment for DOM testing194195## UI Design System196197The full UI design-system rules, component catalogue, token reference, and frontend best practices live in [ui/AGENTS.md](ui/AGENTS.md). That file is auto-loaded by AI coding agents whenever work happens under `ui/` in OSS or `ui-ee/` in Enterprise edition, and should be consulted (and kept up to date) for any frontend change.198199@ui/AGENTS.md200201## Frontend Code Style (Vue 3)202203**File Organization:**204- Use 2-space indentation for Vue, JSON, YAML, CSS205- Use 4-space indentation for JavaScript/TypeScript206- Follow Vue 3 Composition API patterns207- Organize imports: Vue/framework → third-party → local modules208209**Naming Conventions:**210- Components: `PascalCase` files (e.g., `MyComponent.vue`)211- Variables/functions: `camelCase`212- Constants: `UPPER_SNAKE_CASE`213- CSS classes: Follow Element Plus conventions214215**TypeScript:**216- Use strict TypeScript configuration217- Prefer type definitions over `any`218- Use interfaces for object shapes219- Use enums for fixed sets of values220221## Build Commands222223### Java Backend224225```bash226# Clean build227./gradlew clean228229# Full build (includes tests)230./gradlew build231232# Build without tests (faster)233./gradlew build -x test -x integrationTest -x testCodeCoverageReport --refresh-dependencies --no-daemon --parallel234```235236### Test Commands237238```bash239# Run all tests (excludes flaky tests)240./gradlew test241242# Run only unit tests (fastest)243./gradlew unitTest244245# Run integration tests246./gradlew integrationTest247248# Run flaky tests (separate from build)249./gradlew flakyTest250251# Run tests for specific module252./gradlew :core:test253254# Run single test class255./gradlew :module-name:test --tests "ClassName"256257# Run single test method258./gradlew :module-name:test --tests "ClassName.methodName"259260# After running tests: generate a markdown summary of failures only261npx --yes @kestra-io/kestra-devtools generateTestReportSummary --only-errors $(pwd)262```263264### Frontend (UI)265266```bash267cd ui268269# Install dependencies270npm install271272# Development server273npm run dev274275# Type checking276npm run check:types277278# Build for production279npm run build280281# Run tests282npm run test:all # All tests with coverage283npm run test:unit # Unit tests only284npm run test:storybook # Storybook tests285npm run test:e2e # End-to-end tests286287# Linting288npm run lint # Fix linting issues289npm run test:lint # Check linting only290291# Storybook292npm run storybook # Development293npm run build-storybook # Build294```295296## Development Workflow297298### Running Locally2993001. **Start/stop backends:**301```bash302# Start databases with Docker Compose303docker compose -f docker-compose-ci.yml up304305# Stop databases with Docker Compose306docker compose -f docker-compose-ci.yml down307```3083092. **Access application:** http://localhost:8080310311### Worktree setup312313When working in an EE worktree (detected by: the working directory is under a `worktrees/` directory):314```bash315dev-tools/setup-worktree.sh ../worktrees/foo316```317This copies the gitignored `cli/src/main/resources/application-*.yml` files from the main checkout into the worktree. Without this step Kestra cannot boot in the worktree. The script is idempotent — safe to re-run.318319### Security Considerations320- Use tenant isolation for multi-tenant features321- Implement proper authorization with `@HasAnyPermission`322- Handle secrets securely (never log sensitive data)323324### Performance Best Practices325- Implement pagination for large datasets326- Use streaming for large file operations327- Cache frequently accessed data appropriately328- Initialize collections with the expected size to avoid resizing overhead329330## Troubleshooting331332**Common Issues:**333- **Build failures:** Run `./gradlew clean` and retry334- **Test failures:** Check for service dependencies (Docker containers)335- **Frontend issues:** Ensure Node.js version matches package.json requirements336337**Debugging:**338- Use IDE debugging with remote JVM debugging339- Use Micronaut's built-in health endpoints340- Enable debug logging: `--logging.level.io.kestra=DEBUG`341- Use JUnit and Vitest reports for test failures342343## Module Structure344345**Core Modules:**346- `cli` - Command Line Interface347- `core` - Core functionality348- `webserver` - Web server349- `ui` - Vue 3 frontend application350- `executor` - The component responsible for managing execution state351- `scheduler` - The component responsible for scheduling polling and schedule triggers352- `worker` - The component that executes tasks and manages worker instances353- `worker-controller` - The component that manages worker instances and job distribution354- `indexer` - The component responsible for indexing executions355- `plateform` - provides the Platform Bill of Materials (BOM) for dependency management356357**Queuing Layer:**358- `queue` - Core API for queue implementations359- `queue-jdbc` - JDBC-based queue implementation360361**Data Layer:**362- `jdbc-*` - Database implementations (H2, Postgres, MySQL)363364**Testing Modules:**365- `tests` - Common test utilities and base classes366- `jmh-benchmark` - JMH benchmarks for performance testing367368**Key Patterns:**369- Repository pattern for data access370- Service layer for business logic371- Controller layer for HTTP endpoints372- Builder pattern for object construction (often with Lombok `@Builder`)373374## Pull request guidelines375- Always add tests, keep your branch rebased instead of merged, and adhere to the commit message recommendations from https://www.conventionalcommits.org/en/v1.0.0.376- Use types: chore, feat, fix, refactor, test, docs, build377- Use scopes: apps, assets, core, dashboards, deps, design-system, executions, flows, iam, namespaces, plugins, secrets, storage, scheduler, system, tasks, tenants, tests, topology, triggers, variables, version, worker378379## Issue guidelines380- **Classify an issue with its GitHub issue type, not a `kind/*` label.** The `kind/bug` label is retired — do not add it. Set the type instead: `gh issue create --title … ` followed by `gh issue edit <number> --type Bug`, or `gh issue edit <number> --type Task|Feature|Epic`. Available types are `Task`, `Bug`, `Feature` and `Epic` (list them with `gh api /orgs/kestra-io/issue-types`).381- **Do add the `area/*` labels** — `area/frontend`, `area/backend`, `area/devops`, `area/docs`, `area/plugin`, `area/qa`, `area/analytics` — since those drive routing and are still in use.382- Leave triage labels such as `kind/cooldown` to `kestrabot`; it applies them automatically on new issues.383384This document should be updated as the codebase evolves. When in doubt, follow existing patterns in the codebase and maintain consistency with established conventions.385386## UI Translations387388**MANDATORY — never hardcode user-facing strings.** Every label, button, tooltip, placeholder, dialog/section title, table-column header, and toast/confirm message rendered to the user MUST go through vue-i18n: `t("key")` (or `:label`/`:tooltip` bindings) in components, and `<i18n-t keypath="...">` with named slots when the string embeds markup or a component (e.g. a `<code>` fragment). Never write a literal user-facing string in a template, a `:tooltip`/`:label` attribute, or a `toast.*` call. Reuse existing generic keys (`cancel`, `delete`, `edit`, `save`, `add`, `id`, `description`, `namespace`, `revision`, …) instead of duplicating them; put feature-specific strings under one namespaced object (e.g. `"reusableInputs": { … }`). After adding keys to `en.json`, propagate them to every language (translation generation script) so the missing-keys check stays clean — a key present only in `en.json` fails the check.389390Translation files live in `ui/src/translations/`. There is one JSON file per language code (e.g. `de.json`, `fr.json`) plus the source `en.json`.391392### Checking for missing translations393394Run the check script from the `ui/` directory:395396```bash397cd ui && npm run translations:check398```399400A clean run reports `No missing keys. No extra keys.` for every language. Any listed missing keys must be added.401402> **Enterprise Edition:** EE-only keys live in `ui-ee/src/translations/ee_translations/en.json` and are checked separately — run `npm run translations:check` in `ui-ee` as well (see `kestra-ee/AGENTS.md` → "Frontend i18n").403404### Adding missing translations4054061. Identify gaps by running `npm run translations:check` (or by diffing the flattened `en.json` keys against each language file).4072. Translate only the missing keys — do **not** re-translate keys that already have a value.4083. Follow these translation rules (mirroring `generate_translations.ts`):409 - **Reserved English terms — never translate:** `kv store`, `namespace`, `flow`, `subflow`, `task`, `log`, `blueprint`, `id`, `trigger`, `label`, `key`, `value`, `input`, `output`, `port`, `worker`, `backfill`, `healthcheck`, `min`, `max`.410 - **ALL-CAPS status labels stay in English:** `WARNING`, `FAILED`, `SUCCESS`, `PAUSED`, `RUNNING`, etc.411 - **Preserve `{{placeholder}}` variables** exactly — do not translate the word inside the braces.412 - **Use natural UI terminology** — avoid false friends or overly literal translations (e.g. German: Execution → Ausführung, Theme → Modus, State → Zustand).4134. Insert the translated keys into the correct position in the target language JSON, keeping `sort_keys=True` order (alphabetical within each object).4145. Re-run `npm run translations:check` to confirm everything is clean before committing.415
Also in kestra-io/kestra
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| kestra-io/kestraui/AGENTS.md · 28k | AGENTS.md | teststylearchgit+5 | 53/100 | 2 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| trick77/agents-md-syncAGENTS.md · 2 | AGENTS.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| SkeneTechnologies/skene-cookbookAGENTS.md · 51 | AGENTS.md | setupbuildtestlint-format+7 | 100/100 | 2 days ago | |
| duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70 | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| wpscanteam/wpscanAGENTS.md · 9.7k | AGENTS.md | setupbuildteststyle+6 | 100/100 | 2 days ago | |
| mui/material-uiAGENTS.md · 99k | AGENTS.md | setupbuildtestlint-format+9 | 100/100 | 3 days ago | |
| n8n-io/n8npackages/@n8n/agents/AGENTS.md · 199k | AGENTS.md | buildteststylearch+3 | 100/100 | 3 days ago | |
| aaif-goose/gooseAGENTS.md · 52k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TryGhost/Ghoste2e/AGENTS.md · 55k | AGENTS.md | setupteststylearch+2 | 100/100 | 3 days ago |
