This file applies to the entire repository. Nested AGENTS.md files may add rules for a subdirectory; when they do, follow both the root file and the nested file.
This document defines contributor and agent governance only. It does not change runtime APIs, schemas, or protocol types.
- Prefer clear, traceable work over implicit progress. Keep the user informed about what is being done, what remains, and any relevant blockers.
- Use these instructions by default. If a specific task requires a different approach, explain the reason clearly before deviating.
- Keep plans and outputs portable across agent runtimes unless the user asks for behavior tied to a specific tool.
- Avoid unnecessary complexity. Choose the simplest approach that satisfies the user's stated goal and preserves correctness.
- Agents MUST use the available task-tracking tool whenever the work has multiple steps, meaningful uncertainty, or a non-trivial implementation path.
- Track tasks as pending, in progress, and completed so the current state of the work stays explicit.
- Update the task list as work progresses, not only at the end.
- Keep task entries concrete and outcome-oriented. Each task should describe a verifiable unit of work.
- When new work is discovered, add it to the tracker instead of relying on memory.
- When a task becomes irrelevant, mark or explain it rather than silently dropping it.
- Before finishing, reconcile the tracker with the actual work completed and call out anything intentionally left undone.
- Riverpod providers MUST use code generation (
riverpod_generator) rather than hand-written provider declarations. - When a task may touch Riverpod, Drift, or
dart_mappablegenerated code, agents MUST ensure a single repo-scopedbuild_runnerwatcher is active before editing generated surfaces. - The standard watcher command for this repository is
flutter pub run build_runner watch -d. - Agents MUST use the repo-scoped PID/log convention under
.dart_tool/copilot/:build_runner_watch.pidfor the active watcher PID andbuild_runner_watch.logfor output. - Before starting a watcher, agents MUST check whether the PID file exists and whether
ps -p <pid>confirms that process is still alive. If it is alive, reuse that watcher. If it is stale, delete the PID file and start a new watcher. - Agents MUST NOT start a second watcher for the same repository while a live PID is already recorded.
- If the watcher exits unexpectedly, agents should restart it, refresh the PID file, and continue using the same repo-scoped convention.
- Alera runs a Rust layer under Flutter through
flutter_rust_bridgev2.rust/is a Cargo workspace whose root package is the FRB git libraryalera_native(cdylib/staticlib) and whose memberalera-cliis the terminal-host sidecar binary (see Process And Terminal Safety). The Flutter build plugin is atrust_builder/, and the generated Dart bindings atlib/src/rust/(committed, not regenerated in CI).RustLib.init()runs inlib/main.dartbeforerunApp. The FRB native build (cargo build --manifest-path rust/Cargo.toml, no-p) compiles only the rootalera_nativepackage, so it never drags in the sidecar's dependencies. - Git operations MUST go through the
GitBackendboundary (lib/src/shared/infra/git/), not by spawning thegitbinary viaProcessRunner. The production implementationRustGitBackendcalls the Rust API; local operations usegit2(libgit2) and onlycloneis delegated to thegitCLI (via thegit_cmdcrate) so the system credential helper keeps working. - Keep the
GitBackendinterface free of generated bridge types:RustGitBackendis the only place that importslib/src/rust/api/git.dart, and it translates the nativeGitErrorinto the domainGitExceptionhierarchy. Services depend onGitBackend; unit tests use the sharedFakeGitBackend(test/unit/fake_git_backend.dart). - After changing the Rust API surface (
rust/src/api), regenerate bindings withmake frb-generate(flutter_rust_bridge_codegen generate) and commit the result. Building the desktop app requires a Rust toolchain (rustup), pinned byrust/rust-toolchain.toml; CI installs it viadtolnay/rust-toolchain. The sharedrust/Cargo.lockis committed and the native hooks build with--locked, so a regenerated lock must stay complete for both crates.
When planning is needed, use a spec-driven development flow. Do not jump straight from a vague request to implementation if important product or technical decisions are still undefined.
- First clarify the desired behavior, success criteria, audience, inputs, outputs, constraints, and non-goals.
- Prefer discovering facts from the repository, environment, or existing documentation before asking the user.
- Ask targeted questions only for decisions that cannot be safely inferred.
- Convert ambiguous requests into explicit requirements before designing a solution.
- Define the implementation approach after the spec is stable.
- Identify affected interfaces, data flow, dependencies, storage, permissions, error handling, and compatibility constraints when relevant.
- Surface meaningful tradeoffs and choose a default when one option is clearly safer or simpler.
- Keep the design aligned with existing project conventions.
- Break the design into ordered, concrete tasks that can be implemented and verified.
- Include validation steps as first-class tasks, not as an afterthought.
- Present plans using the structure: spec, design, tasks, tests, and assumptions.
- Make the plan decision complete: another engineer or agent should be able to execute it without inventing missing requirements.
- Use the clipboard when it helps transfer commands, snippets, paths, reports, or other information to the user efficiently.
- Prefer native clipboard commands for the user's operating system:
- macOS:
pbcopyandpbpaste. - Windows PowerShell:
Set-ClipboardandGet-Clipboard. - Linux Wayland:
wl-copyandwl-paste. - Linux X11:
xcliporxsel. - WSL:
clip.exewhen copying content into the Windows clipboard is appropriate.
- macOS:
- Tell the user what was copied, especially when the clipboard content is long or operationally important.
- Avoid placing secrets, tokens, credentials, personal data, or destructive commands on the clipboard unless the user explicitly asks for it or the task clearly requires it.
- If clipboard tooling is unavailable or unsafe in the current environment, provide the exact command or content for the user to copy manually.
- Use Conventional Commit style for commit messages.
- Write commit messages and pull request titles in English unless the user explicitly requests another language.
- Commit messages and pull request titles MUST be lowercase.
- Prefer concise commit subjects that clearly describe the change, such as
fix: handle empty clipboard input,docs: update agent workflow rules, orchore: add repository instructions. - Keep pull request descriptions short and useful. Include a brief summary, validation performed, and any important risks or notes when relevant.
- Never add the agent as a coauthor, assisted-by, generated-by, or equivalent attribution in commits, pull requests, pull request descriptions, or related metadata unless the user explicitly asks for it.
- Keep changes scoped to the user request. Do not fold unrelated refactors into implementation work.
- This document SHALL remain organized with non-numbered section headers.
- Be direct and specific. Explain decisions, blockers, and verification results in practical terms.
- Do not hide uncertainty. If something is assumed, say so.
- Keep progress updates short but useful during longer work.
- When implementation is complete, summarize what changed, how it was verified, and any remaining risk or follow-up.
- Always read and edit files from the active working directory.
- Never follow absolute paths copied from another agent or another worktree unless they are revalidated in the current checkout.
- Before mutating git state, check for existing local changes and preserve user work.
- If
.git/index.lockexists, confirm no git process is active before removing it.
- Add comments only when they explain a non-obvious reason: safety, platform behavior, compatibility, release constraints, or a design-system rule.
- Keep comments brief. Do not narrate what the code already says.
- Do not hard-wrap Markdown prose. Keep each paragraph or list item on one line unless the line break is semantically meaningful.
- Preserve explicit line breaks in tables, code fences, lists, and generated templates where Markdown syntax requires them.
- Do not create vague modules named
helpers,utils,common,misc, or similar dumping grounds. - Name files and types after the domain concept they model, such as
workspace_folder_opener.dartorupdate_archive.dart. - If a file name starts feeling generic, split responsibilities before adding more code.
- Avoid files longer than 500 lines. When a file approaches that size, split it by concrete domain responsibility instead of adding more unrelated code.
- Flutter UI values MUST come from
AleraTokensandThemeData. - New UI code MUST NOT introduce ad-hoc visual literals for color, spacing, radius, duration, or typography when an existing token/theme value covers the role.
Colors.transparentMAY be used only for explicit transparent states.- Visible UI copy MUST use sentence case.
- The active app theme strategy SHALL remain dark-mode-only in this version.
- Typography MUST remain fixed to Inter for general text and JetBrains Mono for monospaced text.
- The canonical design-system reference is
docs/ui-styleguide.md. - Shared, reusable UI components live in
lib/src/design_system/, grouped by role and prefixedAlera. New screens MUST reuse these before introducing ad-hoc widgets; a genuinely new shared component belongs here, with a co-located*.preview.dart. - Design-system components MUST be presentational: data and callbacks in via parameters, no Riverpod reads and no native (
dart:io/dart:ffi) code, so they stay previewable. Wire providers in a thin feature-level wrapper instead. - Preview functions MUST use the
@AleraPreviewannotation (not the bare@Preview). Launch withflutter widget-preview start.
- Shortcut-able actions live in
lib/src/features/keyboard/domain/keyboard_action.dartas the single source of truth (id, label, group, per-platform defaults, allow-in-terminal flag). New shortcut-able actions MUST be added to that registry rather than wired through ad-hocShortcuts/CallbackShortcutswidgets. - Behavior is dispatched from one place:
KeyboardCommandDispatcher. Reuse existing controller methods and the shared dialog launchers inworkbench_dialog_launchers.dart; do not duplicate dialog flows. - Matching is centralized in
KeybindingResolverand consumed by exactly two call sites: the globalKeyboardShortcutsScope(shell-mounted) and theTerminalSurfaceonKeyEventhook (terminal-focused interception). Do not add a third matcher or a globalHardwareKeyboardhandler. - The
Modmodifier is platform-neutral (⌘ on macOS, Ctrl elsewhere). Use the canonical token form (Mod+Shift+BracketRight) in defaults; symbol aliases (,,[) are accepted at parse time. - Respect the
TerminalShortcutPolicysetting: underterminalFirst, only bindings withallowInTerminal: truemay intercept while a terminal is focused.
- Alera targets macOS, Windows, and Linux.
- Use
Platformchecks or framework abstractions for platform-specific behavior; do not assume POSIX paths or commands. - Use
pathpackage utilities for filesystem paths. - Keep terminal, process, workspace, updater, and release code explicit about platform support.
- UI shortcut labels must match the actual shortcut behavior for the current platform.
- Performance is a product requirement. UI changes must keep the Flutter frame pipeline responsive and avoid unnecessary rebuilds, layout churn, blocking I/O, and heavy synchronous work.
- Do not run expensive parsing, filesystem traversal, process output processing, hashing, serialization, or other CPU-heavy work on the main isolate when it can reasonably run in another isolate.
- Prefer isolate-backed workers,
compute, streamed processing, or incremental batching for work that can grow with repository size, terminal output size, release artifact size, or user data size. - Keep main-isolate work limited to UI state coordination and small transformations needed for rendering.
- When a main-isolate implementation is intentionally kept, document the reason in code or PR notes if the workload could plausibly become large.
- Treat shell and terminal behavior as user-visible product behavior.
- Do not assume a local shell exists when the code path could later support remote or constrained environments.
- Keep command execution behind
ProcessRunneror a similarly injectable boundary. - Tests for command construction should verify Windows, Linux, and macOS variants when behavior differs.
- Use the lowercase repository
makefilefor app/CLI debug workflows instead of keeping one-off commands in chat or local notes. Its debug targets must remain shell-neutral and route platform-specific behavior through Dart scripts undertool/debug/so they work from PowerShell 7 on Windows as well as Linux and macOS shells.make helplists available rules.make app-debugruns the Flutter app with the development CLI fallback (acargo runof the Rust sidecar),make cli-buildcompiles the RustaleraCLI sidecar (therust/alera-clicrate) with cargo,make app-debug-bundled-cliruns the app against the compiled sidecar,make host-debugruns the Rustalera terminal-hostin the foreground, andmake rust-testruns fmt/clippy/test for the crate. - When debugging persistent terminal behavior, inspect process separation with
make debug-processes; the UI process should be the Flutter app and the host process should bealera terminal-host. UseALERA_HOST_EMPTY_SHUTDOWN_SECONDS,ALERA_HOST_DETACHED_SHUTDOWN_SECONDS, andALERA_HOST_SCROLLBACK_BYTESwhen foreground host debugging needs non-default lifecycle or scrollback values. Usemake host-stoponly when intentionally ending the current debug host for this app id. - The shipped
aleraCLI / terminal-host sidecar is the Rust crate underrust/(rust/alera-cli, binaryalera). The native build hooks —linux/CMakeLists.txt,windows/CMakeLists.txt, and the macOS "Build Alera CLI Sidecar" Xcode phase — build it withcargo build --locked(Release app →--release, otherwise debug) and install the single binary intoresources/alera/alera[.exe]. The toolchain is pinned byrust/rust-toolchain.tomlandrust/Cargo.lockis committed; CI and the hooks build reproducibly with--locked. The Dart client-side and shared protocol files underlib/src/features/workbench/infra/terminal_host/stay active because they connect the app to the sidecar over the socket.
- Alera builds in two flavors selected by the
ALERA_FLAVORenvironment variable:dev(default) andrelease. - The
devflavor usesdev.leynier.alera.devas bundle identifier / GTKAPPLICATION_ID,alera-devas Windows/Linux binary name, andAlera Devas the display name in the Dock, taskbar, and window title. This lets a locally running dev build coexist with an installed release build without sharing user-data directories (which are keyed by bundle id / application id). - The
releaseflavor keeps bundle identifierdev.leynier.aleraand display nameAlera. Its on-disk executable isAleraon Windows (Alera.exe) and macOS (Alera.app, viaALERA_PRODUCT_NAME), while the Linux binary stays lowercasealeraby POSIX convention.desktop_updatercopies the macOS bundle todist/under the lowercase pubspec package name (alera.app), sorelease-cut.ymlrenames it toAlera.appbefore packaging the release tarball. The release flavor MUST be selected by CI for any artifact intended to be installed by an end user..github/workflows/desktop-build.ymland.github/workflows/release-cut.ymlsetALERA_FLAVOR: releaseat the job env level. - The makefile defaults
ALERA_FLAVORtodevand forwards--alera-flavortotool/debug/alera_debug.dart. The debug tool regeneratesmacos/Runner/Configs/Flavor.xcconfig(git-ignored) before eachflutter runand exportsALERA_FLAVORso the Windows/Linux CMake branches and the Dart-sidekAleraFlavorconstant agree.Flavor.example.xcconfigdocuments the dev-flavor values for reference. - Auto-update MUST remain disabled on dev builds regardless of any other flag. The guard lives in
effectiveAutoInstallEnabled(seelib/src/core/build_flavor.dart) and is applied byAleraUpdateConfig.fromEnvironment(). - The canonical flavor identity strings (
Alera,Alera Dev,dev.leynier.alera,dev.leynier.alera.dev, and therelease/devselectors) live inlib/src/core/build_flavor.dart. The macOS xcconfig generator intool/debug/alera_debug.dartimports them so the regeneratedFlavor.xcconfigcannot drift from the runtime Dart constants. - The generated
macos/Runner/Configs/Flavor.xcconfigreflects whatever flavor was most recently prepared bytool/debug/alera_debug.dart. If a contributor wants to rehearse a release build locally after running a devmaketarget, they MUST re-prepare the release flavor first (e.g.ALERA_FLAVOR=release make app-debug) or deleteFlavor.xcconfig— otherwiseflutter build macos --releasewill inherit the stale dev override.
- GitHub Actions work must follow
.github/AGENTS.md. - Release script work must follow
tool/release/AGENTS.md. - Stable auto-update MUST remain disabled until release builds are signed and notarized/trusted for the relevant platform.
- Release automation must publish drafts first, verify all required assets and update manifests, and only then publish public releases.
reference_projects/contains non-runtime references for agentic development and orchestration patterns.reference_projects/orcais the primary reference for ADE-style collaboration, contribution workflow, release gates, and agent-facing project guidance.- Reference projects MUST NOT become runtime dependencies of Alera.
- After every feature, refactor, fix, or infrastructure change, explicitly consider whether
AGENTS.md, nestedAGENTS.mdfiles,readme.md,docs/,.github/CONTRIBUTING.md,SECURITY.md, or release documentation need updates. - If documentation does not need updates, mention that decision in the final summary or PR notes when the change is user-visible, architectural, process-related, release-related, or contributor-facing.
- Keep documentation aligned with implemented behavior. Do not document planned behavior as active behavior.
landing/AGENTS.mdapplies underlanding/.test/AGENTS.mdapplies undertest/..github/AGENTS.mdapplies under.github/.tool/release/AGENTS.mdapplies undertool/release/.