@stonepandastudio/cairn 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +33 -22
  2. package/bin/cairn.js +5 -0
  3. package/lib/init.js +58 -14
  4. package/lib/render/cli.js +106 -0
  5. package/lib/render/engine.js +148 -0
  6. package/lib/render/index.js +210 -0
  7. package/package.json +2 -1
  8. package/presets/EXTRACTION.md +210 -0
  9. package/presets/README.md +86 -0
  10. package/presets/angular/code-guidelines.md +197 -0
  11. package/presets/angular/slots/architect-discussion-topics.md +10 -0
  12. package/presets/angular/slots/architect-mandatory-docs.md +5 -0
  13. package/presets/angular/slots/architect-references.md +4 -0
  14. package/presets/angular/slots/implementation-reference.md +34 -0
  15. package/presets/angular/slots/key-patterns.md +11 -0
  16. package/presets/angular/slots/plan-step-ordering.md +11 -0
  17. package/presets/angular/slots/review-checklist.md +16 -0
  18. package/presets/angular/variants/i18n-external-service.md +11 -0
  19. package/presets/angular/variants/i18n-glossr.md +63 -0
  20. package/presets/core/AGENTS.md +49 -0
  21. package/presets/core/README.md +35 -0
  22. package/presets/core/WORKFLOW.md +56 -0
  23. package/presets/core/agents/architect.md +269 -0
  24. package/presets/core/agents/developer.md +145 -0
  25. package/presets/core/agents/reviewer.md +167 -0
  26. package/presets/core/commands/_stub.md +7 -0
  27. package/presets/core/workflow.json +45 -0
  28. package/presets/drizzle/code-guidelines.md +33 -0
  29. package/presets/drizzle/slots/architect-discussion-topics.md +4 -0
  30. package/presets/drizzle/slots/architect-mandatory-docs.md +4 -0
  31. package/presets/drizzle/slots/implementation-reference.md +17 -0
  32. package/presets/drizzle/slots/key-patterns.md +7 -0
  33. package/presets/drizzle/slots/review-checklist.md +10 -0
  34. package/presets/nestjs/code-guidelines.md +273 -0
  35. package/presets/nestjs/slots/architect-discussion-topics.md +4 -0
  36. package/presets/nestjs/slots/architect-mandatory-docs.md +5 -0
  37. package/presets/nestjs/slots/architect-references.md +5 -0
  38. package/presets/nestjs/slots/implementation-reference.md +45 -0
  39. package/presets/nestjs/slots/key-patterns.md +11 -0
  40. package/presets/nestjs/slots/plan-step-ordering.md +12 -0
  41. package/presets/nestjs/slots/review-checklist.md +12 -0
  42. package/presets/nestjs/variants/validation-class-validator.md +120 -0
  43. package/presets/nestjs/variants/validation-zod.md +194 -0
  44. package/presets/nextjs/code-guidelines.md +45 -0
  45. package/presets/nextjs/slots/architect-discussion-topics.md +5 -0
  46. package/presets/nextjs/slots/architect-mandatory-docs.md +3 -0
  47. package/presets/nextjs/slots/architect-references.md +6 -0
  48. package/presets/nextjs/slots/implementation-reference.md +24 -0
  49. package/presets/nextjs/slots/key-patterns.md +8 -0
  50. package/presets/nextjs/slots/plan-step-ordering.md +11 -0
  51. package/presets/nextjs/slots/review-checklist.md +11 -0
  52. package/presets/react/code-guidelines.md +46 -0
  53. package/presets/react/slots/architect-discussion-topics.md +5 -0
  54. package/presets/react/slots/architect-references.md +5 -0
  55. package/presets/react/slots/implementation-reference.md +26 -0
  56. package/presets/react/slots/key-patterns.md +8 -0
  57. package/presets/react/slots/plan-step-ordering.md +9 -0
  58. package/presets/react/slots/review-checklist.md +10 -0
  59. package/presets/tailwind/code-guidelines.md +28 -0
  60. package/presets/tailwind/slots/implementation-reference.md +8 -0
  61. package/presets/tailwind/slots/key-patterns.md +5 -0
  62. package/presets/tailwind/slots/review-checklist.md +8 -0
  63. package/presets/typeorm/code-guidelines.md +329 -0
  64. package/presets/typeorm/slots/architect-discussion-topics.md +4 -0
  65. package/presets/typeorm/slots/architect-mandatory-docs.md +3 -0
  66. package/presets/typeorm/slots/implementation-reference.md +19 -0
  67. package/presets/typeorm/slots/key-patterns.md +8 -0
  68. package/presets/typeorm/slots/review-checklist.md +8 -0
@@ -0,0 +1,197 @@
1
+ # Code Guidelines
2
+
3
+ <!-- cairn preset: angular -->
4
+
5
+ * In angular templates use new template syntax instead of old `*ng` syntax.
6
+ * Unsubscribe from observables in `ngOnDestroy`
7
+ * Use standalone Angular components by default, refactor component to standalone if it's not standalone component
8
+ * Every utility function, model, constant or mapping function should stay in separated file.
9
+ * For file names use dash-case (Example: `my-long-module.module.ts`)
10
+ * Use Reactive Forms for any new forms.
11
+ * All data access is handled through dedicated services.
12
+ * Complex data manipulation is placed in utils files
13
+
14
+ ## Theming and Colors
15
+
16
+ The application uses a CSS variables-based theming system with the following architecture:
17
+
18
+ **Chain**: Global CSS Variables → SCSS Palette Variables → Abstract SCSS Variables → Component `.scss` files
19
+
20
+ ### Architecture Layers
21
+
22
+ 1. **Global CSS Variables** (`src/scss/themes/default/colors.scss`)
23
+ - Defines actual color values as CSS custom properties
24
+ - Example: `--fotofixer-color-primary: #00aabc;`
25
+ - Changing these allows dynamic theme switching without page refresh
26
+
27
+ 2. **SCSS Palette Variables** (`src/scss/themes/colors.scss`)
28
+ - Maps CSS variables to SCSS variables using `var()` function
29
+ - Example: `$fotofixer-color-primary: var(--fotofixer-color-primary);`
30
+ - **DO NOT import this file directly in component SCSS**
31
+
32
+ 3. **Abstract SCSS Variables** (`src/scss/themes/theme.scss`)
33
+ - Provides semantic/abstract names for colors
34
+ - Example: `$font-color-secondary: colors.$main-color-main-10;`
35
+ - **This is the only file you should import in component SCSS files**
36
+
37
+ ### Rules for Using Colors in SCSS Files
38
+
39
+ * **DO NOT** use hardcoded colors (e.g., `#ffffff`, `white`, `rgb(...)`)
40
+ * **DO NOT** use CSS variables directly (e.g., `var(--main-color-main-11)`)
41
+ * **DO NOT** import `colors.scss` directly
42
+ * **DO** import `theme.scss` using `@use` directive
43
+ * **DO** use abstract SCSS variables from `theme.scss`
44
+ * **DO** add new abstract variables to `theme.scss` if needed
45
+
46
+ ### Example Usage
47
+
48
+ ```scss
49
+ @use "themes/theme" as theme;
50
+
51
+ .my-component {
52
+ background-color: theme.$background-color-white;
53
+ border: 1px solid theme.$border-color-secondary;
54
+ color: theme.$font-color;
55
+
56
+ .secondary-text {
57
+ color: theme.$font-color-secondary;
58
+ }
59
+
60
+ .muted-text {
61
+ color: theme.$font-color-muted;
62
+ }
63
+
64
+ .primary-action {
65
+ background-color: theme.$fotofixer-color-primary;
66
+
67
+ &:hover {
68
+ background-color: theme.$fotofixer-color-hover;
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### Available Abstract Variables (from `theme.scss`)
75
+
76
+ **Primary Colors:**
77
+ - `$fotofixer-color-primary` - Main brand color (cyan)
78
+ - `$fotofixer-color-secondary` - Light brand color
79
+ - `$fotofixer-color-tetriary` - Very light brand color
80
+ - `$fotofixer-color-hover` - Brand hover state
81
+
82
+ **Background Colors:**
83
+ - `$background-color-main` - Main background (light gray)
84
+ - `$background-color-secondary` - Secondary background
85
+ - `$background-color-secondary-hover` - Secondary hover state
86
+ - `$background-color-white` - White background
87
+
88
+ **Font Colors:**
89
+ - `$font-color` - Main text color (black)
90
+ - `$font-color-navbar` - Navbar text
91
+ - `$font-color-secondary` - Secondary text (dark gray)
92
+ - `$font-color-muted` - Muted/disabled text (medium gray)
93
+ - `$invert-font-color` - Inverted text (white)
94
+
95
+ **Border Colors:**
96
+ - `$border-color` - Main border color
97
+ - `$border-color-secondary` - Secondary border (light gray)
98
+ - `$divider-color` - Divider lines (very light gray)
99
+
100
+ **Message Colors:**
101
+ - `$error-message-color` - Error text
102
+ - `$error-message-background-color` - Error background
103
+ - `$success-message-color` - Success text
104
+
105
+ **Other:**
106
+ - `$disabled-color` - Disabled state
107
+ - `$link-hover-color` - Link hover state
108
+
109
+ ## Component Selectors
110
+
111
+ * Do NOT use `app-` prefix for component selectors in new components
112
+ * Use descriptive, kebab-case selector names (Example: `popover`, `project-status-icon`, `connected-projects-popover`)
113
+ * Selector should match the component's purpose without generic prefixes
114
+
115
+ ## Translations and Internationalization
116
+
117
+ ### General Rules
118
+
119
+ * Always use translation keys for static text in templates.
120
+ * For dynamic text in templates use translation keys when possible. If not possible, add a comment explaining why.
121
+ * **Locale files are generated artifacts.** Never hand-edit them and never add a key to one to make a feature render — any manual change is destroyed by the next sync.
122
+
123
+ Where translations come from, and how new keys are submitted, is project-specific:
124
+
125
+ {{> slot: translation-source }}
126
+
127
+ ### Translation Key Naming Conventions
128
+
129
+ * Use PascalCase for naming translation keys.
130
+ * Key structure depends on context:
131
+ * **Common text (no specific context)**: Use 2 parts - `"Common.SaveButton"`, `"Common.CancelButton"`
132
+ * **Context-specific text**: Use nested structure - `"[PageName].[Subcontext].[TextDescription]"`
133
+
134
+ ### Examples
135
+
136
+ **Common keys:**
137
+ ```json
138
+ "Common": {
139
+ "SaveButton": "Save",
140
+ "CancelButton": "Cancel",
141
+ "Loading": "Loading..."
142
+ }
143
+ ```
144
+
145
+ **Page-specific keys:**
146
+ ```json
147
+ "DevicesTable": {
148
+ "Title": "Devices Table",
149
+ "Header": {
150
+ "CityColumn": "City",
151
+ "DeviceColumn": "Device"
152
+ },
153
+ "Button": {
154
+ "DownloadReport": "Download Report"
155
+ }
156
+ }
157
+ ```
158
+
159
+ **Message keys:**
160
+ ```json
161
+ "Messages": {
162
+ "Devices": {
163
+ "FailedLoadDevices": "Failed to load devices",
164
+ "FailedDownloadReport": "Failed to download report"
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Checking Existing Keys
170
+
171
+ Before creating new translation keys, check the existing English locale file for examples and to avoid duplication. Read it only — see the generated-artifact rule above.
172
+
173
+ ## Change detection
174
+
175
+ * **Match the strategy used by nearby/similar components.** The codebase mixes `Default` and `OnPush`; don't default to `OnPush` unless the surrounding components use it. Most page-level components currently use `ChangeDetectionStrategy.Default`.
176
+ * If you're adding a component to an area where everything is `Default`, use `Default`. If you're adding one next to `OnPush` components, use `OnPush`.
177
+ * Don't "upgrade" an existing component from `Default` to `OnPush` as a drive-by change — that's a focused refactor, not part of a feature plan.
178
+
179
+ ## Comments
180
+
181
+ * **Default to no comments.** Good names carry meaning; small functions are self-documenting.
182
+ * Only write a comment when the *why* is non-obvious: a hidden constraint, a subtle invariant, a workaround for a specific bug, behavior that would surprise a reader.
183
+ * Don't explain *what* the code does — identifiers and structure already do that.
184
+ * Don't reference task IDs, PR flows, or "added for feature X" in code comments — that context belongs in commit messages and PR descriptions, and rots as the codebase evolves.
185
+ * No multi-paragraph docstrings or multi-line comment blocks — one short line is the ceiling.
186
+
187
+ ## Constants
188
+
189
+ File name template: `xx-yy.constant.ts` for `XxYy` constant
190
+
191
+ Files with constants should be placed in the `constants/` folder within the corresponding module (see `ai/infrastructure/project-structure.md` for module details)
192
+
193
+ ## Enums
194
+
195
+ File name template: `xx-yy.enum.ts` for `XxYy` enum
196
+
197
+ Files with enums should be placed in the `enums/` folder within the corresponding module (see `ai/infrastructure/project-structure.md` for module details)
@@ -0,0 +1,10 @@
1
+ <!-- cairn preset: angular — fills {{> stack/architect-discussion-topics }} (A.3). -->
2
+ - **Ambiguities** — anything in the description that admits multiple reasonable interpretations
3
+ - **UX / design tradeoffs** — popup vs. page, tabs vs. stacked sections, inline vs. separate component
4
+ - **Integration tensions** — e.g. global company state vs. route-scoped company id
5
+
6
+ **Optional aid — `frontend-design` skill.** When the discussion hinges on a
7
+ visual/UX tradeoff, `frontend-design` can explore mockups. **Treat its output as
8
+ inspiration only** — it does not know this project's conventions (Material UI,
9
+ `theme.scss` variables, base classes, new template syntax, no `app-` prefix,
10
+ translation keys). Never feed its generated code into the plan.
@@ -0,0 +1,5 @@
1
+ <!-- cairn preset: angular — fills {{> stack/architect-mandatory-docs }} (A.2). -->
2
+ - `ai/infrastructure/code-guidelines.md`
3
+ - `ai/infrastructure/project-structure.md`
4
+ - `ai/infrastructure/patterns.md`
5
+ - `ai/infrastructure/mappers.md`
@@ -0,0 +1,4 @@
1
+ <!-- cairn preset: angular — fills {{> stack/architect-references }} (A.1). -->
2
+ - Frontend source files (components, services, base classes)
3
+ - The backend repo's context docs — entity definitions, business logic, controllers
4
+ - Backend source files, for API-shape confirmation
@@ -0,0 +1,34 @@
1
+ <!-- cairn preset: angular — fills {{> stack/implementation-reference }} in the core
2
+ developer. snap-proof/frontend/ai/agents/angular-developer.md has no block like
3
+ the nestjs one — it points at patterns.md + code-guidelines.md and stops.
4
+ This is a minimal synthesis from angular-developer + angular-reviewer; extend
5
+ it when a second Angular repo shows what is actually shared. -->
6
+
7
+ The authoritative source is `ai/infrastructure/code-guidelines.md`; the base-class
8
+ and header-flow catalogue is `ai/infrastructure/patterns.md`. Reminders:
9
+
10
+ ### Components
11
+ - Standalone components — no `NgModule` declarations block
12
+ - No `app-` prefix in the selector
13
+ - Match the change-detection strategy of nearby components
14
+ - Subscriptions collected in a `Subscription`, unsubscribed in `ngOnDestroy`
15
+ - Complex data manipulation goes in a `utils/` file, not inlined
16
+
17
+ ### Templates
18
+ - Control flow: `@if` / `@for` / `@switch` — never `*ngIf` / `*ngFor`
19
+ - Every `@for` carries a `track` expression
20
+ - Every static string is a translation key — no bare literals
21
+
22
+ ### Styles
23
+ - Only `theme.$variable` from `@use "themes/theme" as theme` — no `#hex`, `rgb()`, or CSS custom properties
24
+
25
+ ### Forms
26
+ - Reactive forms only — no `ngModel`
27
+
28
+ ### Files
29
+ - Models, enums, constants, and mapper functions each in their own kebab-case file
30
+ - `enums/`, `constants/`, `mappers/` folders per module
31
+ - Mapper shapes: `EntityResponse → Entity`, `Entity ↔ EntityForm`, `Entity → EntityPayload`
32
+
33
+ ### Build
34
+ - Run the project's production build before reporting completion; a failing build blocks the report
@@ -0,0 +1,11 @@
1
+ <!-- cairn preset: angular — fills {{> stack/key-patterns }} in the core architect
2
+ and developer. From architect-lead.md / angular-developer.md. -->
3
+
4
+ Canonical catalogue: **`ai/infrastructure/patterns.md`** — base classes, the
5
+ `x-admin-profile` header flow, routing. Plans should lean on these instead of
6
+ reinventing them.
7
+
8
+ Micro-level conventions (theming, translations, template syntax, change detection,
9
+ file naming): **`ai/infrastructure/code-guidelines.md`**.
10
+
11
+ Mapper conventions: **`ai/infrastructure/mappers.md`**.
@@ -0,0 +1,11 @@
1
+ <!-- cairn preset: angular — fills {{> stack/plan-step-ordering }} in the core
2
+ architect's Plan format. architect-lead.md gives no explicit ordering beyond
3
+ "each step leaves the app working"; this is a synthesis, refine against a
4
+ second Angular repo. -->
5
+ 1. Models, enums, constants, mapper functions
6
+ 2. Service methods (API calls, state)
7
+ 3. Component logic (`.ts`)
8
+ 4. Template (`.html`) and styles (`.scss`)
9
+ 5. Routing and module wiring
10
+ 6. Translation keys
11
+ 7. Context doc updates
@@ -0,0 +1,16 @@
1
+ <!-- cairn preset: angular — fills {{> stack/review-checklist }} in the core reviewer.
2
+ Verbatim from snap-proof/frontend/ai/agents/angular-reviewer.md § Dimension 2. -->
3
+
4
+ | New template syntax (`@if`, `@for`, `@switch`) — no `*ngIf`/`*ngFor` | `.html` files |
5
+ | `@for` always includes a `track` expression — missing `track` is a compile error in Angular 17+ | `.html` files |
6
+ | Standalone components — no `NgModule` declarations block | Component `.ts` files |
7
+ | Observables subscribed inside components are collected in a `Subscription` and unsubscribed in `ngOnDestroy` | Component `.ts` files |
8
+ | No hardcoded colors (`#hex`, `rgb()`, CSS custom properties) — only `theme.$variable` from `@use "themes/theme" as theme` | `.scss` files |
9
+ | No `app-` prefix in component selectors | Component `.ts` files |
10
+ | All static text in templates uses translation keys — no bare string literals | `.html` files |
11
+ | `src/assets/i18n/*.json` never hand-edited — autogenerated, replaced during localization — **blocking** if the diff touches these files directly | `src/assets/i18n/*.json` |
12
+ | Reactive forms only — no template-driven forms (`ngModel`) | Component `.ts` files |
13
+ | Complex data manipulation goes in `utils/` files, not inlined in components | Component `.ts` files |
14
+ | Mapper pattern respected: `EntityResponse → Entity`, `Entity ↔ EntityForm`, `Entity → EntityPayload` | `mappers/` files |
15
+ | Models, enums, constants, and mapper functions each in their own kebab-case file | Module folder structure |
16
+ | Enums in `enums/` folder, constants in `constants/` folder, mappers in `mappers/` folder | Module structure |
@@ -0,0 +1,11 @@
1
+ <!-- cairn variant: translation-source = external-service. Fills the
2
+ translation-source slot in presets/angular/code-guidelines.md.
3
+ In use by: snap-frontend. A third-party localization vendor owns the values. -->
4
+
5
+ ## slot: translation-source
6
+
7
+ Never add or update translation values for translation keys in `src/assets/i18n/*.json` files directly. These are autogenerated files that will be replaced by a third-party service during the localization process.
8
+
9
+ ### Checking Existing Keys
10
+
11
+ Before creating new translation keys, check existing keys in `src/assets/i18n/en-us.json` for examples and to avoid duplication.
@@ -0,0 +1,63 @@
1
+ <!-- cairn variant: translation-source = glossr. Fills the translation-source slot
2
+ in presets/angular/code-guidelines.md.
3
+ In use by: glossr-frontend. This project dogfoods the product. -->
4
+
5
+ ## slot: translation-source
6
+
7
+ **Glossr itself is the source of truth for all translations.** This project dogfoods the product: keys and values live in the Glossr instance at `glossr.stonepandastudio.com`, not in any file in this repo. There is no `en.json` — do not create one.
8
+
9
+ ### Where Translations Come From
10
+
11
+ Each app consumes Glossr differently:
12
+
13
+ | App | Mechanism | Files |
14
+ |---|---|---|
15
+ | `glossr-frontend` | **Pipeline pull.** `npm run glossr:pull` fetches the CDN and overwrites the locale files, one per target in `glossr.config.json`. | everything under `apps/glossr-frontend/src/assets/i18n/` |
16
+ | `glossr-admin` | **Runtime fetch.** `GlossrCdnTranslateLoader` requests `${translationUrl}/${lang}` on load. | none — no locale files on disk |
17
+
18
+ ### Translation Assets Are Generated — Never Touch Them
19
+
20
+ **Every file under `apps/glossr-frontend/src/assets/i18n/` is a build artifact.** The set is whatever `glossr.config.json` lists as targets (`en-us.json`, `ru-ru.json`, `pl-pl.json`, …) — treat the folder as generated, not the individual filenames, so adding a locale needs no change here.
21
+
22
+ The pipeline runs `npm run glossr:pull` and **replaces these files wholesale**. Consequences:
23
+
24
+ * **Never hand-edit them.** Any manual change is silently destroyed by the next pull — including "just adding the one key I need to see the UI render".
25
+ * **Never add a key to them** to make a new feature display real text. New keys go to `ai/tasks/GLO-[task]/keys.json` (see below) and reach the app only after a human imports the story and pulls.
26
+ * **Read-only reference is fine** — consult `en-us.json` to check whether a key already exists or to copy a naming pattern.
27
+ * **Ignore them when reviewing a diff.** A changed locale file is pull output, not authored work; it is neither a finding nor scope creep. The only locale-file change worth flagging is one made *by hand* in place of a `keys.json` entry.
28
+ * Adding a locale is a `glossr.config.json` change plus the app's language registration — the resulting `.json` is generated, so do not write it by hand.
29
+
30
+ ### Adding New Keys
31
+
32
+ The Glossr CLI is **pull-only** (`glossr --help` → `pull` is the only command), so new keys reach Glossr by manual import. A `push` command is planned; until it exists, keys accumulate in a per-story file and are uploaded once.
33
+
34
+ **One `keys.json` per story — not per step.**
35
+
36
+ ```
37
+ ai/tasks/GLO-[task]/keys.json
38
+ ```
39
+
40
+ Every step of a story writes into that same file:
41
+
42
+ * **File does not exist** (usually step 1) → create it, containing only that step's keys.
43
+ * **File already exists** (step 2+) → **merge** the new keys into it. Deep-merge the nested structure; keep every key earlier steps added. Never overwrite the file wholesale, and never create `keys-step-2.json` or similar.
44
+ * A step that introduces **no** new keys leaves the file untouched.
45
+
46
+ Shape: nested JSON matching the CDN payload, English values, PascalCase keys per the naming conventions below.
47
+
48
+ **Lifecycle:**
49
+
50
+ | When | What | Who |
51
+ |---|---|---|
52
+ | During each step | Create or merge into `keys.json` | developer agent |
53
+ | Story complete | Import `keys.json` into Glossr — **once, for the whole story** | human |
54
+ | After import | `npm run glossr:pull` | human |
55
+ | After pull | Commit the regenerated files in `assets/i18n/` | human |
56
+
57
+ The upload is deliberately deferred to story completion: a story's keys tend to churn across steps, and importing per-step would push keys into Glossr that a later step renames or drops.
58
+
59
+ **Consequence:** for the whole life of the story, the app renders raw key strings for its new keys. That is expected, not a bug — do not "fix" it by editing a locale file. `keys.json` is the durable, git-tracked record of what the story introduced, and it survives the pull that overwrites the locale files.
60
+
61
+ ### Checking Existing Keys
62
+
63
+ Check `apps/glossr-frontend/src/assets/i18n/en-us.json`. Do not use the root-level `all-keys-en.json` / `all-keys-en-admin.json` dumps as a reference — they are untracked one-off exports and already stale (`all-keys-en.json` is 27 keys behind `en-us.json`).
@@ -0,0 +1,49 @@
1
+ # `AGENTS.md`
2
+
3
+ <!-- cairn preset: core. Rendered from workflow.steps[] + the repo's tracker config.
4
+ The Workflow Example numbering, the Agent Profiles, and the tracker section
5
+ all come from config — which is what stops one repo's AGENTS.md drifting from
6
+ its own commands. -->
7
+
8
+ The agents in the **{{ project.assistantName }}** — a small multi-agent system that
9
+ runs {{ stack.0 }} feature work from brief to review.
10
+
11
+ ## High-Level Architecture
12
+
13
+ `{{ architectAgent }}` interprets the request, discusses it, and produces the plan.
14
+ `{{ developerAgent }}` implements the plan. `{{ reviewerAgent }}` checks the result
15
+ against the plan and the guidelines. Each runs in its own session.
16
+
17
+ **Workflow Example.** A task moves through these named invocations; you own the
18
+ transitions. Dispatch table: `ai/INITIAL_PROMPT.md`.
19
+
20
+ {{#each workflow.steps}}
21
+ {{ @index_1 }}. **`/{{ this.command }} {{ tracker.exampleKey }}-NNN 1`** — `{{ this.agentName }}`{{#if this.model}} ({{ this.model }}){{/if}} — {{ this.oneLine }}
22
+ {{/each}}
23
+
24
+ Informal engagement on a task defaults to the first step.
25
+
26
+ ---
27
+
28
+ ## Agent Profiles
29
+
30
+ {{#each agents}}
31
+ ### `{{ this.name }}`
32
+
33
+ Read `{{ this.doc }}` for the full role, workflow, tools, and instructions.{{#if this.note}} {{ this.note }}{{/if}}
34
+
35
+ {{/each}}
36
+
37
+ ---
38
+
39
+ ## Tracker
40
+
41
+ {{#if tracker.remote}}
42
+ `create_brief`, `enrich_description` and `plan_task` sync task state to the
43
+ `{{ tracker.exampleKey }}` project on {{ tracker.providerLabel }} as a side effect.
44
+ Mapping, sync points, stage names, and the `LOCAL-*` rule: `ai/WORKFLOW.md`. Manual:
45
+ `/{{ tracker.slug }}-status`, `/{{ tracker.slug }}-assign`.
46
+ {{else}}
47
+ No remote tracker (`tracker.provider` is `none`). A task is its `ai/tasks/[KEY]/`
48
+ folder; the sync steps are no-ops. See `ai/WORKFLOW.md`.
49
+ {{/if}}
@@ -0,0 +1,35 @@
1
+ # `presets/core`
2
+
3
+ Stack-agnostic content shared by every repo, whatever the framework: the agent
4
+ **role contracts**, the command-stub template, and the `WORKFLOW.md` / `AGENTS.md`
5
+ skeletons.
6
+
7
+ Extracted 2026-09-09 from `snap-proof/{backend,frontend}` (see `../EXTRACTION.md`).
8
+ These are **seeds** — no renderer consumes them yet. They are the canonical version
9
+ of scaffolding that currently exists as two hand-synced copies, already useful as a
10
+ reference to pull the copies back together by hand.
11
+
12
+ ## What lives here vs. in a stack preset
13
+
14
+ `core` holds the parts the backend and frontend agent docs share **verbatim modulo
15
+ two variables** — the workflow scaffold (`R.1`–`R.4`, `E.1`–`E.5`, Mode A / Mode B),
16
+ the report and plan-format templates, the "when to stop" lists. Measured 85–92%
17
+ identical across the two repos.
18
+
19
+ A stack preset (`../nestjs`, `../angular`) fills the slots these contracts declare:
20
+
21
+ | slot in a core agent | nestjs | angular |
22
+ |---|---|---|
23
+ | `{{> stack/review-checklist }}` | TypeORM / class-validator / `@ResponseMapper` rules | `@if`/`@for` / standalone / theme vars / i18n rules |
24
+ | `{{> stack/implementation-reference }}` | module / controller / service / entity / DTO / migration | component / template / SCSS / reactive-form |
25
+ | `{{> stack/key-patterns }}` | `project-structure.md` + `DATABASE_SCHEMA.md` pointers | `patterns.md` (base classes, `x-admin-profile`) pointers |
26
+
27
+ ## Variables
28
+
29
+ Placeholders the renderer substitutes per repo, from `workspace.json` + the repo's
30
+ `cairn.config.json`:
31
+
32
+ - `{{ architectAgent }}` / `{{ developerAgent }}` / `{{ reviewerAgent }}` — the persona names
33
+ - `{{ model }}` — the model the reviewer/QA agents require (`claude-sonnet-5`)
34
+ - `{{ step.fn }}` / `{{ step.command }}` — the workflow verb for a step (`code_review` vs `review_plan` is drift to be removed, not a variant)
35
+ - `{{ tracker.* }}` — provider, stage names, example issue key — for the sync sub-steps and `WORKFLOW.md`
@@ -0,0 +1,56 @@
1
+ # Task Workflow
2
+
3
+ <!-- cairn preset: core. Rendered from workflow.steps[] + the repo's tracker config.
4
+ With a remote tracker (jira-server / youtrack) the sync half renders; with
5
+ `tracker: none` only the local half does. Project-specific bits (a retrofit
6
+ procedure for pre-sync tasks, say) stay in the repo, outside this file. -->
7
+
8
+ A task lives in `ai/tasks/[KEY]/` as a set of step files:
9
+
10
+ | File | Written by |
11
+ |---|---|
12
+ | `brief-step-[N].md` | you — the raw ask, never modified after creation |
13
+ | `description-step-[N].md` | {{ architectAgent }} (Mode A) — the enriched brief |
14
+ | `plan-step-[N].md` | {{ architectAgent }} (Mode B) — the implementation plan |
15
+
16
+ `[KEY]` is the task folder name. Speculative or un-tracked work uses a `LOCAL-`
17
+ prefix so a folder name can never collide with a real issue key.
18
+
19
+ {{#if tracker.remote}}
20
+ ## Sync to {{ tracker.providerLabel }}
21
+
22
+ `ai/tasks/[KEY]/` mirrors to the `{{ tracker.exampleKey }}` project. The folder name
23
+ is the parent issue key; each step's child-issue key is stamped into the first line
24
+ of its `brief-step-[N].md`:
25
+
26
+ ```
27
+ <!-- {{ tracker.subtaskMarker }}: {{ tracker.exampleKey }}-4 -->
28
+ ```
29
+
30
+ Issue keys are project-sequential, not per-parent — a parent and child with
31
+ unrelated numbers is normal. The parent link is the tracker's own link, not the key.
32
+
33
+ **In scope:** a folder starting `{{ tracker.exampleKey }}-` whose step file carries
34
+ `{{ tracker.subtaskMarker }}` frontmatter. **Not in scope:** a `LOCAL-` folder — work
35
+ it locally, mention that once, never sync it.
36
+
37
+ ### Sync points (one-way: local → tracker)
38
+
39
+ | Command | Tracker actions |
40
+ |---|---|
41
+ {{#each workflow.steps}}
42
+ | `{{ this.fn }}(task, step)` | {{ this.trackerAction }} |
43
+ {{/each}}
44
+
45
+ Later stage moves (`{{ tracker.reviewStage }}` onward) are manual — the tracker UI,
46
+ `/{{ tracker.slug }}-status`, or `cairn tracker close-task`.
47
+
48
+ Everything goes through `cairn tracker <command> …` (or the vendored
49
+ `ai/scripts/*.js` shim). Credentials live in `.env` (gitignored).
50
+ {{else}}
51
+ ## No remote tracker
52
+
53
+ `tracker.provider` is `none` — the workflow steps that would sync are no-ops. A task
54
+ is exactly its `ai/tasks/[KEY]/` folder; there is nothing else to update. Pick any
55
+ stable `[KEY]` scheme (a sequential id, a sprint slug) and keep it consistent.
56
+ {{/if}}