@miroshnik/elves 0.0.0 → 2026.1018.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/AGENTS.md +310 -0
  2. package/README.md +344 -0
  3. package/bin/ai-dev.ts +7 -0
  4. package/bin/elves.ts +2847 -0
  5. package/bin/shims/timeout +113 -0
  6. package/claude/CLAUDE.md +71 -0
  7. package/dist/github/scripts/github.js +3428 -0
  8. package/dist/spec/scripts/architecture.js +628 -0
  9. package/dist/spec/scripts/eslint-config.js +54 -0
  10. package/dist/spec/scripts/harness-qzb932c8.js +959 -0
  11. package/dist/spec/scripts/harness-v9s1v9w3.js +16045 -0
  12. package/dist/spec/scripts/harness.js +53 -0
  13. package/dist/spec/scripts/knip-hints.cjs +34 -0
  14. package/docs/ci-concurrency.md +82 -0
  15. package/docs/cloud-sessions.md +203 -0
  16. package/docs/judgment.md +81 -0
  17. package/docs/parallel-checkouts.md +220 -0
  18. package/docs/pr-checks.md +117 -0
  19. package/docs/testing.md +304 -0
  20. package/package.json +70 -1
  21. package/skills/ci-wait/SKILL.md +180 -0
  22. package/skills/ci-wait/scripts/wait-ci.sh +377 -0
  23. package/skills/dashboard/SKILL.md +212 -0
  24. package/skills/dashboard/scripts/dashboard.ts +912 -0
  25. package/skills/dashboard/scripts/sessions.ts +772 -0
  26. package/skills/est/SKILL.md +221 -0
  27. package/skills/est/reference.md +381 -0
  28. package/skills/est/scripts/est.ts +4854 -0
  29. package/skills/github/SKILL.md +206 -0
  30. package/skills/github/locales/en.json +449 -0
  31. package/skills/github/locales/ru.json +449 -0
  32. package/skills/github/reference.md +1073 -0
  33. package/skills/github/scripts/github.ts +4390 -0
  34. package/skills/github/scripts/locale.ts +495 -0
  35. package/skills/github/scripts/package.json +3 -0
  36. package/skills/slot/SKILL.md +145 -0
  37. package/skills/slot/scripts/package.json +3 -0
  38. package/skills/slot/scripts/slot.ts +279 -0
  39. package/skills/spec/SKILL.md +247 -0
  40. package/skills/spec/canon.md +219 -0
  41. package/skills/spec/checks.md +709 -0
  42. package/skills/spec/ci.md +378 -0
  43. package/skills/spec/migration.md +125 -0
  44. package/skills/spec/reference.md +889 -0
  45. package/skills/spec/scripts/architecture.ts +839 -0
  46. package/skills/spec/scripts/c4.ts +184 -0
  47. package/skills/spec/scripts/eslint-config.ts +82 -0
  48. package/skills/spec/scripts/harness.ts +1483 -0
  49. package/skills/spec/scripts/knip-hints.cjs +34 -0
  50. package/skills/spec/scripts/knip-hints.d.cts +17 -0
  51. package/skills/spec/scripts/package-run.ts +22 -0
  52. package/skills/spec/scripts/package.json +3 -0
  53. package/skills/spec/scripts/spec-break.ts +232 -0
  54. package/skills/spec/scripts/spec-claims.ts +198 -0
  55. package/skills/spec/scripts/spec-diff.ts +1111 -0
  56. package/skills/spec/scripts/spec-doc.ts +744 -0
  57. package/skills/spec/scripts/spec-exceptions.ts +233 -0
  58. package/skills/spec/scripts/spec-publish.ts +214 -0
  59. package/skills/spec/scripts/spec-run.ts +235 -0
  60. package/skills/spec/scripts/spec-shard.ts +267 -0
  61. package/skills/spec/scripts/speclib.ts +826 -0
  62. package/skills/spec/scripts/vendor/babel-parser.LICENSE +19 -0
  63. package/skills/spec/scripts/vendor/babel-parser.cjs +14615 -0
  64. package/skills/spec/scripts/vendor/babel-parser.d.cts +3 -0
  65. package/skills/task-env/SKILL.md +231 -0
  66. package/skills/task-env/proxy/compose.yaml +51 -0
  67. package/skills/task-env/reference.md +254 -0
  68. package/skills/task-env/scripts/task-env.ts +1017 -0
@@ -0,0 +1,219 @@
1
+ # Specification — decisions
2
+
3
+ The spec canon, moved out of the `AGENTS.md` core: it applies as a rule to any
4
+ project; the core keeps a paragraph of it and a link here. Read it when you
5
+ write or migrate a test, add a check, an exception or a standard; how to wire
6
+ each mechanism — `checks.md` next to this file, the tools — `SKILL.md`.
7
+
8
+ A project's spec is **decisions with a mechanical check**, functional and
9
+ non-functional: what the system does, what it's made of, which rules the code
10
+ obeys and which qualities it holds. A check is how the system should work,
11
+ code is how it does work: whatever the code is, that's how the system works,
12
+ so code can't be the source of what should be. The source of what should be is
13
+ a decision and its trace (an issue, a commit with a reason); code only shows
14
+ which decision was made, and a test "from code" is written only when the trace
15
+ exists. There are no separate specifications: a decision exists only while a
16
+ mechanism checks it — a test, a lint rule, a check over the architecture
17
+ model. **No check — no decision; no decision — no code:** behavior without a
18
+ check may be changed without agreement, but removing what people use — only
19
+ by a decision in an issue; a standard without a check doesn't apply; code that
20
+ no decision claims is dead and is deleted.
21
+
22
+ - **A decision is the unit of the spec, a folder is its home.** One anatomy
23
+ for all kinds:
24
+ - `<folder>.md` — why and for whom, the reason and rejected alternatives;
25
+ the first paragraph is the description in the table of contents; a
26
+ `<!-- spec: … -->` marker puts a generated diagram (C4, sequence) into the
27
+ story. Test files have no JSDoc headers;
28
+ - the main file `<folder>.test.ts` — the statements: the page's sections
29
+ follow the order of its `describe`s, the main one first; `<folder>.e2e.ts`
30
+ next to it comes right after it (the units open the page), then the other
31
+ `*.test.ts`, `*.e2e.ts`;
32
+ - the mechanism — in the same folder: an `eslint.ts` fragment, an ast-grep
33
+ `rule.yml`. The project's tool configs (`eslint.config.*`, `sgconfig.yml`)
34
+ only collect them from the tree (the harness's `collectEslint`) — a rule
35
+ has one home;
36
+ - `exceptions/` — exceptions for elements without a file of their own, one
37
+ file per element (below).
38
+ - **Monorepo — a package subfolder inside the decision folder:**
39
+ `tests/<kind>/<name>/<package>/`. A package has its own runner (aliases,
40
+ environment, plugins) — it takes `tests/*/*/<package>/`; a test right in the
41
+ decision folder, without a subfolder, is repository-wide (the root runner).
42
+ One decision — one page: the main file is `<folder>.test.ts` at the folder
43
+ root or in the package subfolder (`<package>/<folder>.test.ts`); the story
44
+ starts with the root's main file, then the packages' main files by package
45
+ name, then the other files. `<folder>.md` and `exceptions/` — one per
46
+ folder, at its root. Runners are launched from the repository root (Vitest
47
+ or Jest `projects`, `-c` with the package's config): the harness counts
48
+ element paths from cwd; it reads `exceptions/` relative to the test file
49
+ and `fileOf` from the project root, and the exception path in the hint is
50
+ from the repository root, even with the runner in the package directory.
51
+ - **Three roots of `tests/` — by the reader's question;** the tool kind isn't
52
+ encoded in the structure:
53
+ ```
54
+ tests/
55
+ capabilities/<name>/ what the system does: behavior — unit, integration, e2e
56
+ architecture/ what it's made of: model.ts — C1 external systems (adapters,
57
+ hosts, environment keys, headers), C2 containers (links,
58
+ deploy configs), C3 modules and libraries (directory,
59
+ purpose, API, what it depends on, packages); <name>/ —
60
+ checks over the model
61
+ standards/<name>/ which rules all code obeys: form conventions,
62
+ cross-cutting invariants and qualities
63
+ lib/ factories, database, helpers — not the spec, not in the docs
64
+ ```
65
+ Flat, no subsystems; the folder name is the decision's identifier in
66
+ English. **One fact — one home:** a general rule ("every mutation writes an
67
+ audit record") goes in `standards/`, the behavior of the audit log itself —
68
+ in its own capability; the other capabilities say nothing about it.
69
+ - **Decisions are functional and non-functional — both have a check.** A
70
+ functional one (what the system does) is a capability. A non-functional one
71
+ is architectural (the `architecture` model: what the system is made of) or a
72
+ standard (`standards/`: which rules the code obeys). A quality —
73
+ performance, security, accessibility, reliability — is the same kind of
74
+ decision with a check, not a wish in prose: a cross-cutting one ("every
75
+ mutation writes an audit record", "every route checks permissions", "every
76
+ page passes axe") is a standard, "registry + invariant"; the budget of a
77
+ single capability ("search responds in under 300 ms") — in its capability,
78
+ next to the behavior, checked by a load test that asserts the budget. A
79
+ quality without a check isn't a decision.
80
+ - **A check is the decision's acceptance test and its regression test — that
81
+ is TDD, for every decision.** Written before the code, it is red: the
82
+ decision isn't implemented yet; the code turns it green; from then on the
83
+ same check holds the decision against every later change. Not only
84
+ behavior: "fast" is held by a load test, "data in Postgres" — by the model,
85
+ "every form has a reset button" — by an invariant over the forms. **A
86
+ decision changes through its check:** the check changes first and goes red
87
+ on the current code, then the code follows it to green. Code changed the
88
+ other way round, against a check, turns it red — that's the check doing its
89
+ job, not an obstacle to remove.
90
+ - **The mechanism — by what we pin down** (how to wire it — `checks.md` next
91
+ to this file); each is wrapped in a runner test, so `spec-doc` and
92
+ `spec-diff` see everything the same way:
93
+ - behavior — a test: an algorithm — a unit test, a subsystem — an
94
+ integration test, interaction of subsystems — e2e; the level isn't encoded
95
+ in the name, the `.e2e.ts` suffix is only for the runner;
96
+ - a budget (latency, throughput, size) — a test that measures and asserts
97
+ it: "fast" is a load test against the budget, in the capability's folder;
98
+ - a form convention ("no `console` in the domain") — a lint rule with
99
+ examples (the harness's `examples`): "not allowed" gives a rule error,
100
+ "allowed" and a file outside scope — don't;
101
+ - a behavioral convention — "registry + invariant" (`invariant`): a registry
102
+ from the code (router, schema, files), a test per element, a "registry
103
+ isn't empty" test and a violator on which the check fails;
104
+ - **a registry that parallel PRs edit element by element — one file per
105
+ element** (exceptions — `exceptions/`): deleting and adding your own file
106
+ overlaps with nothing, while in a shared array neighboring lines conflict,
107
+ and every next PR goes for a CI rerun; sorting doesn't save it, and
108
+ `merge=union` brings both back when neighboring lines are deleted. **A
109
+ record about an element with its own file — a mark in that file** (outside
110
+ scope and exception): the element is deleted — the record goes too,
111
+ whereas a record in a test or in `exceptions/` outlived the element, and a
112
+ parallel PR added a record about what no longer existed;
113
+ - boundaries, dependencies and the stack (a database, a framework) — the
114
+ architecture model: "data in Postgres" is a storage container with its
115
+ `pg` client, a framework is a package allowed for its modules;
116
+ `boundariesConfig` (ESLint, the error shows in the editor) and
117
+ `architecture` (a directory is
118
+ in a module, a package is allowed for a module and used, an external
119
+ system only through an adapter, a module in one container, a library in
120
+ the containers of the modules that depend on it); the whole graph (cycles,
121
+ orphans) — dependency-cruiser, only when it's needed;
122
+ - the order of interaction, when it is itself a decision ("reserve first,
123
+ then charge"), — `sequence` with `order` over a `trace` at the model's
124
+ boundaries.
125
+ - **A check can fail and doesn't flake** (the "Tests and code" section in
126
+ `AGENTS.md`): a test is written before the code and is red first, a lint
127
+ rule proves "not allowed" with an example, an invariant — with a violator,
128
+ an exception — with a ratchet. `.only`, `skip` without a reason and an issue
129
+ number, retries, mocks of your own modules (only external edges may be
130
+ substituted) — a lint error.
131
+ - **Claimedness — code holds on to decisions at attachment points,** not line
132
+ by line:
133
+ - every entry point (route, page, job, command) is called by at least one
134
+ capability test — by the call log (`journal` and `spec-claims`), not by
135
+ coverage: coverage says "executed", not "claimed";
136
+ - every code directory is in a model module, every package is allowed for a
137
+ module and imported;
138
+ - every file and export is reachable from an entry point (`deadCode`, knip);
139
+ - every environment variable is declared and read (`envVars`).
140
+
141
+ Existing unclaimed code — exceptions with an issue, not deletion.
142
+ - **A test is for a decision, not for every line,** inside an entry point too.
143
+ A test is needed when all three hold: it's a decision (it could have been
144
+ otherwise), a breakage would go unnoticed (types don't catch it, eyes don't
145
+ see it), a mistake is costly (shared code, data, money, external systems). I
146
+ don't test compiler and library guarantees, styles and layout, label texts —
147
+ except a regression after a real bug. A thin spec page is no reason to test
148
+ trifles: a test of a trifle fails on any edit, it gets fixed mechanically,
149
+ and it stops being spec.
150
+ - **Exceptions — with a ratchet:** for an element with its own file — a mark
151
+ in it (`// spec-exception(<decision>) #N: reason`, outside scope —
152
+ `spec-outside`), otherwise in the decision folder's `exceptions/` directory,
153
+ one file per exception (`<element>.json`: the element, `#issue` and the
154
+ reason); an exception that no longer violates fails the check (`remove the
155
+ mark in <file>`, `remove the exception: delete <file>`). The old `exceptions.ts` is migrated
156
+ by `spec-exceptions`; the harness fails on it with a hint. Disabling lint in
157
+ code — only with a rule and `-- #N reason` (`lintExceptions`); a blanket
158
+ `eslint-disable` is forbidden, an unnecessary disable is a `lint` error.
159
+ Exceptions are visible on the decision's page — it's debt, not a secret. A
160
+ task to sort out a violator is a Task, not a Bug: a bug is wrong behavior
161
+ for the user, while a violation of a standard in force is debt. A new check
162
+ on existing code enters green right away: current violations — as
163
+ exceptions with a task to sort them out, not a disabled check or a postponed
164
+ rollout.
165
+ - **What can't be checked isn't called spec.** Where the look or UX is a
166
+ decision, the check is targeted: a screenshot test, a job test;
167
+ accessibility and budgets — like any quality (above); the rest (look, texts,
168
+ impression) — a product document or acceptance in the issue.
169
+ - **Names are statements in the project language** (`language` in
170
+ `.agents/elves.json`). `describe` — a capability in the user's terms ("only
171
+ someone with access to the entity itself sees its history"), `it` — a
172
+ concrete example; not a function, component or file name (`spec-doc` warns
173
+ about such ones and `spec-diff` counts the PR's new ones in its body: in
174
+ `ru` a statement has Russian words, in another language it is a phrase of
175
+ words, not an identifier). A rule without an exit code and without
176
+ exceptions: failing `--strict` on names was paperwork, not findings (#447).
177
+ Tests of one
178
+ capability from units and e2e —
179
+ under the same `describe`. JSDoc before a `describe` or `it` — what the name
180
+ doesn't show, one to three sentences for the spec reader; file names, issue
181
+ numbers, how the test is set up — in `//`, that's for the code reader.
182
+ Rewrite an unclear name rather than explain it.
183
+ - **Intent comes in through an issue:** we discuss the implementation and make
184
+ decisions in the task (the questions section, comments). A code task gets at
185
+ creation its decision labels (the "Task tracking" section in `AGENTS.md`)
186
+ and the scenarios section: future `it` names (or "describe › it") as a list:
187
+ from them the user sees the requirements before the code and can stop it.
188
+ For a "registry + invariant" standard the harness generates the tests per
189
+ element — the scenario is the name of the `describe` in which `invariant`
190
+ (or `examples`) is called. The agent first writes the checks and runs them
191
+ locally — the new ones are red (the check can fail, the behavior doesn't
192
+ exist yet); then the code — green. Push and PR — only when green: a red CI
193
+ run proves nothing, it's noise. The PR's spec section — `spec-diff
194
+ --scenarios`, matching scenarios against tests.
195
+ - **The diff of checks in a PR is the diff of the spec,** the diff of code is
196
+ the implementation. The PR body is `spec-diff` output: added, changed and
197
+ removed test names, changes to the architecture model, exceptions and
198
+ registries. A removed test is a withdrawn requirement; that must be visible.
199
+ - **Documentation is generated,** not written by hand: `spec-doc` builds a
200
+ page per decision (why — `<folder>.md`, what holds — `describe`, what checks
201
+ it — the tests, collapsed under the section; for a standard — the examples'
202
+ code and the exceptions), the architecture page from the model (C4 diagrams
203
+ and the module table) and sequence diagrams from scenario traces.
204
+ `docs/spec` isn't in `main`: after a merge CI publishes it to the `spec`
205
+ branch (`spec-publish`); review goes by `spec-diff`. Product documents
206
+ (vision, business decisions, research) aren't spec and live separately.
207
+ - **A recurring decision is a standard:** on task close (check 5 of the "Epic
208
+ refresh on task close" section in `AGENTS.md`) a repetition found becomes a
209
+ "Standard · …" issue; the result is a rule in `tests/standards/` and a
210
+ refactoring.
211
+ - **Migrating an old spec** (OpenSpec, a technical specification) into
212
+ decisions — the `migration.md` reference next to this file: an outcome for
213
+ each requirement, check by breaking, removal categories, "the spec fell
214
+ behind the code".
215
+ - **What's not here:** state markers and todos as a plan (the plan is in the
216
+ issue), ADRs (the reason is in the decision's `<folder>.md`), capability
217
+ registries, handwritten documentation of behavior and hand-drawn diagrams,
218
+ Gherkin, mutation testing (noise from equivalent mutants, pressure towards
219
+ tests of trifles), approval points other than the issue.