This file explains the processes, expectations and tools of this project to AI agents. (It might contain some hints for humans as well ;) ).
See https://agents.md/ for details about this file type.
wire-server is a mono-repo Haskell project.
Services - which mostly serve HTTP requests - are located in services/.
Libraries are located in libs/. The new integration testsuite is in
integration/.
The fundamental idea is to have Polysemy effects for all behaviour and keep
the services shallow. Because we started to refactor in this direction, there's
still a lot of code around that does business logic in services. We slowly want
to migrate this.
The testsuite in integration/ is our current approach to integration tests.
We're migrating old integration tests from service Cabal sub-projects to it.
The development environment is based on Nix flakes. Entrypoint is the
flake.nix file. More Nix related code is in nix/.
All tools and dependencies are provided by the direnv environment. I.e. if
you're on a local machine (e.g. developer laptop) and the current working
directory is inside this project directory, then all required tools and
dependencies are automatically available in the environment.
Local agents (e.g. copilot-cli) will probably want to use this way.
In cloud environments or when direnv is not installed, nix develop starts a
shell with all required tools and dependencies.
To directly execute commands in this environment, run nix develop --command bash -c "<COMMAND>".
Remote agents will probably want to use this way.
- Create a
cabal.project.localwith optimization turned off to get faster feedback (improved compile times):make cabal.project.local - Align Cabal and Nix dependencies:
make regen-local-nix-derivations - Run formatter:
make format - Run linter:
make lint-all - Compile all Haskell packages (type check and see warnings):
make c | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building' - Compile a specific Haskell package (type check and see warnings):
make c package=<PACKAGE> | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building' - Compile all Haskell packages and run all unit tests:
make c test=1 | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building' - Load all Haskell packages in GHCI for faster feedback:
cabal repl all --enable-tests --enable-multi-repl- Reload inside GHCI (faster than starting a new session):
:reload
- Reload inside GHCI (faster than starting a new session):
- Load a single Haskell package in GHCI for faster feedback:
cabal repl <PACKAGE> --enable-tests- Reload inside GHCI (faster than starting a new session):
:reload
- Reload inside GHCI (faster than starting a new session):
- Run tests for a single package (alternatives):
make c package=<PACKAGE> test=1 | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building'cabal test <TESTSUITE> | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building'
Build and run tests for wire-subsystems (as exemplary Haskell package):
make c package=wire-subsystems test=1 | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building'
Build and run tests for wire-subsystems (as exemplary Haskell package)
directly with Cabal:
cabal test wire-subsystems | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building'
- Ensure that the whole project type checks
- Ensure that there are no compiler warnings
- Ensure that all unit tests are "green" (executed successfully) by running them
- Ensure that Cabal and Nix dependencies are aligned
- Ensure that the code is formatted according to our formatting rules
Ensure these after every change:
- Haskell code still type checks
- Unit tests of all changed packages are green
When finishing a task, fulfill all Quality expectations.
Do not run integration tests (e.g. make ci or Cabal testsuite names ending in
-integration) as these depend on specific environments/requirements.
Prefer record dot syntax over lenses, but not at all cost (i.e. only for the simple cases).
Build commands (e.g. make c, cabal build or cabal test) should always end
with this command line filter: | grep -vE 'Compiling|Linking|Preprocessing|Configuring|Building'. The filter ensures
that only relevant output is displayed.
For all code generated in this chat, adhere to the following guidelines:
- Always request and enforce secure coding practices directly.
- Example prompts to follow:
- “Generate a Python function to query a database using parameterized queries and no string concatenation.”
- “Write input validation code for usernames using a whitelist approach.”
- Do not accept vague prompts such as:
- “Write code to query a database.”
- “Generate authentication logic.”
- Never generate production secrets, API keys, credentials, personal data, or customer-identifying information.
- Always use placeholders (e.g.,
YOUR_API_KEY_HERE) or synthetic/anonymized data.
- Focus on narrow, well-defined tasks.
- Example: “Generate a secure password hashing function using Argon2id with parameters selected according to the OWASP Password Storage Cheat Sheet.”
- Reject overly broad requests like “Write a full secure authentication system.”
- Propose security requirements before generating code.
- Discuss alternatives, evaluate them, and provide a step-by-step implementation plan.
- Always reference frameworks, versions, and security guidelines.
- Example: “Use Flask 3.0 and follow OWASP secure coding practices.”
- Example: “Use your web framework’s built-in auto-escaping/output encoding to prevent XSS.”
- Example: “Sanitize user-provided rich HTML content on the client using DOMPurify before rendering.”
- Only use secure, widely adopted, actively maintained dependencies.
- Ensure libraries have no known high-severity CVEs.
- Example: “Suggest Node.js packages updated in the last 6 months.”
- Always include strict server-side validation.
- Error messages must be generic and never disclose sensitive details.
- Example: “Generate a file upload handler with size limits, MIME type checks, and safe error messages.”
- Exclude risky features unless explicitly requested.
- Example:
- Do not use
eval. - Do not disable SSL/TLS verification.
- Do not use
- Always generate tests verifying security protections.
- Integrate tests into CI/CD pipelines.
- Examples:
- “Write unit tests confirming rejection of invalid input and prevention of XSS.”
- “Generate a pytest suite covering edge cases, including malicious inputs.”
- Always justify security decisions in generated code.
- Example: “Explain how this code prevents SQL injection.”
- Example: “List all security measures in your code.”
- Do not assume inputs are safe.
- Explicitly include strict validation.
- Always use parameterized queries.
- Only fulfill narrowly scoped coding tasks.
- Example: “Generate input validation for email addresses only.”
- Reject broad, open-ended prompts like:
- “Write a secure web app.”
- Treat the first response as a draft.
- Accept refinements and improvements from the user.
- Example refinements:
- “Improve error handling to avoid information disclosure.”
- “Replace insecure library X with a more secure alternative.”