A Claude-native team workflow.
Engineer at Nomain.
We turn complex mainframe systems into clear, accessible knowledge — so engineers, analysts and business stakeholders can all understand legacy code, onboard faster, and plan modernization with confidence.
Come build the agent that powers all of this. Find me after, or scan at the end.
Not a framework. Not best practices. Just the workflow we converged on since we switched to Claude in December — what we share, where we put it, and how a ticket flows from Linear all the way to production telemetry.
We switched to Claude in December. Every engineer is now running their own Claude — often several in parallel, across worktrees and background tasks. Without something shared, those agents make different decisions on the same problem: different naming, different test patterns, different log levels, different security assumptions.
So the real question stopped being how do I prompt better. It became what do all our agents need to know, and where does it live? Everything below is what we've built up since.
Backend services, web apps, the VS Code extension, infrastructure, docs, eval datasets — all in one repo. So whichever feature an engineer is touching, their Claude has the full picture available in one place.
It also gives us a single, obvious home for the shared substrate: CLAUDE.md at the root, skills and agents under .claude/ — read by every session, from every corner of the codebase.
Our conventions exist because they're right for the problem — conv commits, xUnit v3, our audit-logging boundary, our Linear taxonomy, our LADR format. Every skill, CLAUDE.md entry and hook exists to teach the model how we work, so it contributes without dragging the codebase toward its training defaults.
The flip side would be picking tools because Claude prefers them, or quietly relaxing our standards because the model keeps drifting from them. We try hard not to.
Claude reads from two places: your personal home folder (~/.claude/ on your machine), and a .claude/ folder inside the repo. The personal one is invisible to teammates — so the split is explicit:
~/.claude/ — personal taste, individual memoryCLAUDE.md — facts every agent needs at startup.claude/skills/ — repeatable team workflows.claude/agents/ — narrow-domain subagentsThings we'd otherwise re-explain in every conversation, or things a new hire would get wrong without being told. We keep it short and curated — it's a system prompt, not a wiki.
We work in a monorepo, so the root CLAUDE.md covers cross-cutting rules. Subprojects can add their own CLAUDE.md for context Claude only needs when working in that subtree.
Three real entries from the root →
xUnit v3: dotnet test silently does nothing. Use dotnet run --project. Saves the agent a 5-minute dead end every time.
Tenant lifecycle, admin actions, auth events → IAuditLogger, not ILogger. Different EventId range, 12-month retention.
Conventional commits. No customer data. Co-author trailer for Claude. --no-verify is forbidden unless asked.
/manage-issue/implement-issue-tdd/qa-evaluation (agent changes)/mr-ready + mr-reviewer/triage-ast, /triage-analysis/usage-analytics, /agent-analyticsEach step is a skill — a markdown file with a procedure, invoked by name. The procedure itself is what we review and iterate on, not the prompts people happen to type.
Calls the Linear MCP, but the skill is mostly a markdown reference doc: our team IDs, label taxonomy, severity ladder, "definition of ready", which team owns what.
Without it the model invents reasonable-looking labels that don't exist, picks the wrong team, or writes acceptance criteria too vague for the next agent to act on.
Because everything lives in one repo, Claude has the actual code open while writing the ticket. Scope, acceptance criteria, and file references point at real classes — not what the model imagines exists.
Plans a test list up front, then drives Red → Green → Refactor cycle-by-cycle. Tests stay honest because they're written first.
Same setup (branch, plan, approval) without the strict TDD loop — for changes where TDD doesn't fit.
From there, Claude reaches for the right companion based on what we're working on:
/qa-evaluation — agent prompt & tool changes; can self-run and iterate/ladr — capture an architecture decision/local-db — explore the local Postgres knowledge graph/aspire — run, debug, inspect the distributed appiac-expert subagent + /bicep-config, /cicd-pipelines, /add-new-environment — anything in iac/ or .gitlab/Builds, runs tests, commits with conv-commit, pushes, opens the MR using our GitLab template. Then starts a 4-minute /loop to watch the pipeline and new review threads.
A GitLab CI job (mr-claude-review.yml) invokes the mr-reviewer subagent on every MR. It posts each finding as a separate resolvable thread with severity prefixes (blocker:, fix:, nit:) — landed on after our first version dropped one wall-of-text comment nobody read.
When the monitoring loop spots new threads — from CI or human reviewers — it delegates back to mr-reviewer in Address mode. The agent triages each thread, presents its plan, and only changes code with explicit approval. It never resolves threads — only the developer does.
/triage-ast and /triage-analysis pull recent logs from Azure Log Analytics, cluster recurring failures, and offer to file Linear tickets — with the cluster signature in the body so duplicates collapse.
/usage-analytics wraps the KQL we kept rewriting by hand — active tenants, message volume, token spend, Deep Insights usage.
/agent-analytics looks at our own agent in production — tool-call distributions, latency, answer-quality scores, failure modes. Findings often loop straight back into a new /qa-evaluation dataset.
Each one is just a procedure one of us did manually, written down so nobody has to remember it again.
Skills, CLAUDE.md, agents — every convention you encode compounds across the team.
christian.moller@nomain.com
We're hiring an AI Engineer
assets.nomain.com/careers