@_brenosiqueira/claude-skills 1.0.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.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # claude-skills
2
+
3
+ > Claude AI skills for software project documentation and sprint planning.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @claudeskills/core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Initialize skills in your project
14
+
15
+ ```bash
16
+ cd your-project
17
+ claude-skills init
18
+ ```
19
+
20
+ This creates `.claude/skills/` with all available skills:
21
+
22
+ ```
23
+ your-project/
24
+ └── .claude/
25
+ └── skills/
26
+ ├── project-docs/
27
+ │ ├── SKILL.md
28
+ │ └── references/
29
+ └── github-sprint/
30
+ ├── SKILL.md
31
+ └── references/
32
+ ```
33
+
34
+ ### Commands
35
+
36
+ ```bash
37
+ claude-skills init # Copy all skills to .claude/skills/
38
+ claude-skills init -s project-docs # Copy only one skill
39
+ claude-skills list # Show available skills and install status
40
+ claude-skills add github-sprint # Add a specific skill
41
+ claude-skills show project-docs # Print SKILL.md to stdout
42
+ ```
43
+
44
+ ### Use in Claude
45
+
46
+ After running `init`, reference the skills in your Claude conversation:
47
+
48
+ 1. **Upload the files** from `.claude/skills/<skill-name>/` at the start of a conversation
49
+ 2. **Or mention** the skill by name — Claude will follow the instructions automatically
50
+
51
+ ## Available skills
52
+
53
+ ### `project-docs`
54
+ Generates standardized documentation for software projects:
55
+ - `PROJETO.md` — product vision, roadmap, business model
56
+ - `ARQUITETURA.md` — technical decisions, stack, ADRs
57
+ - `README.md` — overview and setup instructions
58
+ - `API.md` — endpoint contracts and examples
59
+ - `ONBOARDING.md` — guide for new developers
60
+ - `SPRINTS.md` — sprint history and planning
61
+
62
+ ### `github-sprint`
63
+ Generates sprint planning files and automates GitHub issue creation:
64
+ - `sprints/sprint-N.yml` — structured sprint plan
65
+ - `.github/workflows/create-issues.yml` — GitHub Action
66
+ - `.github/scripts/create-sprint-issues.js` — Action script
67
+
68
+ Commit `sprint-N.yml` → GitHub Action creates milestone, labels and issues automatically.
69
+
70
+ ## Adding to .gitignore
71
+
72
+ The `.claude/` folder contains AI instructions, not secrets. We recommend
73
+ **committing it** so your whole team has access to the same skills.
74
+
75
+ If you prefer not to commit it:
76
+
77
+ ```gitignore
78
+ .claude/
79
+ ```
80
+
81
+ ## Publishing a new skill
82
+
83
+ 1. Add your skill folder to `skills/`
84
+ 2. Add metadata to `src/commands/list.js` (`SKILL_META`)
85
+ 3. Bump version in `package.json`
86
+ 4. `npm publish --access public`
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@_brenosiqueira/claude-skills",
3
+ "version": "1.0.0",
4
+ "description": "Claude AI skills for software project documentation and sprint planning",
5
+ "keywords": ["claude", "ai", "skills", "documentation", "sprint", "github"],
6
+ "author": "your-name",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "bin": {
10
+ "claude-skills": "./src/cli.js"
11
+ },
12
+ "files": [
13
+ "src/",
14
+ "skills/"
15
+ ],
16
+ "dependencies": {
17
+ "chalk": "^5.3.0",
18
+ "commander": "^12.0.0",
19
+ "fs-extra": "^11.2.0"
20
+ },
21
+ "engines": {
22
+ "node": ">=18.0.0"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/your-username/claude-skills"
27
+ }
28
+ }
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: github-sprint
3
+ description: >
4
+ Generates sprint planning files and GitHub automation for any software project.
5
+ Use this skill whenever the user wants to plan a sprint, create GitHub issues,
6
+ break down tasks into issues, generate a sprint backlog, set up GitHub milestones,
7
+ or automate issue creation from a project plan. Triggers on phrases like "plan sprint",
8
+ "create issues", "break down sprint", "generate backlog", "create GitHub tasks",
9
+ "automate issues", or any request to turn a project plan into GitHub issues.
10
+ Always use this skill when the conversation involves sprints, GitHub issues, or
11
+ project task breakdown — even if the user doesn't say "skill" explicitly.
12
+ ---
13
+
14
+ # GitHub Sprint Skill
15
+
16
+ Generates structured sprint YAML files and the GitHub Action workflow that
17
+ automatically creates milestones, labels and issues when the YAML is committed.
18
+
19
+ ## Overview
20
+
21
+ This skill produces two types of output:
22
+
23
+ 1. **`sprints/sprint-N.yml`** — structured sprint plan (committed to the repo)
24
+ 2. **`.github/workflows/create-issues.yml`** — GitHub Action (one-time setup)
25
+
26
+ When the user commits `sprint-N.yml`, the Action triggers automatically and
27
+ creates everything in GitHub: milestone, labels, and all issues with full
28
+ descriptions and acceptance criteria.
29
+
30
+ ---
31
+
32
+ ## Workflow
33
+
34
+ ### Step 1 — Understand the sprint
35
+
36
+ Extract from the conversation (or ask if missing):
37
+
38
+ - Sprint number and name
39
+ - Duration (default: 2 weeks)
40
+ - Which apps/services are involved (api, mobile, web, etc.)
41
+ - What needs to be built — features, setup tasks, integrations
42
+
43
+ Do NOT ask for more than necessary. If the conversation already has the
44
+ sprint details, go straight to generating.
45
+
46
+ ### Step 2 — Generate the YAML
47
+
48
+ Read `references/yaml-schema.md` for the full schema and rules.
49
+ Read `references/issue-templates.md` for issue body templates by type.
50
+
51
+ Key rules:
52
+ - Every issue needs: title, description, acceptance criteria (3+ items), app label
53
+ - Setup/config tasks use type `chore`, new functionality uses `feature`
54
+ - Group issues by app in the YAML (api, passenger, driver, admin, shared)
55
+ - Sprint label is always `sprint-N` (e.g. `sprint-1`)
56
+ - Title format: `[app] Short imperative description`
57
+
58
+ Save to `/mnt/user-data/outputs/sprints/sprint-N.yml`
59
+
60
+ ### Step 3 — Generate the GitHub Action (first sprint only)
61
+
62
+ Check if `.github/workflows/create-issues.yml` was already generated in this
63
+ conversation. If not, read `references/github-action.md` and generate it.
64
+
65
+ Save to `/mnt/user-data/outputs/.github/workflows/create-issues.yml`
66
+
67
+ ### Step 4 — Present files and instructions
68
+
69
+ Present both files. Then show the user exactly what to do:
70
+
71
+ ```
72
+ 1. Copy sprints/ and .github/ to your repository root
73
+ 2. Set the secret GH_TOKEN in repo Settings → Secrets → Actions
74
+ (token needs: issues, milestones, labels permissions)
75
+ 3. git add . && git commit -m "chore: add sprint-N plan" && git push
76
+ 4. Watch the Action run at github.com/OWNER/REPO/actions
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Quality checklist before presenting
82
+
83
+ - [ ] Every issue has at least 3 acceptance criteria
84
+ - [ ] No issue title is vague ("setup things", "implement feature")
85
+ - [ ] API contracts documented on endpoint issues (method, path, body, response)
86
+ - [ ] Each app has at least one setup/chore issue in sprint 1
87
+ - [ ] Sprint label matches sprint number (sprint-1, sprint-2, etc.)
88
+ - [ ] YAML is valid (no tabs, consistent indentation)
@@ -0,0 +1,194 @@
1
+ # GitHub Action — create-issues.yml
2
+
3
+ ## What it does
4
+
5
+ Triggers when a `sprints/sprint-*.yml` file is pushed to `main` or `dev`.
6
+ Reads the YAML and creates:
7
+ 1. Labels (skips if already exists)
8
+ 2. Milestone with due date = push date + duration_weeks
9
+ 3. Issues with full body, labels and milestone
10
+
11
+ ## The action file
12
+
13
+ Save to `.github/workflows/create-issues.yml` in the repository.
14
+
15
+ ```yaml
16
+ name: Create sprint issues
17
+
18
+ on:
19
+ push:
20
+ branches: [main, dev]
21
+ paths:
22
+ - 'sprints/sprint-*.yml'
23
+
24
+ jobs:
25
+ create-issues:
26
+ runs-on: ubuntu-latest
27
+ permissions:
28
+ issues: write
29
+
30
+ steps:
31
+ - name: Checkout
32
+ uses: actions/checkout@v4
33
+ with:
34
+ fetch-depth: 2
35
+
36
+ - name: Setup Node.js
37
+ uses: actions/setup-node@v4
38
+ with:
39
+ node-version: '20'
40
+
41
+ - name: Install dependencies
42
+ run: npm install js-yaml @octokit/rest
43
+
44
+ - name: Find changed sprint files
45
+ id: changed
46
+ run: |
47
+ FILES=$(git diff --name-only HEAD~1 HEAD -- 'sprints/sprint-*.yml' | tr '\n' ' ')
48
+ echo "files=$FILES" >> $GITHUB_OUTPUT
49
+
50
+ - name: Create issues from sprint YAML
51
+ if: steps.changed.outputs.files != ''
52
+ env:
53
+ GH_TOKEN: ${{ secrets.GH_TOKEN }}
54
+ REPO: ${{ github.repository }}
55
+ run: |
56
+ node .github/scripts/create-sprint-issues.js ${{ steps.changed.outputs.files }}
57
+ ```
58
+
59
+ ## The Node.js script
60
+
61
+ Save to `.github/scripts/create-sprint-issues.js` in the repository.
62
+
63
+ ```javascript
64
+ const fs = require('fs');
65
+ const yaml = require('js-yaml');
66
+ const { Octokit } = require('@octokit/rest');
67
+
68
+ const octokit = new Octokit({ auth: process.env.GH_TOKEN });
69
+ const [owner, repo] = process.env.REPO.split('/');
70
+ const files = process.argv.slice(2);
71
+
72
+ async function run() {
73
+ for (const file of files) {
74
+ if (!fs.existsSync(file)) continue;
75
+ console.log(`\nProcessing ${file}...`);
76
+ const data = yaml.load(fs.readFileSync(file, 'utf8'));
77
+ await processSprint(data);
78
+ }
79
+ }
80
+
81
+ async function processSprint(data) {
82
+ const { sprint, labels, issues } = data;
83
+
84
+ // 1. Create labels
85
+ const allLabels = [
86
+ ...(labels.apps || []),
87
+ ...(labels.types || []),
88
+ ...(labels.sprint || []),
89
+ ];
90
+
91
+ for (const label of allLabels) {
92
+ try {
93
+ await octokit.issues.createLabel({
94
+ owner, repo,
95
+ name: label.name,
96
+ color: label.color,
97
+ description: label.description || '',
98
+ });
99
+ console.log(` ✓ Label: ${label.name}`);
100
+ } catch (e) {
101
+ if (e.status === 422) {
102
+ console.log(` ~ Label already exists: ${label.name}`);
103
+ } else {
104
+ console.error(` ✗ Label error ${label.name}:`, e.message);
105
+ }
106
+ }
107
+ }
108
+
109
+ // 2. Create milestone
110
+ const dueDate = new Date();
111
+ dueDate.setDate(dueDate.getDate() + (sprint.duration_weeks || 2) * 7);
112
+
113
+ let milestoneNumber;
114
+ try {
115
+ const { data: ms } = await octokit.issues.createMilestone({
116
+ owner, repo,
117
+ title: `Sprint ${sprint.number} — ${sprint.name}`,
118
+ description: sprint.milestone_description || '',
119
+ due_on: dueDate.toISOString(),
120
+ });
121
+ milestoneNumber = ms.number;
122
+ console.log(` ✓ Milestone: Sprint ${sprint.number} (#${milestoneNumber})`);
123
+ } catch (e) {
124
+ // Milestone may already exist — find it
125
+ const { data: milestones } = await octokit.issues.listMilestones({ owner, repo });
126
+ const existing = milestones.find(m => m.title.startsWith(`Sprint ${sprint.number}`));
127
+ if (existing) {
128
+ milestoneNumber = existing.number;
129
+ console.log(` ~ Milestone already exists: #${milestoneNumber}`);
130
+ } else {
131
+ throw e;
132
+ }
133
+ }
134
+
135
+ // 3. Create issues
136
+ for (const issue of issues) {
137
+ const issueLabels = [
138
+ issue.app,
139
+ issue.type,
140
+ `sprint-${sprint.number}`,
141
+ ].filter(Boolean);
142
+
143
+ try {
144
+ const { data: created } = await octokit.issues.create({
145
+ owner, repo,
146
+ title: issue.title,
147
+ body: issue.body,
148
+ labels: issueLabels,
149
+ milestone: milestoneNumber,
150
+ });
151
+ console.log(` ✓ Issue #${created.number}: ${issue.title}`);
152
+ } catch (e) {
153
+ console.error(` ✗ Issue error "${issue.title}":`, e.message);
154
+ }
155
+ }
156
+
157
+ console.log(`\n✅ Sprint ${sprint.number} created successfully!`);
158
+ }
159
+
160
+ run().catch(err => {
161
+ console.error('Fatal error:', err);
162
+ process.exit(1);
163
+ });
164
+ ```
165
+
166
+ ## Setup instructions (one time)
167
+
168
+ 1. Create a GitHub Personal Access Token:
169
+ - Go to github.com → Settings → Developer settings → Personal access tokens → Fine-grained tokens
170
+ - Permissions needed: **Issues** (read/write), **Pull requests** (read)
171
+ - Repository access: only the transport repo
172
+
173
+ 2. Add the token as a secret:
174
+ - Go to repo → Settings → Secrets and variables → Actions
175
+ - New repository secret: name `GH_TOKEN`, value = the token
176
+
177
+ 3. Commit both files to the repository:
178
+ ```
179
+ .github/
180
+ ├── workflows/
181
+ │ └── create-issues.yml
182
+ └── scripts/
183
+ └── create-sprint-issues.js
184
+ ```
185
+
186
+ 4. From now on, committing any `sprints/sprint-N.yml` triggers the Action automatically.
187
+
188
+ ## Idempotency
189
+
190
+ The script is safe to run multiple times:
191
+ - Labels: skips if already exists (422 response)
192
+ - Milestones: finds existing if create fails
193
+ - Issues: always creates new (GitHub doesn't deduplicate issues)
194
+ → To avoid duplicates, only commit each sprint YAML once
@@ -0,0 +1,125 @@
1
+ # Issue Body Templates
2
+
3
+ Use these templates as base for generating issue bodies.
4
+ Adapt the sections and content to the specific task.
5
+
6
+ ## Template: Setup / Chore
7
+
8
+ ```markdown
9
+ ## Descrição
10
+ [2-3 sentences: what needs to be configured and why it's needed before other tasks]
11
+
12
+ ## O que configurar
13
+ - [ ] Install/configure item 1
14
+ - [ ] Install/configure item 2
15
+ - [ ] Create folder structure
16
+ - [ ] Add environment variables to .env.example
17
+
18
+ ## Critérios de aceite
19
+ - [ ] `npm run dev` starts without errors
20
+ - [ ] TypeScript compiles without errors
21
+ - [ ] [specific tool] connects successfully on startup
22
+ - [ ] Health check endpoint returns 200
23
+
24
+ ## Referências
25
+ - ARQUITETURA.md — Section X
26
+ ```
27
+
28
+ ## Template: API Endpoint (feature)
29
+
30
+ ```markdown
31
+ ## Descrição
32
+ [What this endpoint does, who calls it and when]
33
+
34
+ ## Comportamento esperado
35
+ 1. Receives [input]
36
+ 2. Validates [what]
37
+ 3. Does [action]
38
+ 4. Returns [output]
39
+
40
+ ## O que implementar
41
+ - [ ] Request validation (zod schema)
42
+ - [ ] Business logic
43
+ - [ ] Database query / update
44
+ - [ ] Error handling
45
+
46
+ ## Critérios de aceite
47
+ - [ ] Returns correct status code for success
48
+ - [ ] Returns 400 for invalid input with descriptive error
49
+ - [ ] Returns 401 without valid JWT
50
+ - [ ] [Business rule criterion]
51
+ - [ ] [Edge case criterion]
52
+
53
+ ## Contrato
54
+ \`\`\`
55
+ METHOD /path
56
+ Headers: Authorization: Bearer {token}
57
+ Body: { field: type }
58
+ Response 200: { field: type }
59
+ Response 400: { error: string }
60
+ Response 401: { error: string }
61
+ \`\`\`
62
+
63
+ ## Referências
64
+ - ARQUITETURA.md — relevant section
65
+ ```
66
+
67
+ ## Template: Mobile Screen (feature)
68
+
69
+ ```markdown
70
+ ## Descrição
71
+ [What this screen shows and what the user can do on it]
72
+
73
+ ## Comportamento esperado
74
+ 1. [First thing that happens when user arrives]
75
+ 2. [Main interaction]
76
+ 3. [What happens on success]
77
+ 4. [What happens on error]
78
+
79
+ ## O que implementar
80
+ - [ ] Screen layout and components
81
+ - [ ] API integration (which endpoint)
82
+ - [ ] State management (Zustand store update or TanStack Query)
83
+ - [ ] Navigation on success/error
84
+ - [ ] Loading and error states
85
+
86
+ ## Critérios de aceite
87
+ - [ ] [Visual/layout criterion]
88
+ - [ ] [Data criterion — what is displayed]
89
+ - [ ] [Interaction criterion — what happens on tap/submit]
90
+ - [ ] Loading state shown during API call
91
+ - [ ] Error message shown on failure
92
+ - [ ] [Navigation criterion — where does it go next]
93
+
94
+ ## Referências
95
+ - ARQUITETURA.md — Section 5 or 6
96
+ ```
97
+
98
+ ## Template: Admin Screen (feature)
99
+
100
+ ```markdown
101
+ ## Descrição
102
+ [What this admin screen manages]
103
+
104
+ ## Comportamento esperado
105
+ 1. Data loaded via [endpoint]
106
+ 2. [Main admin action]
107
+ 3. Feedback shown after action
108
+
109
+ ## O que implementar
110
+ - [ ] Table/list component with data
111
+ - [ ] Filter/search if applicable
112
+ - [ ] Action buttons with confirmation
113
+ - [ ] API calls for each action
114
+ - [ ] Toast feedback on success/error
115
+
116
+ ## Critérios de aceite
117
+ - [ ] Data loads correctly from API
118
+ - [ ] [Action] calls correct endpoint
119
+ - [ ] Success feedback shown (toast)
120
+ - [ ] List refreshes after action
121
+ - [ ] Accessible only with admin JWT
122
+
123
+ ## Referências
124
+ - ARQUITETURA.md — Section 7
125
+ ```
@@ -0,0 +1,146 @@
1
+ # YAML Schema — Sprint Plan
2
+
3
+ ## Full structure
4
+
5
+ ```yaml
6
+ sprint:
7
+ number: 1
8
+ name: "Autenticação e Perfis"
9
+ duration_weeks: 2
10
+ milestone_description: "One sentence describing the sprint goal"
11
+
12
+ labels:
13
+ apps:
14
+ - name: api
15
+ color: "0075ca"
16
+ description: "Backend Node.js"
17
+ - name: passenger
18
+ color: "1D9E75"
19
+ description: "App passageiro"
20
+ # add/remove app labels as needed for the project
21
+ types:
22
+ - name: feature
23
+ color: "0e8a16"
24
+ description: "Nova funcionalidade"
25
+ - name: chore
26
+ color: "e4e669"
27
+ description: "Configuração e infra"
28
+ - name: bug
29
+ color: "d73a4a"
30
+ description: "Correção de bug"
31
+ sprint:
32
+ - name: sprint-1
33
+ color: "f9d0c4"
34
+ description: "Sprint 1"
35
+
36
+ issues:
37
+ - title: "[api] Configurar projeto base"
38
+ type: chore # feature | chore | bug
39
+ app: api # must match a label name above
40
+ body: |
41
+ ## Descrição
42
+ Text describing what needs to be done and why.
43
+
44
+ ## O que implementar
45
+ - [ ] Item 1
46
+ - [ ] Item 2
47
+
48
+ ## Critérios de aceite
49
+ - [ ] Criterion 1
50
+ - [ ] Criterion 2
51
+ - [ ] Criterion 3
52
+
53
+ ## Referências
54
+ - Link or doc reference
55
+ ```
56
+
57
+ ## Rules
58
+
59
+ ### Title
60
+ - Format: `[app] Short imperative verb phrase`
61
+ - Good: `[api] Endpoint POST /auth/send-otp`
62
+ - Bad: `[api] Auth stuff`, `[api] Implement authentication endpoint for sending OTP via SMS`
63
+ - Max 60 characters
64
+
65
+ ### Body sections
66
+ Every issue MUST have all four sections:
67
+ 1. `## Descrição` — what and why (2-4 sentences)
68
+ 2. `## O que implementar` — checklist of sub-tasks
69
+ 3. `## Critérios de aceite` — minimum 3 verifiable items
70
+ 4. `## Referências` — doc or architecture section reference
71
+
72
+ ### Endpoint issues (api features)
73
+ Add a `## Contrato` section with the full API contract:
74
+
75
+ ```markdown
76
+ ## Contrato
77
+ \`\`\`
78
+ POST /auth/send-otp
79
+ Body: { phone: string }
80
+ Response 200: { message: string }
81
+ Response 400: { error: string }
82
+ Response 429: { error: 'Too many requests' }
83
+ \`\`\`
84
+ ```
85
+
86
+ ### Type rules
87
+ - `chore`: project setup, config, infrastructure, CI, dependencies
88
+ - `feature`: new user-facing or system functionality
89
+ - `bug`: fix for broken behaviour (usually not in sprint planning)
90
+
91
+ ### Labels applied per issue
92
+ The Action automatically applies: `[app label]`, `[type label]`, `[sprint label]`
93
+ You do NOT need to list labels in the YAML per issue — they are inferred from
94
+ `app` and `type` fields plus the sprint number.
95
+
96
+ ## Minimal valid example
97
+
98
+ ```yaml
99
+ sprint:
100
+ number: 2
101
+ name: "Mapas e Geolocalização"
102
+ duration_weeks: 2
103
+ milestone_description: "Integração de mapas, rastreamento em tempo real e estimativa de corrida."
104
+
105
+ labels:
106
+ apps:
107
+ - { name: api, color: "0075ca", description: "Backend" }
108
+ - { name: passenger, color: "1D9E75", description: "App passageiro" }
109
+ - { name: driver, color: "378ADD", description: "App motorista" }
110
+ types:
111
+ - { name: feature, color: "0e8a16", description: "Nova funcionalidade" }
112
+ - { name: chore, color: "e4e669", description: "Configuração e infra" }
113
+ sprint:
114
+ - { name: sprint-2, color: "c5def5", description: "Sprint 2" }
115
+
116
+ issues:
117
+ - title: "[api] Integrar Google Maps Directions API"
118
+ type: feature
119
+ app: api
120
+ body: |
121
+ ## Descrição
122
+ Integrar a Google Maps Directions API para calcular distância e
123
+ duração estimada entre origem e destino de uma corrida.
124
+
125
+ ## O que implementar
126
+ - [ ] Instalar SDK `@googlemaps/google-maps-services-js`
127
+ - [ ] Criar serviço `MapsService` com método `getRoute(origin, destination)`
128
+ - [ ] Usar resultado para popular `distanceKm` e `durationMin` na corrida
129
+
130
+ ## Critérios de aceite
131
+ - [ ] `getRoute` retorna distância em km e duração em minutos
132
+ - [ ] Erros da API do Google tratados e logados
133
+ - [ ] Chave de API carregada via variável de ambiente
134
+ - [ ] Teste unitário com mock da API
135
+
136
+ ## Contrato
137
+ ```
138
+ POST /rides/estimate
139
+ Body: { originLat, originLng, destinationLat, destinationLng }
140
+ Response 200: { distanceKm, durationMin, priceMin, priceMax }
141
+ Response 400: { error: string }
142
+ ```
143
+
144
+ ## Referências
145
+ - ARQUITETURA.md — Seção 4 (Engine de precificação)
146
+ ```