Contributing (Technical)¶
Thanks for helping build WorkWingman. This page covers the dev loop, the mandatory review gate, coding conventions, and the CI gates a change has to clear.
Dev setup¶
Follow getting-started.md first: install the prerequisites (.NET 10 SDK, Node 22.12+, Git), clone, run the three processes, and confirm both test suites pass:
dotnet test # 381 backend tests (xUnit)
cd frontend && npm test # frontend tests (Vitest)
Branch / PR flow¶
- Branch off the default branch. Never commit directly to
master/main. - Code the change. Keep the diff scoped; match the surrounding style (below).
/codex-review— run the mandatory second-opinion gate before you commit (below).- Commit once review is addressed.
- Open a PR.
- CI must be green before merge (below).
The mandatory /codex-review gate¶
Before committing, run /codex-review on your uncommitted changes. This is a
mandatory second-opinion gate, not a suggestion — it's a fresh reviewer looking for
bugs, security issues (OWASP Top 10), performance problems, and quality issues before your
change enters history.
- Run it on the uncommitted diff, read every finding, and either fix it or have a defensible reason not to.
- Only commit once the review is addressed.
- Treat "the gate passed" as a precondition for committing, the same way you'd treat "tests pass."
Coding conventions¶
Match the existing code. These are the patterns already in the tree — follow them rather than introducing new ones.
C# (Core, Infrastructure, Api)¶
- File-scoped namespaces (
namespace WorkWingman.Core.Models;). - Primary constructors for dependency injection
(e.g.
public class JobsController(IJobQueueService queue) : ControllerBase). recordtypes for DTOs — request bodies are records (e.g.public record ResolveRequest(string CallId, string Choice);).Corehas no infrastructure dependencies. Keep the dependency direction pointing inward towardCore. Put implementations inInfrastructure, interfaces inCore.- Enums serialize as strings; JSON properties are camelCase. Preserve this — the frontend depends on it.
- Comments explain WHY / constraints, not WHAT. The existing model and controller XML-doc comments are the standard: they capture intent and invariants (e.g. "Secrets themselves never leave the vault service"), not restatements of the code.
Angular (frontend)¶
- Standalone components (no NgModules) — Angular 22, under
src/app/features/<screen>. - Signals for reactive state.
- Shared services live in
src/app/core/. - See angular.dev for standalone + signals references.
The two-track docs rule¶
Docs live in two synchronized tracks:
docs/technical/— full detail for engineers.docs/plain/— everyday language with analogies, for everyone.
When you change code that these docs describe, update both tracks in the same PR. A change to an endpoint, a screen, or the setup flow should land with its doc updates so the two tracks never drift out of sync with the code or each other.
Honesty rule: document only what actually exists. Anything not yet built goes under a
## Roadmap heading and is clearly labeled as not-yet-working — never described as if it's
finished.
Keep out of git¶
Never commit:
bin/andobj/— .NET build output.*.kdbx— the KeePass vault file. It holds real secrets and must never enter history.
(Also avoid committing local data such as generated documents or the tracker database.)
CI gates¶
CI (.github/workflows/ci.yml) runs on pushes and PRs to master/main and must be green
to merge. Jobs include:
| Job | Runner | Steps |
|---|---|---|
| Backend (.NET) | windows-latest |
Set up .NET 10 → dotnet build --configuration Release → dotnet test (with test.runsettings). |
| Frontend (Angular) | ubuntu-latest |
Set up Node → npm ci → npm run build → npm test. |
| Docs (two-track + linked + fresh) | ubuntu-latest |
Pairing check (every technical/X.md ↔ plain/X.md, no exceptions — documentation of how WorkWingman works always gets both tracks; docs/reference/ is for point-in-time records, e.g. tenant validation runs and merge audits, and is not a way out of writing the plain track) → orphan check (every doc linked from the README table or another doc) → freshness gate: a change touching src/ or frontend/src/ without touching docs/ fails, unless the head commit says [skip docs] → advisory warning when a 500+-insertion change lands without a making-of story beat. |
| Diagrams (D2 up to date) | ubuntu-latest |
Rebuilds all D2 diagrams with the pinned Linux binary; on push it self-heals drift by committing the canonical render (D2 output is platform-dependent, so only CI's render is canonical), on PRs drift is a hard failure. |
The docs job makes the two-track rule and docs freshness a gate, not a convention: code
that changes behavior ships with its docs (and, for architecture moves, its diagram + a
making-of beat) in the same change. [skip docs] exists for pure refactors and mechanical
bumps — using it for a real behavior change defeats the point and will be caught in review.
Run dotnet test and npm test locally before pushing so you don't burn a CI cycle on a
failure you could catch in seconds.
Related docs¶
- Plain-language version: ../plain/contributing.md
- Getting started: getting-started.md
- API reference: api-reference.md
- Docs index: ../README.md