From bd497aefd5e5f939c6f3d50e66aa2f150558b5bc Mon Sep 17 00:00:00 2001 From: Wanja Krah Date: Wed, 28 Oct 2026 07:26:47 +0100 Subject: [PATCH] Spec driven development setup --- AGENTS.md | 12 ++ skills/LICENSE.mattpocock | 21 ++++ skills/README.md | 22 ++++ skills/grill-me/SKILL.md | 7 ++ skills/grill-me/agents/openai.yaml | 5 + skills/grilling/SKILL.md | 30 +++++ skills/grilling/agents/openai.yaml | 3 + skills/upstream.json | 9 ++ specs/README.md | 4 + specs/S1_School-JSON-import-export.md | 160 ++++++++++++++++++++++++++ 10 files changed, 273 insertions(+) create mode 100644 AGENTS.md create mode 100644 skills/LICENSE.mattpocock create mode 100644 skills/README.md create mode 100644 skills/grill-me/SKILL.md create mode 100644 skills/grill-me/agents/openai.yaml create mode 100644 skills/grilling/SKILL.md create mode 100644 skills/grilling/agents/openai.yaml create mode 100644 skills/upstream.json create mode 100644 specs/README.md create mode 100644 specs/S1_School-JSON-import-export.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..546b2e4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# Project skills and specifications + +- Project skills are stored in `skills/`; specifications belong in `specs/`. +- Use `grill-me` only when the user explicitly requests it, for example + `Use grill-me to review this plan` or `Gebruik grill-me voor dit ontwerp`. +- Before using it, read `skills/grill-me/SKILL.md` and its dependency + `skills/grilling/SKILL.md`. If no dedicated Skill tool is available, load these + files directly and follow their instructions within the available tools. +- Installing or mentioning a skill does not start an interview. Do not apply + `grilling` automatically to ordinary development requests. +- Keep the upstream skill files unchanged. Source revision and license are + recorded in `skills/upstream.json` and `skills/LICENSE.mattpocock`. diff --git a/skills/LICENSE.mattpocock b/skills/LICENSE.mattpocock new file mode 100644 index 0000000..f1dd2c0 --- /dev/null +++ b/skills/LICENSE.mattpocock @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Matt Pocock + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 0000000..d747095 --- /dev/null +++ b/skills/README.md @@ -0,0 +1,22 @@ +# Project skills + +Reusable agent instructions for this repository. Invoke them explicitly in the +conversation, for example: + +> Gebruik grill-me om de JSON-import en -export met mij uit te werken. + +## Installed skills + +| Skill | Purpose | +| --- | --- | +| [grill-me](grill-me/SKILL.md) | Entry point for reviewing a plan or design through questions. | +| [grilling](grilling/SKILL.md) | Interview instructions required by `grill-me`. | + +The skills are copied from [Matt Pocock's skills.sh listing](https://skills.sh/mattpocock/skills/grill-me) +and its [upstream repository](https://github.com/mattpocock/skills). +The exact upstream commit and paths are recorded in [upstream.json](upstream.json). +The upstream [MIT license](LICENSE.mattpocock) is included. + +These project-local files are available to the agent from the next conversation +turn through the instructions in the root `AGENTS.md`. They are not installed +globally. Updating them requires explicitly downloading a new upstream revision. diff --git a/skills/grill-me/SKILL.md b/skills/grill-me/SKILL.md new file mode 100644 index 0000000..3947ff9 --- /dev/null +++ b/skills/grill-me/SKILL.md @@ -0,0 +1,7 @@ +--- +name: grill-me +description: A relentless interview to sharpen a plan or design. +disable-model-invocation: true +--- + +Call the Skill tool with "grilling". diff --git a/skills/grill-me/agents/openai.yaml b/skills/grill-me/agents/openai.yaml new file mode 100644 index 0000000..4d6fb0c --- /dev/null +++ b/skills/grill-me/agents/openai.yaml @@ -0,0 +1,5 @@ +interface: + display_name: "Grill Me" + short_description: "Sharpen a plan through interview" +policy: + allow_implicit_invocation: false diff --git a/skills/grilling/SKILL.md b/skills/grilling/SKILL.md new file mode 100644 index 0000000..df69d99 --- /dev/null +++ b/skills/grilling/SKILL.md @@ -0,0 +1,30 @@ +--- +name: grilling +description: Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases. +--- + +Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it. + +Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled: the questions you can ask _now_ without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round. + +Format a round like so: + +``` +❓ **Q1** - ****: + +➡️ + +--- + +❓ **Q2** - ****: + +➡️ +``` + +Word each question so "yes" accepts your recommended answer. + +Each round the user answers reshapes the tree: settled decisions push the frontier outward and unblock questions that depended on them. Recompute the frontier and ask the next round. A question whose answer depends on another question still open in this round belongs to a _later_ round, not this one. + +Finding _facts_ is your job, never the user's. When a frontier question needs a fact from the environment (filesystem, tools, etc.), dispatch a sub-agent to find it; don't ask the user for anything you could look up yourself. Don't block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait for the sub-agent to report; ask the rest of the frontier now. The _decisions_ are the user's: put each to them and wait. + +The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Do not act on it until the user confirms you have reached a shared understanding. diff --git a/skills/grilling/agents/openai.yaml b/skills/grilling/agents/openai.yaml new file mode 100644 index 0000000..ddbdb96 --- /dev/null +++ b/skills/grilling/agents/openai.yaml @@ -0,0 +1,3 @@ +interface: + display_name: "Grilling" + short_description: "Stress-test thinking a round of questions at a time" diff --git a/skills/upstream.json b/skills/upstream.json new file mode 100644 index 0000000..d3781de --- /dev/null +++ b/skills/upstream.json @@ -0,0 +1,9 @@ +{ + "repository": "https://github.com/mattpocock/skills", + "commit": "59db609eb1e18aaf59b63284d0e52255aff0c63c", + "source": "https://skills.sh/mattpocock/skills/grill-me", + "skills": { + "grill-me": "skills/productivity/grill-me", + "grilling": "skills/productivity/grilling" + } +} diff --git a/specs/README.md b/specs/README.md new file mode 100644 index 0000000..2d96b97 --- /dev/null +++ b/specs/README.md @@ -0,0 +1,4 @@ +# Specifications + +Store feature specifications, requirements and agreed design decisions here. +Use descriptive Markdown filenames, for example `school-json-import-export.md`. diff --git a/specs/S1_School-JSON-import-export.md b/specs/S1_School-JSON-import-export.md new file mode 100644 index 0000000..0b8fba6 --- /dev/null +++ b/specs/S1_School-JSON-import-export.md @@ -0,0 +1,160 @@ +# S1 — School JSON import and export + +Status: agreed after the grill-me review. + +## User story + +**As** a school maintainer, +**I want** to export and import my dance school as a JSON file, +**so that** I can store my school configuration locally while the application does +not offer persistent storage, +**and so that** I retain ownership of my data. + +## Intent + +Export downloads a complete snapshot of one dance school to a local JSON file. +Import restores that snapshot as a new school or replaces the corresponding +existing school after explicit confirmation. + +## Scope + +### In scope + +- Exporting an existing school to a readable JSON file. +- Importing a school that does not exist or no longer exists. +- Replacing an existing school with the complete imported snapshot. +- Preserving all configured school data and relationships, including: + - School details and its persistent unique key. + - Dancers and their details. + - Dance groups, types, age ranges and styles. + - Dancer memberships, including dancers belonging to multiple groups. + - Shows, dates, day parts and any existing group assignments to day parts. + - Coaches and any existing links between coaches and groups. +- Full validation, an import preview, confirmation and clear error messages. + +Preserving existing data does not add management screens for coaches or the +ability to assign groups to show day parts. + +### Out of scope + +- Merging an imported snapshot with an existing school. +- Persistent server-side storage. + +The existing-school prompt includes a merge option, but selecting it only displays +that merging is not yet supported. It must not change any data. Implementing merge +behavior requires a separate specification. + +## Identity and file format + +- Every school has a persistent unique key that is included in exports and + preserved through imports and subsequent exports. +- Import identifies an existing school by that key, not by its name or a + runtime-generated numeric ID. The key remains meaningful after a server restart. +- A school with the same name but a different unique key is a separate school. +- A file contains one school and all data needed to restore it without accessing + another school or the original server state. +- The readable, documented JSON format includes a `formatVersion` field. +- Users may edit the JSON manually. Edited files undergo the same validation as + files produced by the application. +- Unknown fields and unsupported format versions are rejected explicitly; data + must not be silently ignored. +- Relationships in the file must be unambiguous and restored correctly. Internal + numeric IDs need not remain identical, provided school identity and all + relationships are preserved without collisions with other schools. + +## Export flow + +1. The maintainer opens an existing school's management screen. +2. The maintainer selects the JSON export option. +3. The application downloads a JSON file containing a consistent, complete + snapshot of that school. +4. Export does not change the school or any other application data. + +## Import flow + +1. The maintainer selects the JSON import option and chooses a local file. +2. The application validates the entire file before changing any stored data. +3. For a valid file, the application shows a preview containing the school name + and the numbers of dancers, dance groups and shows. +4. If the unique school key is unknown, the maintainer confirms adding the school + or cancels the import. +5. If the key already exists, the application identifies the school that would be + replaced and offers replace, merge or cancel: + - **Replace:** explicitly warn that the existing school is replaced completely. + After confirmation, replace all its configured data with the snapshot. + - **Merge:** show a message that this functionality is not yet supported and + leave all data unchanged. + - **Cancel:** leave all data unchanged. +6. A confirmed import is committed as one operation. The application must not + expose a partially imported or partially replaced school. +7. If validation or importing fails, show **"Import niet gelukt"** together with + the concrete cause. The user can correct the file and try again. + +## Validation and failure behavior + +- Validate JSON syntax, the supported file structure and format version, required + data, field values and all relationships before applying the import. +- Reject unknown fields and references to missing objects, including a group's + reference to a dancer absent from the snapshot. +- A failure must not create a partial school, partially replace an existing + school, or modify another school. +- A replacement must not remove the original school until the complete + replacement can succeed. If it fails, the original school remains intact. +- Error messages explain the cause specifically enough to correct the file. + For example: **"Import niet gelukt: groep Hiphop verwijst naar een onbekende + danser."** + +## Acceptance criteria + +### Export + +1. Each existing school offers a JSON-file export that can be downloaded and + stored locally. +2. The export includes its persistent unique key, `formatVersion`, all configured + data listed in scope and all relationships between those objects. +3. Exporting leaves the application data unchanged. +4. A school with no dancers, groups or shows can be exported and imported. + +### Adding a school + +5. A valid file with an unknown school key shows the preview before any data is + added. Confirming creates the complete school; cancelling changes nothing. +6. An exported school can be restored after the original school is deleted or + the in-memory server state is lost. +7. An existing school with the same name but a different key is neither replaced + nor treated as the same school. + +### Replacing a school + +8. A valid file with an existing school key prompts the user to replace, merge or + cancel and clearly identifies the existing school. +9. Confirming replacement replaces the complete configuration. Objects and + relationships present only in the previous configuration are not retained as + part of the replaced school. +10. Other schools remain unchanged by replacement. +11. Selecting merge displays that merging is not yet supported and changes + nothing. Cancelling also changes nothing. + +### Validation and errors + +12. Malformed JSON, unsupported format versions, unknown fields, missing required + data, invalid field values and unresolved relationships cause the entire + import to fail. +13. Each failed import displays **"Import niet gelukt"** and a concrete cause. +14. A failed new-school import adds nothing. A failed replacement preserves the + entire existing school. Other schools are unaffected in either case. +15. After a failure, the user can select a corrected file and retry. + +### Round-trip integrity + +16. Exporting and importing a school preserves every configured field and + relationship, including a dancer's membership in multiple groups, shows and + their day parts, and any existing coaches or day-part group assignments. +17. Exporting the restored school again preserves its unique school key and + equivalent configuration, even if internal numeric IDs changed. + +## Implementation handoff + +This specification records agreed behavior. Backend endpoints, the detailed JSON +schema and frontend implementation remain implementation work; this review does +not implement the feature.