Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist
build
.svelte-kit
pnpm-lock.yaml
templates/.claude/
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ All notable changes to the netrock generator will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [0.9.2] - 2026-03-21

### Added

- `devops-engineer` agent for infrastructure implementation (Dockerfiles, Aspire, CI/CD, env vars)
- Agent escalation pattern: implementation agents stop and report to orchestrator after 3 failed attempts on out-of-scope issues
- Review conflict handling: `/address-review` now flags contradictory comments for user judgment
- Infra delegation pattern and autonomous behavior trigger in generated CLAUDE.md

### Fixed

- All 19 procedural skills now properly invocable (replaced `disable-model-invocation` with `user-invocable: true` and descriptions)
- Skill frontmatter standardized to `user-invocable` (hyphen) per Claude Code docs
- `security-reviewer` model changed from `sonnet` to `inherit` (matches session model)

## [0.9.1] - 2026-03-21

### Changed
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@netrock/core",
"version": "0.9.1",
"version": "0.9.2",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/manifests/claude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function registerClaudeManifest(): void {
// Agents (backend-relevant)
{ path: '.claude/agents/backend-engineer.md', templated: false },
{ path: '.claude/agents/backend-reviewer.md', templated: false },
{ path: '.claude/agents/devops-engineer.md', templated: false },
{ path: '.claude/agents/devops-reviewer.md', templated: false },
{ path: '.claude/agents/filemap-checker.md', templated: false },
{ path: '.claude/agents/product-owner.md', templated: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4012,6 +4012,7 @@ exports[`file list snapshots > full preset file list 1`] = `
[
".claude/agents/backend-engineer.md",
".claude/agents/backend-reviewer.md",
".claude/agents/devops-engineer.md",
".claude/agents/devops-reviewer.md",
".claude/agents/filemap-checker.md",
".claude/agents/product-owner.md",
Expand Down
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@netrock/web",
"private": true,
"version": "0.9.1",
"version": "0.9.2",
"type": "module",
"scripts": {
"dev": "vite dev",
Expand Down
1 change: 1 addition & 0 deletions templates/.claude/agents/backend-engineer.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ Fix failures. Loop until green. Never commit broken code.
- Check FILEMAP.md before modifying existing files
- Commit atomically: `type(scope): imperative description`
- No Co-Authored-By lines in commits
- If stuck after 3 attempts on an issue outside your scope (e.g., frontend type errors, infra config), stop and report the blocker to the orchestrator with what you tried
54 changes: 54 additions & 0 deletions templates/.claude/agents/devops-engineer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: devops-engineer
description: "Implements infrastructure changes - Dockerfiles, Aspire config, CI/CD workflows, health checks, env vars. Delegates to this agent for infra work that stays within deployment and orchestration files."
tools: Read, Grep, Glob, Edit, Write, Bash
model: inherit
maxTurns: 30
skills: infra-conventions
---

You are a senior DevOps engineer implementing infrastructure changes for a .NET 10 + SvelteKit application. The stack uses Aspire for local dev orchestration. Production deployment is platform-agnostic via Dockerfiles.

The full infrastructure overview is loaded via the `infra-conventions` skill. Refer to it for all patterns.

## First Steps

Before making any changes:
1. Read the relevant existing configuration files
2. Check `FILEMAP.md` for downstream impact if modifying existing files

## Scope

- Dockerfiles (backend and frontend)
- `.github/workflows/` CI/CD pipelines
- `MyProject.AppHost/Program.cs` (Aspire orchestration)
- `MyProject.ServiceDefaults/Extensions.cs` (shared OTEL/resilience config)
- `appsettings.*.json` (configuration changes)
- `deploy/` scripts and configuration
- Health check endpoints
- Environment variable plumbing

## Verification

After changes, verify as applicable:
```bash
# Docker builds
docker build -f src/backend/Dockerfile -t test-api .
docker build -f src/frontend/Dockerfile -t test-frontend .

# Aspire orchestration
dotnet run --project src/backend/MyProject.AppHost

# Backend build (if config changes affect it)
dotnet build src/backend/MyProject.slnx
```

## Rules

- Match existing patterns exactly - read sibling files first
- Check FILEMAP.md before modifying existing files
- Never expose secrets in Dockerfiles, CI logs, or config files
- Pin passwords and credentials explicitly - never let Aspire generate random ones
- Commit atomically: `type(scope): imperative description`
- No Co-Authored-By lines in commits
- If stuck after 3 attempts on an issue outside your scope (e.g., application service logic, frontend components, database schema changes), stop and report the blocker to the orchestrator with what you tried
2 changes: 1 addition & 1 deletion templates/.claude/agents/security-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: security-reviewer
description: "Reviews code for security vulnerabilities, auth bypasses, PII leakage, and OWASP risks. Use proactively when reviewing security-sensitive changes (auth, permissions, user data, API endpoints, middleware, cookies, tokens)."
tools: Read, Grep, Glob
model: sonnet
model: inherit
maxTurns: 20
skills: security-conventions
---
Expand Down
11 changes: 7 additions & 4 deletions templates/.claude/agents/test-writer.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
---
name: test-writer
description: "Writes tests for backend code. Delegates to this agent when tests need to be written alongside new features or changes."
description: "Writes tests for backend and frontend code. Delegates to this agent when tests need to be written alongside new features or changes."
tools: Read, Grep, Glob, Edit, Write, Bash
model: inherit
maxTurns: 30
skills: backend-conventions
skills: backend-conventions, frontend-conventions
---

You are a test writer for a .NET 10 project. You write tests that follow the project's established patterns exactly.
You are a test writer for a .NET 10 + SvelteKit project. You write tests that follow the project's established patterns exactly.

The convention reference is loaded via skill. The Testing section in `backend-conventions` covers test types, helpers, auth patterns, mock setup, and conventions in detail. Refer to it.
Both convention references are loaded via skills. The Testing sections in `backend-conventions` and `frontend-conventions` cover test types, helpers, auth patterns, mock setup, and conventions in detail. Refer to them.

## Process

Expand All @@ -18,6 +18,7 @@ The convention reference is loaded via skill. The Testing section in `backend-co
3. Write tests following the exact same structure and imports
4. Run the relevant test command to verify:
- Backend: `dotnet test src/backend/MyProject.slnx -c Release`
- Frontend: `cd src/frontend && pnpm run test`
5. Fix any failures. Loop until green.

## Rules
Expand All @@ -26,3 +27,5 @@ The convention reference is loaded via skill. The Testing section in `backend-co
- Never add test frameworks or packages without asking
- Cover the happy path and meaningful edge cases - not every permutation
- Backend: use `Result` pattern assertions (`result.IsSuccess`, `result.Error`)
- Frontend: mock only what's necessary, test behavior not implementation details
- If stuck after 3 attempts on an issue outside your scope (e.g., production code bugs, missing dependencies), stop and report the blocker to the orchestrator with what you tried
3 changes: 2 additions & 1 deletion templates/.claude/skills/add-aspire-dep/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add an infrastructure dependency to Aspire AppHost
user-invocable: true
---

Adds an infrastructure dependency to Aspire AppHost.
Expand Down
5 changes: 4 additions & 1 deletion templates/.claude/skills/add-background-job/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- @feature jobs -->
---
disable-model-invocation: true
description: Add a Hangfire background job (recurring or one-time)
user-invocable: true
---

Adds a recurring or one-time Hangfire background job.
Expand Down Expand Up @@ -39,6 +40,7 @@ internal sealed class MyCleanupJob(
```

Key conventions:

- Mark `internal sealed`, use primary constructor
- Descriptive `JobId` (kebab-case, e.g. `"expired-token-cleanup"`)
- `Hangfire.Cron` helpers: `Cron.Hourly()`, `Cron.Daily()`, `Cron.Weekly()`
Expand Down Expand Up @@ -88,4 +90,5 @@ backgroundJobClient.Enqueue<WelcomeEmailJob>(job => job.ExecuteAsync(user.Id, us
// Delayed
backgroundJobClient.Schedule<WelcomeEmailJob>(job => job.ExecuteAsync(user.Id, user.Email), TimeSpan.FromMinutes(30));
```

<!-- @end -->
3 changes: 2 additions & 1 deletion templates/.claude/skills/add-ci-area/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add a new project area to CI workflows
user-invocable: true
---

Adds a new project area to CI.
Expand Down
11 changes: 8 additions & 3 deletions templates/.claude/skills/add-email-template/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- @feature auth -->
---
disable-model-invocation: true
description: Add a transactional email template using Fluid (Liquid)
user-invocable: true
---

Adds a transactional email template using Fluid (Liquid).
Expand All @@ -24,8 +25,12 @@ Properties auto-map to snake_case Liquid variables (`OrderNumber` -> `order_numb

- `order-confirmation.liquid` - HTML body fragment (injected into `_base.liquid` via `{{ body | raw }}`):
```html
<h2 style="margin: 0 0 20px 0; font-size: 22px; font-weight: 700; color: #333333;">Order Confirmed</h2>
<p style="margin: 0 0 16px 0;">Your order <strong>{{ order_number }}</strong> totaling {{ total }} has been confirmed.</p>
<h2 style="margin: 0 0 20px 0; font-size: 22px; font-weight: 700; color: #333333;">
Order Confirmed
</h2>
<p style="margin: 0 0 16px 0;">
Your order <strong>{{ order_number }}</strong> totaling {{ total }} has been confirmed.
</p>
```
- `order-confirmation.subject.liquid` - Subject line (plain text, no HTML)
- `order-confirmation.text.liquid` - Plain text body (optional but recommended)
Expand Down
5 changes: 4 additions & 1 deletion templates/.claude/skills/add-env-var/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add an environment variable to backend or frontend
user-invocable: true
---

Adds an environment variable (backend or frontend).
Expand All @@ -12,6 +13,7 @@ Adds an environment variable (backend or frontend).
4. If it needs an Options class: use `/add-options-class`

<!-- @feature frontend -->

## Frontend-consumed variable

1. Add to `src/frontend/.env.example` (documentation with placeholder)
Expand All @@ -27,4 +29,5 @@ Adds an environment variable (backend or frontend).
4. Import: `import { PUBLIC_VAR } from '$env/static/public';`

> For secrets or keys that differ per environment (like Turnstile site keys), prefer runtime configuration via `$env/dynamic/private` with SSR layout data instead of build-time `PUBLIC_*` args.

<!-- @end -->
3 changes: 2 additions & 1 deletion templates/.claude/skills/add-options-class/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add a typed options/configuration class with validation
user-invocable: true
---

Adds a typed options/configuration class.
Expand Down
10 changes: 6 additions & 4 deletions templates/.claude/skills/add-permission/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- @feature auth -->
---
disable-model-invocation: true
description: Add a permission constant across backend and frontend
user-invocable: true
---

Adds a permission constant across backend and frontend.
Expand All @@ -19,10 +20,11 @@ Adds a permission constant across backend and frontend.
```
`AppPermissions.All` discovers permissions via reflection - no manual registration needed.
2. Add `[RequirePermission(AppPermissions.Orders.View)]` to the relevant controller actions
3. *(Optional)* Seed the permission for existing roles in `SeedRolePermissionsAsync()` in `src/backend/MyProject.Infrastructure/Persistence/Extensions/ApplicationBuilderExtensions.cs`
3. _(Optional)_ Seed the permission for existing roles in `SeedRolePermissionsAsync()` in `src/backend/MyProject.Infrastructure/Persistence/Extensions/ApplicationBuilderExtensions.cs`
4. Verify: `dotnet build src/backend/MyProject.slnx`

<!-- @feature frontend -->

**Frontend:**

5. Add matching constants to `src/frontend/src/lib/utils/permissions.ts`:
Expand All @@ -39,5 +41,5 @@ Adds a permission constant across backend and frontend.
```
8. If adding a sidebar nav item: add `permission: Permissions.Orders.View` to the nav item in `AppSidebar.svelte` - items are filtered per-permission, not as a group
9. Verify: `cd src/frontend && pnpm run test && pnpm run format && pnpm run lint && pnpm run check`
<!-- @end -->
<!-- @end -->
<!-- @end -->
<!-- @end -->
3 changes: 2 additions & 1 deletion templates/.claude/skills/add-rate-limit/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add a rate limit policy to an endpoint
user-invocable: true
---

Adds a rate limit policy.
Expand Down
3 changes: 2 additions & 1 deletion templates/.claude/skills/add-route-constraint/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Add a route constraint for path parameter validation
user-invocable: true
---

Adds a route constraint for validating string path parameters at the routing layer.
Expand Down
30 changes: 27 additions & 3 deletions templates/.claude/skills/add-test/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---
disable-model-invocation: true
argument-hint: "[unit|component|api|validator]"
description: Add tests following project test patterns
user-invocable: true
argument-hint: "[unit|component|api|validator|frontend-unit|frontend-component]"
---

Adds backend tests. Specify test type or infer from context.
Adds tests. Specify test type or infer from context.

## Unit Test

Expand Down Expand Up @@ -87,3 +88,26 @@ For FluentValidation rules without starting the test server.
}
```
3. Verify: `dotnet test src/backend/tests/MyProject.Api.Tests -c Release`

## Frontend Unit Test

For utility functions, state modules, and pure logic in `$lib/`.

1. Create `src/frontend/src/lib/{module}/{file}.test.ts` (co-located with source)
2. Import explicitly: `import { describe, it, expect, vi } from 'vitest'`
3. Default environment is `node`. For DOM tests, add `// @vitest-environment jsdom` at top of file
4. `restoreMocks: true` is configured globally - no manual cleanup needed
5. Verify: `cd src/frontend && pnpm run test`

## Frontend Component Test

For Svelte components with DOM interactions.

1. Create `src/frontend/src/lib/components/{feature}/{Component}.test.ts` (co-located)
2. Add `// @vitest-environment jsdom` at top of file
3. Mock SvelteKit modules as needed:
```typescript
vi.mock('$app/navigation', () => ({ goto: vi.fn(), invalidateAll: vi.fn() }));
vi.mock('$lib/paraglide/messages', () => new Proxy({}, { get: (_, key) => () => String(key) }));
```
4. Verify: `cd src/frontend && pnpm run test`
3 changes: 2 additions & 1 deletion templates/.claude/skills/address-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Read PR review comments from GitHub, evaluate, address, and reply
user_invocable: true
user-invocable: true
argument-hint: '[PR number]'
---

Expand Down Expand Up @@ -68,6 +68,7 @@ Do NOT resolve threads that need further discussion from the reviewer.
- Reference specific commits when you make a change
- If a change requires a migration, new endpoint, or significant scope: discuss before implementing
- Never resolve a thread without either fixing the code or explaining why no change is needed
- If review comments contradict each other, flag the conflict for the user instead of trying to satisfy each of them
- Group related fixes into a single commit when they address the same concern
- Run `/verify` before pushing
- No em dashes in replies
3 changes: 2 additions & 1 deletion templates/.claude/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
disable-model-invocation: true
description: Create a GitHub issue with labels and optional sub-issues
user-invocable: true
---

Creates a GitHub issue.
Expand Down
Loading
Loading