Skip to content

Latest commit

 

History

History
230 lines (174 loc) · 8.67 KB

File metadata and controls

230 lines (174 loc) · 8.67 KB

CLAUDE.md

Operating instructions for Claude Code (and other AI agents) working in this repository. Audience is the agent, not human contributors — for human-facing documentation see README.md.

When the instructions here conflict with the user's global ~/.claude/CLAUDE.md, this file wins — project-specific rules override the global defaults.

Project overview

ai-lib is a shared catalog of AI assistants for the Danish public sector. The application is a Symfony 8 web app built on the ITK Dev Docker development setup.

Tech stack

  • PHP 8.4 running under phpfpm (Symfony 8 skeleton, PSR-4 App\\ at src/).
  • Nginx in front of phpfpm, served via the shared Traefik proxy at https://ai-lib.local.itkdev.dk.
  • MariaDB for persistence.
  • Mailpit for outbound mail capture at https://mail-ai-lib.local.itkdev.dk.
  • ITK Dev Docker template symfony-8 provides the container orchestration.

Project structure

bin/                Symfony console entry
config/             Symfony configuration (bundles, packages, routes, services)
public/             Web root (public/index.php)
src/                Application code (PSR-4 namespace App\)
assets/             Frontend entry points (placeholder until a stack is picked)
.docker/            nginx config and templates
.github/workflows/  CI workflows (do NOT edit locally — see "Workflows" below)
docs/adr/           Architecture Decision Records (see "ADRs")

Execution policy

All language/build tooling runs inside containers. Never invoke php, composer, node, npm, npx, prettier, or similar on the host.

Preferred order:

  1. task <name> — the project's Taskfile.yml is the entry point for everyday commands. Run task --list to see what's available.
  2. task compose -- <args> / task compose-exec -- <args> — pass-through helpers when no dedicated target exists.
  3. itkdev-docker-compose <command> — for cross-project ITK Dev tooling not wrapped by the project Taskfile (e.g. traefik:start).
  4. docker compose --profile dev run --rm <service> <args> — direct fallback for the dev-only tooling (prettier, markdownlint) when going around the Taskfile is justified.

Common commands

# Lifecycle
task start                          # pull, up, composer install
task down                           # tear the stack down

# Composer / PHP / Symfony console
task composer -- <command>          # e.g. task composer -- require foo/bar
task compose-exec -- phpfpm php <command>
task console -- <command>           # e.g. task console -- cache:clear

# Coding standards (check / apply pairs)
task coding-standards-php-check
task coding-standards-php-apply
task coding-standards-twig-check
task coding-standards-twig-apply
task coding-standards-yaml-check
task coding-standards-yaml-apply
task coding-standards-markdown-check
task coding-standards-markdown-apply
task coding-standards-composer-check
task coding-standards-composer-apply

# Run every check at once
task coding-standards-check

# Tests
task test                           # PHPUnit, no coverage
task test-coverage                  # PHPUnit + Xdebug coverage, enforces 100% gate

The coverage gate is 100% and is enforced by the Tests GitHub Actions workflow on every pull request — see .github/workflows/tests.yaml.

Run the matching check before committing changes in that area. For commands without a dedicated task, fall back to task compose -- <args> or itkdev-docker-compose <args>.

Coding standards

Config files live at the repo root:

  • .php-cs-fixer.dist.php — PHP CS Fixer (Symfony ruleset).
  • .twig-cs-fixer.dist.php — Twig CS Fixer.
  • .prettierrc.yaml — Prettier (YAML, CSS/SCSS, JS).
  • .markdownlint.jsonc + .markdownlintignore — Markdown lint.

These come from the symfony-8 template — don't edit them without a reason. If a project-specific override is needed, override via the template's documented mechanism (e.g. .php-cs-fixer.php next to .php-cs-fixer.dist.php).

Controllers stay thin

Controllers handle routes and template/response rendering only — no business logic. Push logic into a service class. A controller action looks like: inject service → call service method → return render() / Response / RedirectResponse.

Service classes are fully documented

Every service class method (public, protected, private) carries a PHPDoc block with a one-line summary, a description of intent, @param per parameter, @return, and @throws for every exception that can be raised.

Workflows

The .github/workflows/*.yaml files are mirrored from itk-dev/devops_itkdev-docker and carry a Do not edit this file! header. If a workflow needs to change, open a PR upstream rather than patching locally.

Branching and PRs

  • Base branch for feature work: develop. main is the release/stable line.
  • Branch name: feature/issue-<n>-<short-slug> (e.g. feature/issue-5-claude-md).
  • One issue per branch where possible. Reference the issue number in the branch name and PR.
  • PR target: develop.
  • A PR must:
    • Link the issue with Fixes #<n> (or Closes #<n> for non-bug issues). Use Refs #<n> when coverage is partial.
    • Pass all required CI checks before merging.
    • Carry a CHANGELOG.md update under ## [Unreleased] for any user-visible change.

Commits

Use Conventional Commits:

  • feat: new feature
  • fix: bug fix
  • docs: documentation only
  • chore: tooling, build, deps, repo housekeeping
  • refactor: code change that neither adds a feature nor fixes a bug
  • test: tests only

Keep subject lines under ~70 characters. Use the body for the why.

CHANGELOG

CHANGELOG.md follows Keep a Changelog. Add an entry to ## [Unreleased] under the right section (Added, Changed, Fixed, Removed, Deprecated, Security) for every meaningful change.

GitHub issue types and labels

Every issue must have its native issue type set to one of:

  • Bug — something is broken.
  • Feature — new user-visible capability.
  • Task — everything else: chores, tooling, documentation, infrastructure, refactors, ADRs, etc.

Documentation-only work is tracked as a Task type plus the documentation label. The type classifies the nature of the work, labels add orthogonal context.

The current gh CLI (≤ 2.92) does not expose --type. To set a type, fall back to the REST API (PATCH /repos/{owner}/{repo}/issues/{n} with type=<Name>) when available, otherwise ask the user to set it in the UI. Labels can always be set with gh issue create --label.

Pushing

SSH keys aren't available to the Claude session. Push one-off via HTTPS:

git push https://github.com/itk-dev/ai-lib.git HEAD:<branch>

Do not change the origin remote URL — SSH is wanted for normal use outside Claude.

ADRs

Architectural decisions are recorded as ADRs in docs/adr/. Create and manage them via the itkdev-adr skill (see issue #11). Open an ADR for decisions that:

  • Change the runtime architecture (storage, integrations, deployment).
  • Choose between two viable options with non-trivial trade-offs.
  • Establish a convention other contributors must follow.

Small implementation choices belong in code review, not in an ADR.

Do not include a "Follow-up Actions" (or similarly named) checklist inside an ADR. Track follow-up work as GitHub issues and reference the ADR from each issue, not the other way around. The ADR records the decision; the issues track the work derived from it. The one-time cleanup of existing sections is tracked in #44.

Domain glossary

  • Assistant — a configured AI persona/prompt bundle that can be exported, shared, and re-imported.
  • Catalog — the searchable collection of assistants surfaced by the app.
  • OpenWebUI export format — the JSON schema used by OpenWebUI for importing/exporting assistants; the canonical interchange format for this project.
  • Share/upload flow — the moderated path by which a user submits an assistant to the catalog (metadata + review).
  • Tags / categories — taxonomy applied to assistants for filtering and discovery.
  • Moderation — validation and review of submitted assistants before they appear in the catalog.

When in doubt

  • Prefer an existing pattern in the codebase over inventing a new one.
  • For non-trivial decisions, write an ADR or ask the user — don't silently pick.
  • For destructive git operations (reset --hard, push --force, branch deletion), stop and ask the user — these are deny-listed globally for good reason.