Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0ab3b4d
HF-359: Split the developer docs and add per-directory agent instruct…
sequba Aug 31, 2026
5e3af05
HF-359: Deny agent reads of every generated and built path
sequba Aug 31, 2026
5b7cbae
HF-359: Lint edited files at authoring time with a PostToolUse hook
sequba Aug 31, 2026
7cb969f
HF-359: Record the remaining monorepo decisions
sequba Aug 31, 2026
7c2ac83
HF-359: Record the worker, changelog, and Node version decisions
sequba Aug 31, 2026
c1fd06b
HF-359: Make dev-docs the single source of truth
sequba Aug 31, 2026
a49b869
HF-359: Open every skill by naming the dev-docs pages it needs
sequba Aug 31, 2026
2e86b5c
HF-359: Move the docs content guide into dev-docs
sequba Aug 31, 2026
80753c5
HF-359: Address the second review round
sequba Sep 1, 2026
83eb116
HF-359: Drop the PostToolUse lint hook
sequba Sep 1, 2026
a000d8f
HF-359: Correct what the dev-docs migration got wrong
sequba Sep 1, 2026
0c2372b
HF-359: Release the packages together, from one changelog
sequba Sep 1, 2026
72001ee
HF-359: Restructure the repository as a monorepo (#1758)
sequba Sep 1, 2026
ba32eec
HF-359: Fix four dev-docs cross-references that resolved to the wrong…
claude Sep 1, 2026
f5b86aa
HF-359: Point the engine TESTING page at the standards, and place the…
claude Sep 1, 2026
5211c60
HF-359: Link the private-suite mechanics to the test README that hold…
claude Sep 1, 2026
89208ab
HF-359: Point the portal AGENTS.md at its own README
claude Sep 1, 2026
2d76345
HF-359: Fix the last two links that pointed at the dev-docs index ins…
claude Sep 1, 2026
74734b5
HF-359: Correct three claims the split and the dropped hook left behind
claude Sep 1, 2026
fc4be17
HF-359: Fix two cross-level anchors, name the type surface, complete …
claude Sep 1, 2026
b840322
HF-359: Drop a duplicated sentence and unstale three example paths
claude Sep 1, 2026
b023f7d
HF-359: Point the Workers Builds deploy commands at the root scripts
claude Sep 1, 2026
75567c3
HF-359: Make the published tarball carry the changelog by itself
claude Sep 1, 2026
76af7e9
HF-359: Point the package at its own directory and drop two dead devD…
claude Sep 1, 2026
2c0f0ce
HF-359: Repair the monorepo table and point the engine row at the eng…
claude Sep 1, 2026
15bc20a
HF-359: Unstale eight paths the move left pointing at the old root
claude Sep 1, 2026
dd62fad
HF-359: Make the engine's own test script the full gate it is documen…
claude Sep 1, 2026
b562c14
Merge branch 'develop' into feat/hf-359-monorepo-agent-setup
sequba Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `.ai/`

Everything an AI agent needs is in [`dev-docs/`](../dev-docs/README.md). This directory holds nothing else.
24 changes: 24 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"enabledPlugins": [
"typescript-lsp@claude-plugins-official"
],
"permissions": {
"deny": [
"Read(/hyperformula/lib/**)",
"Read(/hyperformula/es/**)",
"Read(/hyperformula/commonjs/**)",
"Read(/hyperformula/dist/**)",
"Read(/hyperformula/languages/**)",
"Read(/hyperformula/typings/**)",
"Read(/hyperformula/coverage/**)",
"Read(/hyperformula/test-jest/**)",
"Read(/hyperformula/test-jasmine/**)",
"Read(/hyperformula/typedoc/**)",
"Read(/hyperformula/storage/**)",
"Read(/docs/functions/**)",
"Read(/docs/.vuepress/dist/**)",
"Read(/docs/.vuepress/api-sidebar.json)",
"Read(/docs/.vuepress/api-sidebar-relative.json)"
]
}
}
31 changes: 31 additions & 0 deletions .claude/skills/changelog-creation/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: changelog-creation
description: Use when a change to source code needs a changelog entry, and before pushing any bug fix, feature, or behaviour change. Covers when an entry is required, which section it belongs in, how to write the title, and the link format.
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`DOC-STANDARDS.md`](../../../dev-docs/DOC-STANDARDS.md#the-changelog) | Which section to use, the bullet format, and how to write the text |
| [`PULL-REQUESTS.md`](../../../dev-docs/PULL-REQUESTS.md#order-of-operations) | Why the entry comes after the pull request, not before |

## 2. Decide whether an entry is required at all

Documentation-only, test-only, and CI or tooling changes take none, and neither does a bug that was introduced and never released.

## 3. Open the pull request first

**Every entry ends with a GitHub link**: the public issue it fixes when one exists, otherwise the pull request. So the entry needs a number that only exists once the pull request is open. Do not guess it — read it from the URL `gh pr create` prints. Skill `pr-creation`.

## 4. Write the bullet

Under `## [Unreleased]` in `CHANGELOG.md` at the repository root — one changelog for every package, because they release together on one version. Put it in the section that matches the change, creating the `### ` heading if it is absent. Name the package the entry concerns when the text does not make it obvious. End it with the link from step 3.

## 5. Re-read it as a user would

If it names a class, a file, or an internal identifier, rewrite it. Check it carries nothing sensitive — no client, customer, or partner names, and nothing that identifies them indirectly. See [`AGENTS.md`](../../../AGENTS.md#never-publish-sensitive-information).

## 6. Push it to the same branch

So the open pull request picks it up.
52 changes: 52 additions & 0 deletions .claude/skills/hyperformula-code-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: hyperformula-code-review
description: Use when reviewing a diff, a branch, or a pull request in the HyperFormula repository. Covers correctness for a calculation engine, performance on the hot paths, the five places a function change must touch, API stability, and what the definition of done requires.
---

## 1. Read the relevant files from `dev-docs/`

Always:

| File | Why |
|---|---|
| [`DEFINITION-OF-DONE.md`](../../../dev-docs/DEFINITION-OF-DONE.md) | What the change was required to contain |
| [`CODE-STYLE.md`](../../../dev-docs/CODE-STYLE.md) | Style, and which paths are hot enough that complexity matters |
| [`TESTING.md`](../../../dev-docs/TESTING.md#a-test-must-prove-behaviour) | Whether the tests prove anything, or only execute code |

Then the page covering what the diff touches: [`ARCHITECTURE.md`](../../../hyperformula/dev-docs/ARCHITECTURE.md), [`PARSER.md`](../../../hyperformula/dev-docs/PARSER.md), [`INTERPRETER.md`](../../../hyperformula/dev-docs/INTERPRETER.md), [`DEPENDENCY-GRAPH.md`](../../../hyperformula/dev-docs/DEPENDENCY-GRAPH.md), [`FUNCTION-CATALOGUE.md`](../../../hyperformula/dev-docs/FUNCTION-CATALOGUE.md), [`I18N.md`](../../../hyperformula/dev-docs/I18N.md).

Review in the order below, and stop to report the first serious finding rather than burying it under style notes.

## 2. Correctness

- **Would the test fail without the fix?** Ask it of every bug-fix pull request.
- **Any `throw` reachable from evaluation**, instead of a returned `CellError`.
- **Hand-rolled coercion** instead of `ArithmeticHelper`.
- **Empty cells, empty ranges, and error arguments** — the most common gap in a function change.
- **A parser change without a matching `Unparser` change.**
- **A structural change that does not assert the formula text afterwards.**
- **A new mutation missing one of `CrudOperations`, `Operations`, `UndoRedo`** — undo diverges silently.

## 3. Completeness of a function change

Check every one of [the five places a function change must touch](../../../hyperformula/dev-docs/INTERPRETER.md#the-five-places-a-function-change-must-touch); most of them fail silently when missed. Plus `sizeOfResultArrayMethod` for anything array-returning, and an explicit `optionalArg` where arity does not express the valid call. Skill `hyperformula-function-dev`.

## 4. Performance

Allocation in a per-cell or per-vertex loop; work that could be hoisted out of the broadcast path; a range expanded into per-cell iteration; anything that widens what a change invalidates; a `ParserWithCaching` change that makes the result depend on something outside the cache key. Ask for `npm run test:performance` on hot-path changes.

## 5. Public API

`hyperformula/src/HyperFormula.ts` and its exported types are the contract. A signature, return-type, or behaviour change is breaking and needs a migration-guide section and an explicit note. JSDoc here is published output — review it as documentation.

## 6. Process

One atomic change per pull request. Say so when unrelated refactors have been folded in, rather than approving them through.

## 7. Style, last and briefly

ESLint owns formatting. Comment only on what it cannot check: a misleading name, a function doing two things, duplicated logic an existing helper already covers.

## Reporting

One line per finding: what is wrong, where, and what to do instead. No praise, no summary of what the pull request does. Separate "this is a bug" from "I would have done it differently", and never present the second as the first.
69 changes: 69 additions & 0 deletions .claude/skills/hyperformula-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: hyperformula-dev
paths: hyperformula/src/**
description: >
Use for ANY work touching the HyperFormula engine in `hyperformula/src/`: fixing bugs, adding features,
changing the public API, working on the parser, the interpreter, the dependency graph,
CRUD operations, configuration options, named expressions, or number and date formats.
Also use for how-to questions about engine internals (how recalculation works, why a formula
returns an error, where a value is coerced). Triggers on file paths under `hyperformula/src/`, or when the
user describes a symptom in a calculation without naming a file. This is the primary entry
point for engine development — when in doubt, load it.
---

## 1. Read the relevant files from `dev-docs/`

Always:

| File | Why |
|---|---|
| [`ARCHITECTURE.md`](../../../hyperformula/dev-docs/ARCHITECTURE.md) | The pipeline, the core modules, and the invariants that hold everywhere in `hyperformula/src/` |
| [`CODE-STYLE.md`](../../../dev-docs/CODE-STYLE.md) | Style, and which paths are hot enough that complexity matters |
| [`DEFINITION-OF-DONE.md`](../../../dev-docs/DEFINITION-OF-DONE.md) | What the change must contain before review |

Then the page for the stage you are changing:

| File | For |
|---|---|
| [`PARSER.md`](../../../hyperformula/dev-docs/PARSER.md) | `hyperformula/src/parser/` — formula text to AST, and back |
| [`INTERPRETER.md`](../../../hyperformula/dev-docs/INTERPRETER.md) | `hyperformula/src/interpreter/` — AST to value, and built-in functions |
| [`DEPENDENCY-GRAPH.md`](../../../hyperformula/dev-docs/DEPENDENCY-GRAPH.md) | `hyperformula/src/DependencyGraph/` — dependency tracking and recalculation order |
| [`FUNCTION-CATALOGUE.md`](../../../hyperformula/dev-docs/FUNCTION-CATALOGUE.md) | `hyperformula/src/interpreter/functionMetadata/` — function descriptions |
| [`I18N.md`](../../../hyperformula/dev-docs/I18N.md) | `hyperformula/src/i18n/` — function-name translations |
| [`TESTING.md`](../../../hyperformula/dev-docs/TESTING.md) | Writing the test the change needs |

## 2. Locate the stage before changing anything

The engine is a pipeline: `CellContentParser` → `parser/` → `GraphBuilder` → `DependencyGraph/` → `Evaluator` → `interpreter/` → `Serialization`.

| Symptom | Stage |
|---|---|
| Does not parse, or parses wrongly | `hyperformula/src/parser/` |
| `getCellFormula` returns something the user never typed | `hyperformula/src/parser/Unparser.ts` |
| A function returns the wrong value or error | `hyperformula/src/interpreter/plugin/` — skill `hyperformula-function-dev` |
| Value right, but stale after an edit | `hyperformula/src/DependencyGraph/`, `hyperformula/src/Evaluator.ts` |
| Wrong after adding or removing rows or columns | `hyperformula/src/dependencyTransformers/`, `LazilyTransformingAstService.ts` |
| Wrong in one language only | `hyperformula/src/i18n/languages/` — skill `i18n-translations` |
| Coercion or comparison is wrong | `hyperformula/src/interpreter/ArithmeticHelper.ts` |
| The public API disagrees with its docs | `hyperformula/src/HyperFormula.ts` |

A bug that looks like an interpreter problem is often a parser or graph problem. Confirm which before editing. Use the `typescript-lsp` plugin to find a definition or its callers; grep is for text, not symbols.

## 3. Reproduce first

Write the failing test before the fix and watch it fail — skill `test-writing-discipline`. For a calculation bug the smallest reproduction is a two-line `buildFromArray` plus one `getCellValue`.

If `hyperformula/test/hyperformula-tests/` is absent, `npm run test:jest` runs only the smoke tests and reports a clean pass over almost nothing. Run `npm run test:setup-private` first, and after every branch switch.

## 4. Change, then run the fast loop

```bash
npm run test:jest -- <pattern>
npm run lint
```

Run `npm run test:performance` for changes to the evaluation or CRUD hot paths.

## 5. Finish the change

Tests, documentation, JSDoc, changelog, translations — every item of `DEFINITION-OF-DONE.md`.
38 changes: 38 additions & 0 deletions .claude/skills/hyperformula-function-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: hyperformula-function-dev
paths: hyperformula/src/interpreter/**
description: Use when adding a new built-in spreadsheet function to HyperFormula, changing an existing one's signature, arguments, return type, or error behaviour, or when a function returns the wrong value or the wrong error. Covers the FunctionPlugin contract, runFunction and argument metadata, the function metadata catalogue, translations, and the full end-to-end checklist.
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`INTERPRETER.md`](../../../hyperformula/dev-docs/INTERPRETER.md#built-in-functions) | The plugin contract, `runFunction`, and every argument and function metadata field. Read this before writing any code. |
| [`FUNCTION-CATALOGUE.md`](../../../hyperformula/dev-docs/FUNCTION-CATALOGUE.md) | What the catalogue entry must contain, and the two ways to get it wrong |
| [`I18N.md`](../../../hyperformula/dev-docs/I18N.md) | Where to source a translation, and why an invented one cannot be taken back |
| [`TESTING.md`](../../../hyperformula/dev-docs/TESTING.md#what-each-kind-of-change-needs) | The list of cases a function change must cover |
| [`DEFINITION-OF-DONE.md`](../../../dev-docs/DEFINITION-OF-DONE.md) | What the change must contain before review |

## 2. Touch all five places

A function is not done until all five agree, and they do not fail the same way — a missing catalogue entry fails the docs build, a parameter-count mismatch only warns on the console, and the rest fail silently.

The list is in [`INTERPRETER.md`](../../../hyperformula/dev-docs/INTERPRETER.md#the-five-places-a-function-change-must-touch). Work through it there rather than from a copy; two of the five have their own page, linked from it.

## 3. Declare the two things nothing cross-checks

- A function that can return an array needs `sizeOfResultArrayMethod`.
- A function whose valid call arity alone does not express — a zero-argument form, an omitted trailing argument — needs `optionalArg: true` declared explicitly, or the public API advertises the argument as required.

## 4. Verify

```bash
npm run test:jest -- <FunctionName>
npm run docs:generate-function-docs # fails loudly on a bad or missing catalogue entry
npm run lint
```

## 5. Record any deviation from Excel

That is a decision, not an accident. Put it in [`docs/guide/list-of-differences.md`](../../../docs/guide/list-of-differences.md) and say so in the changelog entry. Never write a description that documents Excel while the code does something else.
40 changes: 40 additions & 0 deletions .claude/skills/hyperformula-unit-testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: hyperformula-unit-testing
paths: hyperformula/test/**
description: Use when writing or modifying tests for HyperFormula, or when a change to `hyperformula/src/` needs test coverage. Covers the two suites, fetching the private suite, how to build an engine in a test, and what a function or CRUD change must cover.
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`TESTING.md`](../../../hyperformula/dev-docs/TESTING.md) | The two suites, how to run them, and what each kind of change must cover |
| [`TESTING.md`](../../../dev-docs/TESTING.md#how-to-write-a-test-case) | How to write the case itself, and what a test must prove to count |
| [`WORKTREES.md`](../../../dev-docs/WORKTREES.md) | Only when working in a linked worktree, where the private suite is absent entirely |

And [`hyperformula/test/README.md`](../../../hyperformula/test/README.md) for how the private suite is fetched and the environment variables it honours.

## 2. Attach the private suite before trusting anything

```bash
npm run test:setup-private
```

Run it after every branch switch. Without `hyperformula/test/hyperformula-tests/` the Jest run covers only the smoke tests and reports a clean pass over almost nothing — the most common false signal in this repository. `test:performance` and `test:compatibility` fail on a missing path rather than an assertion; read the error before concluding the code is broken.

## 3. Write the case from the requirement

Not from the implementation. A test written from the code passes for any implementation, including the wrong one.

## 4. Run it and watch it fail

For a bug fix this is not optional — skill `test-writing-discipline`.

```bash
npm run test:jest -- <pattern> # one file or one describe
npm run test:watch
```

## 5. Fix the code, then run again

Read the output rather than assuming it. `npm run test` is the full local gate: lint, Jest, and the browser run.
35 changes: 35 additions & 0 deletions .claude/skills/i18n-translations/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: i18n-translations
paths: hyperformula/src/i18n/**
description: Use when adding a built-in function that needs translated names, adding a language pack, or fixing a function name that is wrong in one language. Covers the translation sources, the rules, and what breaks when a key is missing.
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`I18N.md`](../../../hyperformula/dev-docs/I18N.md) | Why translations are engine input rather than decoration, the rules, and the table of sources to translate from |
| [`PARSER.md`](../../../hyperformula/dev-docs/PARSER.md) | Only when changing separators or error literals — the lexer builds its token set from the language package |

## 2. Look the name up in a real source

Use the sources in [`I18N.md`](../../../hyperformula/dev-docs/I18N.md#where-to-find-a-translation), in the order listed. **Never invent or machine-translate a function name.** A wrong one ships to every user of that language pack and cannot be changed without breaking their formulas.

## 3. Add the key to every language file

All of them, in the same change as the function. Missing one is the usual failure, and nothing type-checks it on every path. Do not reorder existing entries while adding one — it turns a one-line diff into an unreviewable one.

## 4. Test it in that language

A test that parses a formula using the translated name and asserts the result. Not in English.

## 5. Verify

```bash
npm run test:jest -- i18n
npm run lint
```

## Adding a whole language pack

The file, its export in `hyperformula/src/i18n/languages/index.ts`, a key set identical to the other packs, a changelog entry, and `npm run bundle:languages --workspace=hyperformula` for the standalone UMD build.
42 changes: 42 additions & 0 deletions .claude/skills/pr-creation/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: pr-creation
description: Use before creating, pushing, opening, or updating a pull request in the HyperFormula repository — load this BEFORE running `gh pr create` or pushing a feature/docs/fix branch, not only when the user says "PR". Covers branch naming, the pre-flight lint/tests, the PR-then-changelog flow, and filling the GitHub PR template.
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`PULL-REQUESTS.md`](../../../dev-docs/PULL-REQUESTS.md) | Branch naming, the pre-flight gate, the template, and the one-change-per-pull-request rule |
| [`DEFINITION-OF-DONE.md`](../../../dev-docs/DEFINITION-OF-DONE.md) | Every item the change must contain before review |
| [`DOC-STANDARDS.md`](../../../dev-docs/DOC-STANDARDS.md#the-changelog) | The changelog entry that follows the pull request |

## 2. Commit on a correctly named branch

`<type>/<ticket>-<slug>`. Nothing from a private ticket in the name — the identifier alone is fine.

## 3. Run the gate and read the output

```bash
npm run test:setup-private
npm run lint
npm run test:jest
```

A green Jest run without `hyperformula/test/hyperformula-tests/` covers only the smoke tests. Confirm the suite is attached before calling it green. Do not open a pull request on a red run and describe it as ready.

## 4. Push and open the pull request

Fill in every section of the template. Tick the Types of changes boxes honestly, breaking change included.

## 5. Add the changelog entry

Read the number from the pull request URL, then skill `changelog-creation`. Push it to the same branch.

## 6. Confirm the definition of done

Then read your own diff end to end before asking anyone else to.

## While the branch is open

Update the description in the same push whenever the scope changes.
30 changes: 30 additions & 0 deletions .claude/skills/test-writing-discipline/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: test-writing-discipline
description: Use when writing, fixing, or reviewing any test for HyperFormula, and whenever a test is red during feature work. Enforces that tests prove intended behaviour rather than merely execute code, and never go "green for the sake of green".
---

## 1. Read the relevant files from `dev-docs/`

| File | Why |
|---|---|
| [`TESTING.md`](../../../dev-docs/TESTING.md#a-test-must-prove-behaviour) | The rule, the banned ways of going green, and what a hollow assertion looks like. It is short — read it now, before touching the test. |

## 2. Write the test from the requirement

Before reading the implementation. A test written from the code passes for any implementation, including the wrong one.

## 3. Run it and watch it fail

For a bug fix this is not optional: a test that has never failed proves nothing about the bug.

## 4. Fix the code, not the test

When a test is red the default assumption is that the code is wrong. Changing the expectation requires a one-sentence reason about the *specification*, not about the effort of fixing the code.

## 5. Run it again and read the output

Never claim a test passes because the reasoning is sound. And before treating green as coverage, confirm `hyperformula/test/hyperformula-tests/` is present — `npm run test:setup-private`.

## If you cannot make it pass honestly

Say so. "This test fails and I do not yet know why" is a useful report; a green run that hides it is not.
Loading
Loading