@pixerate/editor 0.223.1 → 0.223.3

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 (28) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.js +1 -1
  3. package/dist/{chunk-SVHXD2VH.js → chunk-H73MSHYZ.js} +5 -1
  4. package/dist/{chunk-BDT2IYXK.cjs → chunk-VXLYEYP4.cjs} +6 -2
  5. package/dist/tools/index.cjs +2 -2
  6. package/dist/tools/index.js +1 -1
  7. package/dist/tools/skill-evals.d.cts +6 -1
  8. package/dist/tools/skill-evals.d.ts +6 -1
  9. package/package.json +1 -1
  10. package/skills/README.md +5 -1
  11. package/skills/pixerate-diagram/SKILL.md +8 -0
  12. package/skills/pixerate-diagram-architecture/SKILL.md +104 -0
  13. package/skills/pixerate-diagram-architecture/evals/label-protocols.json +62 -0
  14. package/skills/pixerate-diagram-architecture/evals/trust-boundaries.json +64 -0
  15. package/skills/pixerate-diagram-architecture/evals/web-app.json +56 -0
  16. package/skills/pixerate-diagram-process-flow/SKILL.md +99 -0
  17. package/skills/pixerate-diagram-process-flow/evals/order-process.json +73 -0
  18. package/skills/pixerate-diagram-process-flow/evals/swimlanes.json +74 -0
  19. package/skills/pixerate-diagram-process-flow/evals/tidy-decision.json +76 -0
  20. package/skills/pixerate-spreadsheet/SKILL.md +2 -0
  21. package/skills/pixerate-spreadsheet-analysis/SKILL.md +97 -0
  22. package/skills/pixerate-spreadsheet-analysis/evals/count-and-average.json +148 -0
  23. package/skills/pixerate-spreadsheet-analysis/evals/month-over-month.json +128 -0
  24. package/skills/pixerate-spreadsheet-analysis/evals/summary-by-region.json +178 -0
  25. package/skills/pixerate-spreadsheet-financial-model/SKILL.md +98 -0
  26. package/skills/pixerate-spreadsheet-financial-model/evals/find-hardcoded.json +113 -0
  27. package/skills/pixerate-spreadsheet-financial-model/evals/projection-with-inputs.json +118 -0
  28. package/skills/pixerate-spreadsheet-financial-model/evals/scenarios.json +136 -0
@@ -0,0 +1,178 @@
1
+ {
2
+ "prompt": "Make a summary of total sales by region next to the data, starting at G1 (a header row, then one row per region), using formulas so it updates when the data changes.",
3
+ "fixture": {
4
+ "editor": "spreadsheet",
5
+ "rows": [
6
+ [
7
+ "Date",
8
+ "Region",
9
+ "Product",
10
+ "Amount"
11
+ ],
12
+ [
13
+ "2026-01-05",
14
+ "North",
15
+ "Widget",
16
+ 120
17
+ ],
18
+ [
19
+ "2026-01-07",
20
+ "South",
21
+ "Gadget",
22
+ 80
23
+ ],
24
+ [
25
+ "2026-01-12",
26
+ "North",
27
+ "Gadget",
28
+ 95
29
+ ],
30
+ [
31
+ "2026-01-15",
32
+ "East",
33
+ "Widget",
34
+ 60
35
+ ],
36
+ [
37
+ "2026-01-20",
38
+ "West",
39
+ "Widget",
40
+ 150
41
+ ],
42
+ [
43
+ "2026-02-02",
44
+ "South",
45
+ "Widget",
46
+ 110
47
+ ],
48
+ [
49
+ "2026-02-08",
50
+ "East",
51
+ "Gadget",
52
+ 70
53
+ ],
54
+ [
55
+ "2026-02-11",
56
+ "North",
57
+ "Widget",
58
+ 130
59
+ ],
60
+ [
61
+ "2026-02-19",
62
+ "West",
63
+ "Gadget",
64
+ 90
65
+ ],
66
+ [
67
+ "2026-02-25",
68
+ "South",
69
+ "Gadget",
70
+ 85
71
+ ]
72
+ ]
73
+ },
74
+ "checks": [
75
+ {
76
+ "why": "one row per region with the right totals",
77
+ "tool": "get_range",
78
+ "args": {
79
+ "range": "G2:H10"
80
+ },
81
+ "expect": {
82
+ "values": {
83
+ "$nonEmpty": {
84
+ "$length": 4,
85
+ "$expr": "[['North',345],['South',275],['East',130],['West',240]].every(([r, t]) => v.some((row) => row[0] === r && row[1] === t))"
86
+ }
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "why": "the totals are formulas over the data, not typed numbers",
92
+ "tool": "get_range",
93
+ "args": {
94
+ "range": "H2:H5"
95
+ },
96
+ "expect": {
97
+ "raw": {
98
+ "$every": {
99
+ "$every": {
100
+ "$match": [
101
+ "^=.*(SUMIFS?|SUMPRODUCT|FILTER)",
102
+ "i"
103
+ ]
104
+ }
105
+ }
106
+ }
107
+ }
108
+ },
109
+ {
110
+ "why": "a header row",
111
+ "tool": "get_range",
112
+ "args": {
113
+ "range": "G1:H1"
114
+ },
115
+ "expect": {
116
+ "values": [
117
+ {
118
+ "$every": {
119
+ "$match": "\\S"
120
+ }
121
+ }
122
+ ]
123
+ }
124
+ },
125
+ {
126
+ "why": "no formula errors",
127
+ "tool": "get_range",
128
+ "args": {
129
+ "range": "G1:H10"
130
+ },
131
+ "expect": {
132
+ "errors": []
133
+ }
134
+ }
135
+ ],
136
+ "solution": [
137
+ {
138
+ "tool": "get_range",
139
+ "args": {
140
+ "range": "A1:D20"
141
+ }
142
+ },
143
+ {
144
+ "tool": "set_range",
145
+ "args": {
146
+ "start": "G1",
147
+ "values": [
148
+ [
149
+ "Region",
150
+ "Total sales"
151
+ ],
152
+ [
153
+ "North",
154
+ "=SUMIFS($D$2:$D$11,$B$2:$B$11,G2)"
155
+ ],
156
+ [
157
+ "South",
158
+ "=SUMIFS($D$2:$D$11,$B$2:$B$11,G3)"
159
+ ],
160
+ [
161
+ "East",
162
+ "=SUMIFS($D$2:$D$11,$B$2:$B$11,G4)"
163
+ ],
164
+ [
165
+ "West",
166
+ "=SUMIFS($D$2:$D$11,$B$2:$B$11,G5)"
167
+ ]
168
+ ]
169
+ }
170
+ },
171
+ {
172
+ "tool": "get_range",
173
+ "args": {
174
+ "range": "G1:H5"
175
+ }
176
+ }
177
+ ]
178
+ }
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: pixerate-spreadsheet-financial-model
3
+ description: The financial model workflow in a Pixerate spreadsheet - inputs (assumptions) in labelled cells kept apart from calculations and outputs, one consistent formula across each row, absolute references to inputs, no hard-coded numbers in formulas, projections that compound, scenario and sensitivity tables, checks that totals tie, and finding the hard-coded or broken cell in an existing model. Use when asked to build or check a financial model, forecast, projection, budget, business case, revenue or cost model, break-even, loan or growth calculation, scenario or what-if table, or to find why a model does not update, or when get_range and set_range are available. Load with pixerate-spreadsheet, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-spreadsheet
7
+ ---
8
+
9
+ # Building a financial model
10
+
11
+ A model is inputs, calculations and outputs. Inputs are the assumptions a person changes
12
+ (starting revenue, growth, prices); calculations turn them into numbers period by period;
13
+ outputs are what the reader looks at (totals, year-5 revenue, profit). Every calculation
14
+ refers to inputs by absolute reference and never contains a typed number, so changing one
15
+ assumption flows through everything.
16
+
17
+ This skill is the method. `pixerate-spreadsheet` has the full tool reference and functions.
18
+
19
+ ## Goal and quality bar
20
+
21
+ - Inputs live in their own labelled cells at the top (or on their own block), one assumption per
22
+ cell, with units in the label.
23
+ - Each row of the projection uses one formula pattern across its periods, referring to inputs
24
+ absolutely (`$B$2`) and to the previous period relatively (`B5`).
25
+ - No hard-coded numbers in calculation formulas (no `*1.08`, no `+5000`); constants that matter
26
+ are inputs.
27
+ - Outputs are formulas; checks tie (subtotals add to totals, a balance closes).
28
+ - No formula errors; the model gives the expected value for a case you can work out by hand.
29
+
30
+ ## Inputs to confirm
31
+
32
+ - **Assumptions** and their values and units (growth as 0.08 or 8 %, currency).
33
+ - **Periods** (years or months) and how many.
34
+ - **Layout** the user expects (where inputs, the projection and outputs go).
35
+ - **Scenarios** to compare (low, base, high).
36
+
37
+ ## Working method
38
+
39
+ 1. **Read** what exists: `get_range` the whole model area, `raw` as well as `values`.
40
+ **Check:** you can list the inputs, the calculation rows and the outputs.
41
+ 2. **Inputs block.** Labels in column A, values in B (`set_range` in one call). Rates as
42
+ fractions (0.08), money as plain numbers with the currency in the label.
43
+ 3. **Timeline.** A header row of periods (years 1-5 in B4:F4).
44
+ 4. **Calculation rows.** One `set_range` per row: the first period from an input (`=$B$1`),
45
+ later periods from the previous one and the input (`=B5*(1+$B$2)`), the same pattern across.
46
+ **Check:** `get_range` values match a hand calculation (100,000 at 8 % is 108,000, then
47
+ 116,640); `errors` empty.
48
+ 5. **Outputs and checks.** Totals (`=SUM(B5:F5)`), year-N values, and a check cell that should be
49
+ 0 or TRUE (`=SUM(B7:F7)-B9`).
50
+ 6. **Scenarios.** A small table with the scenario inputs in one column and the output formula
51
+ next to each, referring to the starting input absolutely and its own scenario cell
52
+ relatively (`=$B$1*(1+A9)^4` for year 5).
53
+ **Check:** the base scenario equals the main model's output.
54
+ 7. **Audit.** Read `raw` across every calculation row: each should match its neighbours' pattern;
55
+ a formula with a typed number or a different reference is the bug.
56
+
57
+ ## Decision table
58
+
59
+ | Need | Formula pattern |
60
+ | --- | --- |
61
+ | Compound growth period on period | `=prev*(1+$rate$)` |
62
+ | Value at period n directly | `=$start$*(1+$rate$)^(n-1)` |
63
+ | Cost as a share of revenue | `=revenue_cell*$cost_share$` |
64
+ | Fixed cost each period | `=$fixed_cost$` |
65
+ | Running total | `=prev_total+this_period` |
66
+ | Profit | `=revenue-costs` |
67
+ | Scenario output | Input in its own cell per scenario, output formula next to it |
68
+ | Something does not update | Find the formula with a typed number or a missing `$` |
69
+
70
+ ## Recipes
71
+
72
+ **Five-year projection.** `set_range` from A1: `[["Starting revenue", 100000], ["Growth", 0.08],
73
+ [], ["Year", 1, 2, 3, 4, 5], ["Revenue", "=$B$1", "=B5*(1+$B$2)", "=C5*(1+$B$2)",
74
+ "=D5*(1+$B$2)", "=E5*(1+$B$2)"]]`.
75
+
76
+ **Find a hard-coded number.** `get_range` the calculation rows; compare each `raw` with its
77
+ neighbours; replace the odd one with the pattern (`set_cell`).
78
+
79
+ **Scenarios.** From A8: `[["Growth", "Year 5 revenue"], [0.05, "=$B$1*(1+A9)^4"], [0.08,
80
+ "=$B$1*(1+A10)^4"], [0.12, "=$B$1*(1+A11)^4"]]`.
81
+
82
+ ## Pitfalls
83
+
84
+ - **Typed numbers in formulas** (`=C5*1.08`) do not follow the input; the classic broken model.
85
+ - **Relative input references** shift as formulas copy across; inputs need `$`.
86
+ - **Mixed patterns in a row** hide errors; one formula pattern per row.
87
+ - **Percent confusion**: 8 typed as a rate is 800 %; write 0.08 or `8%`.
88
+ - **Circular references** (`#CYCLE!`) from a total that includes itself.
89
+ - **`set_range` does not shift references** the way fill does; write each cell's own.
90
+ - **Outputs typed as values** break when an input changes.
91
+
92
+ ## Tools used
93
+
94
+ - `get_range`: read `raw` and `values`, check results and errors
95
+ - `set_range`: write the inputs, timeline, rows and scenario tables, one undo step each
96
+ - `set_cell`: fix one formula
97
+ - `insert_rows`, `insert_columns`: add periods or lines
98
+ - `undo_spreadsheet`: take back a step
@@ -0,0 +1,113 @@
1
+ {
2
+ "prompt": "Something in this revenue model doesn't update when I change the growth rate in B2. Find and fix it.",
3
+ "fixture": {
4
+ "editor": "spreadsheet",
5
+ "rows": [
6
+ [
7
+ "Starting revenue",
8
+ 100000,
9
+ null,
10
+ null,
11
+ null,
12
+ null
13
+ ],
14
+ [
15
+ "Growth",
16
+ 0.08,
17
+ null,
18
+ null,
19
+ null,
20
+ null
21
+ ],
22
+ [
23
+ null,
24
+ null,
25
+ null,
26
+ null,
27
+ null,
28
+ null
29
+ ],
30
+ [
31
+ "Year",
32
+ 1,
33
+ 2,
34
+ 3,
35
+ 4,
36
+ 5
37
+ ],
38
+ [
39
+ "Revenue",
40
+ "=$B$1",
41
+ "=B5*(1+$B$2)",
42
+ "=C5*1.08",
43
+ "=D5*(1+$B$2)",
44
+ "=E5*(1+$B$2)"
45
+ ]
46
+ ]
47
+ },
48
+ "checks": [
49
+ {
50
+ "why": "no typed growth rate left in the projection",
51
+ "tool": "get_range",
52
+ "args": {
53
+ "range": "C5:F5"
54
+ },
55
+ "expect": {
56
+ "raw": [
57
+ {
58
+ "$every": {
59
+ "$match": "^=.*\\$?B\\$?2",
60
+ "$not": {
61
+ "$match": "1\\.08"
62
+ }
63
+ }
64
+ }
65
+ ]
66
+ }
67
+ },
68
+ {
69
+ "why": "the values are unchanged at 8 %",
70
+ "tool": "get_range",
71
+ "args": {
72
+ "range": "F5"
73
+ },
74
+ "expect": {
75
+ "values": {
76
+ "$expr": "Math.abs(v[0][0] - 136048.896) < 0.01"
77
+ }
78
+ }
79
+ },
80
+ {
81
+ "why": "the inputs are untouched",
82
+ "tool": "get_range",
83
+ "args": {
84
+ "range": "B1:B2"
85
+ },
86
+ "expect": {
87
+ "values": [
88
+ [
89
+ 100000
90
+ ],
91
+ [
92
+ 0.08
93
+ ]
94
+ ]
95
+ }
96
+ }
97
+ ],
98
+ "solution": [
99
+ {
100
+ "tool": "get_range",
101
+ "args": {
102
+ "range": "A1:F5"
103
+ }
104
+ },
105
+ {
106
+ "tool": "set_cell",
107
+ "args": {
108
+ "cell": "D5",
109
+ "value": "=C5*(1+$B$2)"
110
+ }
111
+ }
112
+ ]
113
+ }
@@ -0,0 +1,118 @@
1
+ {
2
+ "prompt": "Build a five-year revenue projection: starting revenue 100,000 in year 1, growing 8 % a year. Put the inputs at the top (labels in column A, values in column B: starting revenue in B1, growth in B2) and the projection in rows 4-5 (years 1-5 in B4:F4, revenue in B5:F5), so I can change the growth rate in one place.",
3
+ "fixture": {
4
+ "editor": "spreadsheet",
5
+ "rows": [
6
+ [
7
+ ""
8
+ ]
9
+ ]
10
+ },
11
+ "checks": [
12
+ {
13
+ "why": "the inputs are in their own cells",
14
+ "tool": "get_range",
15
+ "args": {
16
+ "range": "B1:B2"
17
+ },
18
+ "expect": {
19
+ "values": [
20
+ [
21
+ 100000
22
+ ],
23
+ [
24
+ 0.08
25
+ ]
26
+ ]
27
+ }
28
+ },
29
+ {
30
+ "why": "the projection compounds at the input rate",
31
+ "tool": "get_range",
32
+ "args": {
33
+ "range": "B5:F5"
34
+ },
35
+ "expect": {
36
+ "values": {
37
+ "$expr": "[100000, 108000, 116640, 125971.2, 136048.896].every((x, i) => Math.abs(v[0][i] - x) < 0.01)"
38
+ }
39
+ }
40
+ },
41
+ {
42
+ "why": "later years are formulas that use the growth input (B2), not a typed rate",
43
+ "tool": "get_range",
44
+ "args": {
45
+ "range": "C5:F5"
46
+ },
47
+ "expect": {
48
+ "raw": [
49
+ {
50
+ "$every": {
51
+ "$match": "^=.*\\$?B\\$?2"
52
+ }
53
+ }
54
+ ]
55
+ }
56
+ },
57
+ {
58
+ "why": "no formula errors",
59
+ "tool": "get_range",
60
+ "args": {
61
+ "range": "A1:F5"
62
+ },
63
+ "expect": {
64
+ "errors": []
65
+ }
66
+ }
67
+ ],
68
+ "solution": [
69
+ {
70
+ "tool": "set_range",
71
+ "args": {
72
+ "start": "A1",
73
+ "values": [
74
+ [
75
+ "Starting revenue",
76
+ 100000,
77
+ null,
78
+ null,
79
+ null,
80
+ null
81
+ ],
82
+ [
83
+ "Growth",
84
+ 0.08,
85
+ null,
86
+ null,
87
+ null,
88
+ null
89
+ ],
90
+ [
91
+ null,
92
+ null,
93
+ null,
94
+ null,
95
+ null,
96
+ null
97
+ ],
98
+ [
99
+ "Year",
100
+ 1,
101
+ 2,
102
+ 3,
103
+ 4,
104
+ 5
105
+ ],
106
+ [
107
+ "Revenue",
108
+ "=$B$1",
109
+ "=B5*(1+$B$2)",
110
+ "=C5*(1+$B$2)",
111
+ "=D5*(1+$B$2)",
112
+ "=E5*(1+$B$2)"
113
+ ]
114
+ ]
115
+ }
116
+ }
117
+ ]
118
+ }
@@ -0,0 +1,136 @@
1
+ {
2
+ "prompt": "Below the model, add a small scenario table from A8: the year-5 revenue at 5 %, 8 % and 12 % growth (growth rates in A9:A11, year-5 revenue next to each in B9:B11), with formulas from the starting revenue in B1.",
3
+ "fixture": {
4
+ "editor": "spreadsheet",
5
+ "rows": [
6
+ [
7
+ "Starting revenue",
8
+ 100000,
9
+ null,
10
+ null,
11
+ null,
12
+ null
13
+ ],
14
+ [
15
+ "Growth",
16
+ 0.08,
17
+ null,
18
+ null,
19
+ null,
20
+ null
21
+ ],
22
+ [
23
+ null,
24
+ null,
25
+ null,
26
+ null,
27
+ null,
28
+ null
29
+ ],
30
+ [
31
+ "Year",
32
+ 1,
33
+ 2,
34
+ 3,
35
+ 4,
36
+ 5
37
+ ],
38
+ [
39
+ "Revenue",
40
+ "=$B$1",
41
+ "=B5*(1+$B$2)",
42
+ "=C5*(1+$B$2)",
43
+ "=D5*(1+$B$2)",
44
+ "=E5*(1+$B$2)"
45
+ ]
46
+ ]
47
+ },
48
+ "checks": [
49
+ {
50
+ "why": "the three growth rates",
51
+ "tool": "get_range",
52
+ "args": {
53
+ "range": "A9:A11"
54
+ },
55
+ "expect": {
56
+ "values": [
57
+ [
58
+ 0.05
59
+ ],
60
+ [
61
+ 0.08
62
+ ],
63
+ [
64
+ 0.12
65
+ ]
66
+ ]
67
+ }
68
+ },
69
+ {
70
+ "why": "year-5 revenue for each scenario",
71
+ "tool": "get_range",
72
+ "args": {
73
+ "range": "B9:B11"
74
+ },
75
+ "expect": {
76
+ "values": {
77
+ "$expr": "[121550.625, 136048.896, 157351.936].every((x, i) => Math.abs(v[i][0] - x) < 0.01)"
78
+ }
79
+ }
80
+ },
81
+ {
82
+ "why": "formulas from the starting revenue",
83
+ "tool": "get_range",
84
+ "args": {
85
+ "range": "B9:B11"
86
+ },
87
+ "expect": {
88
+ "raw": {
89
+ "$every": {
90
+ "$every": {
91
+ "$match": "^=.*\\$?B\\$?1"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ },
97
+ {
98
+ "why": "the base model still uses B2",
99
+ "tool": "get_range",
100
+ "args": {
101
+ "range": "F5"
102
+ },
103
+ "expect": {
104
+ "values": {
105
+ "$expr": "Math.abs(v[0][0] - 136048.896) < 0.01"
106
+ }
107
+ }
108
+ }
109
+ ],
110
+ "solution": [
111
+ {
112
+ "tool": "set_range",
113
+ "args": {
114
+ "start": "A8",
115
+ "values": [
116
+ [
117
+ "Growth",
118
+ "Year 5 revenue"
119
+ ],
120
+ [
121
+ 0.05,
122
+ "=$B$1*(1+A9)^4"
123
+ ],
124
+ [
125
+ 0.08,
126
+ "=$B$1*(1+A10)^4"
127
+ ],
128
+ [
129
+ 0.12,
130
+ "=$B$1*(1+A11)^4"
131
+ ]
132
+ ]
133
+ }
134
+ }
135
+ ]
136
+ }