# Shared rules Rules that apply to both backend and frontend work in this repository. Stack-specific guides (`backend-context.md`, `frontend-context.md`) extend these rules. ## Project state - Attainly is in early development. - Attainly helps users break hierarchical goals into scheduled assignments, complete daily work, and track progress toward a target date. - Sets define explicit ordered element levels. Every depth has one kind, and a kind can appear at only one depth within a set. Root elements use the first level, and children use the level immediately after their parent. - Schedules target whole sets. Users choose a set level as the assignment granularity. To schedule a subset, create a separate named set containing that subset. - Schedules are immutable historical snapshots. Copy the set name and each assignment's name, kind, and full path when creating a schedule. - Persisted schedules must not reference their source set or selected level. Persisted assignments must not reference their source elements. Later source edits or deletions must not change an existing schedule. - Schedule recalculation must preserve completed work and the schedule's original start date. Treat the requested start as the boundary for redistributing unfinished assignments, and update the target date. - Planned features in `README.md` are future ideas, not authorized scope. - The Laravel backend exists under `backend/`. - The standalone Vue frontend exists under `frontend/website/`. - Keep the frontend independent from the backend. Do not add backend-driven rendering, asset delivery, or build integration unless the user explicitly asks for it. - PostgreSQL is the development and runtime database. - PHPUnit uses in-memory SQLite for isolated tests. ## Process (TDD) 0. Before editing any file, ensure you are working in a dedicated git worktree, not the main checkout (`git status` and `git worktree list`). If on `master`/`main` or in the main working directory, create a worktree first (see Branching). 1. Write the test first. 2. Run the test to confirm it fails for the expected reason. 3. Commit the failing test. The test commit must precede the implementation commit, not merely appear earlier in the implementation diff. 4. Implement the smallest change that makes the test pass. 5. Run the test to confirm it passes. 6. Commit the implementation. 7. Repeat for each new behavior. Use judgment for changes that cannot meaningfully be test-driven, such as documentation-only edits or declarative environment configuration. Validate those changes with the most relevant parser, formatter, dry run, or check. ## Maintaining these instructions - Treat user steering as durable when it corrects or establishes a reusable project rule for workflow, architecture, conventions, validation, safety, or scope. - When durable steering is received during work, update the appropriate `ai/*.md` file in the active worktree before completing the task. Do not wait for a separate request to maintain the instructions. - Put repository-wide rules in `shared.md` and stack-specific rules in the matching backend or frontend guide. - Merge new guidance into the existing rule set. Keep it concise, remove duplication, and resolve conflicts between shared and stack-specific text. - Do not persist task-specific scope, temporary directions, secrets, environment incidents, or instructions that conflict with higher-priority guidance. - Commit a durable instruction update separately from implementation unless the task itself is solely an instruction change. ## Approval discipline - Treat dependency installation, tests, static analysis, formatting, linting, type checking, and builds as routine project operations. Run them without asking for advance approval when they stay within the requested scope and sandbox boundaries. - If an essential operation is blocked by sandbox or network policy, batch the necessary provisioning or validation into one narrowly scoped approval request. Prefer a reusable command prefix when it can be safely limited to the required tool and operation. - Do not request repeated approvals for commands that fit a previously approved scope. - Do not prefix routine commands with per-command cache environment overrides. Configure cache locations once in Codex, direnv, or the project environment. Use temporary overrides only to diagnose a cache-specific problem. - Truly destructive actions, external writes, main-stack control, and operations outside the workspace still require explicit approval. ## Running processes - The main checkout owns the canonical stack on the default ports. Assume it is the user's stack. Do not start, restart, or stop it unless the user asks. - A worktree owns its own isolated stack. The flake shell hook assigns a deterministic port offset and creates worktree-local PostgreSQL state. - Start a worktree stack only when runtime or integration validation requires it. Start it once, reuse it throughout validation, and stop it once when finished. - PHPUnit, frontend formatting, linting, type checking, and production builds do not require services. The Cypress completion suite does require the worktree stack. - When worktree stack control is necessary, operate it directly. Do not ask the user to start or stop worktree services. - Never use `process-compose -t=false` for a detached stack. It can leave an orphaned PostgreSQL process holding the data directory. - Non-interactive agent shells do not automatically load direnv. Bare project commands can use missing tools, default ports, or paths from the main checkout. - Run PHP, Composer, Artisan, npm, tests, builds, database clients, and services through the development environment. - Resolve the direnv target from the worktree containing the current working directory. Never target the main checkout or a different worktree: ```sh direnv exec "$(git rev-parse --show-toplevel)" ``` - Git and environment-neutral read-only inspection do not need direnv. - Start and stop a worktree stack from its root: ```sh direnv exec "$(git rev-parse --show-toplevel)" process-compose up -D direnv exec "$(git rev-parse --show-toplevel)" process-compose down ``` - Run backend commands from `backend/` and frontend commands from `frontend/website/`. The direnv target remains the worktree root. - When a normally valid check fails because a required service is down, surface the environmental failure. Do not skip the check, change databases, or claim the work is complete. - PHPUnit is self-contained and uses in-memory SQLite. It does not require the PostgreSQL stack unless a future test explicitly targets real PostgreSQL. ## Code style - Keep lines at or below 80 columns where practical. Do not split short, readable lines unnecessarily. - Use explicit, descriptive variable names. Do not use single-letter or unexplained abbreviated names. - Explore the codebase and inspect similar files before implementing a new pattern. - Never use em dashes in code, comments, or docblocks. Use hyphens. - Always use braced control-statement bodies, including early returns: ```ts if (identifier === null) { return null } ``` ## Git commit style - Use present-tense, imperative subjects: `add`, `create`, `wire`, `fix`, `test`. - Keep subjects lowercase and short, normally three to six words. - Match patterns in the existing git history. - Do not add AI or tool coauthor trailers. - Add a body when the subject cannot explain non-obvious motivation or multi-file coordination. - Wrap bodies at approximately 72 columns and separate them from the subject with a blank line. ## Git commits - Commit tests before implementation. - Keep one logical change per commit. A logical change may span multiple files. - Commit each meaningful step rather than batching unrelated work. - Do not include drive-by formatter or linter changes. Restore them or land them as a separate formatting commit. - If a check fails on untouched code, do not bundle an unrelated fix. Report the baseline failure or handle it as its own explicitly scoped change. ## Branching - Never implement features directly in the main checkout or on `master`/`main`. - Use a dedicated worktree under `/.worktrees/`. - Create it with: ```sh git worktree add \ "$(git rev-parse --show-toplevel)/.worktrees/" \ -b ``` - Use descriptive kebab-case branch names, optionally prefixed with a type such as `feature/` or `fix/`. - Keep worktree names short, preferably no more than about 20 characters. PostgreSQL Unix socket paths are limited in length. - Provision a fresh worktree through direnv: ```sh direnv allow direnv exec true ``` - Never symlink `backend/vendor` or `frontend/website/node_modules` from another checkout. Dependencies and generated files must remain worktree-local. - The shell hook installs backend dependencies but not frontend dependencies. Install frontend dependencies from `frontend/website/`: ```sh direnv exec "$(git rev-parse --show-toplevel)" npm install ``` Do not push anything. Make commits as the TDD workflow requires. ## Before completing a change A change is not complete until the worktree stack is ready and the unified gate passes against that worktree: 1. Start the stack detached from the worktree root: ```sh direnv exec "$(git rev-parse --show-toplevel)" \ process-compose up -D ``` 2. Poll `process-compose process list` until every process is running and ready. 3. Run the complete gate from the worktree root: ```sh JUST_JOBS=4 direnv exec "$(git rev-parse --show-toplevel)" just test-all ``` 4. Do not hand-assemble a substitute from focused commands. `test-all` runs one pool of 13 jobs: frontend format, lint, type, build, and Cypress groups; Larastan; the PHPUnit Unit and Feature suites; and the Cypress spec coverage guard. Jobs report as they finish, failed output is buffered and printed at the end, and every job runs even after another job fails. `JUST_JOBS` limits concurrency and defaults to 4. Use 2 when resources are constrained or 1 for a serial debugging run. 5. Everything must pass before completion. Report exact baseline or environmental failures rather than hiding them. 6. If the stack was started only for validation, stop it when finished: ```sh direnv exec "$(git rev-parse --show-toplevel)" process-compose down ``` Focused `just` recipes are for iteration only. For Nix or shell-hook changes, also run `nix fmt` and `nix flake check`. For service configuration changes, also run `process-compose --dry-run`.