@cratis/pi 2.28.1 → 2.30.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 (22) hide show
  1. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +11 -0
  2. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/verification.json +2 -0
  3. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +11 -0
  4. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +8 -0
  5. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +28 -7
  6. package/package/corpus/skills/cratis-screenplay-event-modeling/verification.json +12 -0
  7. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +33 -1
  8. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +27 -0
  9. package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +11 -0
  10. package/package/corpus/skills/cratis-screenplay-projections/verification.json +2 -0
  11. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +11 -0
  12. package/package/corpus/skills/cratis-screenplay-read-surface/verification.json +2 -0
  13. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +11 -0
  14. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +8 -0
  15. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +11 -0
  16. package/package/corpus/skills/cratis-screenplay-ui-composition/verification.json +2 -0
  17. package/package/corpus/skills/cratis-social-feed-post/SKILL.md +93 -0
  18. package/package/corpus/skills/cratis-social-feed-post/verification.json +14 -0
  19. package/package/corpus/skills/cratis-writing-voice-and-cadence/SKILL.md +99 -0
  20. package/package/corpus/skills/cratis-writing-voice-and-cadence/verification.json +13 -0
  21. package/package/profile-catalog.json +14 -1
  22. package/package.json +1 -1
@@ -10,6 +10,17 @@ The two slice types that run without anyone pressing a button. A `capture` in a
10
10
  `Translate` slice turns outside data into events; a `reaction` in an `Automation`
11
11
  slice runs when something happens.
12
12
 
13
+ ## Locate the model
14
+
15
+ Look first in `.cratis/screenplay/` at the repository root. This is the
16
+ conventional home for consumer-owned `.play` source; do not invent another
17
+ location or search the whole repository before checking it.
18
+
19
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
20
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
21
+ questions or navigates the model in the repository's documentation; the `.play`
22
+ source is the single flow model.
23
+
13
24
  ## Verified product sources
14
25
 
15
26
  | Package | Version | Purpose |
@@ -3,6 +3,8 @@
3
3
  "input": "Translate external data into events and declare a reaction.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ { "kind": "skill-contains", "value": ".cratis/screenplay/" },
7
+ { "kind": "skill-contains", "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`" },
6
8
  { "kind": "skill-contains", "value": "cannot be mixed in one clause" },
7
9
  { "kind": "skill-contains", "value": "`where` belongs to the reaction, not to one trigger" },
8
10
  { "kind": "skill-contains", "value": "Startup` and `Shutdown" }
@@ -10,6 +10,17 @@ Everything that changes the system: the `command` that expresses intent, the
10
10
  `event` it appends, the rules that can refuse it, and the strongly-typed values
11
11
  they are all built from.
12
12
 
13
+ ## Locate the model
14
+
15
+ Look first in `.cratis/screenplay/` at the repository root. This is the
16
+ conventional home for consumer-owned `.play` source; do not invent another
17
+ location or search the whole repository before checking it.
18
+
19
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
20
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
21
+ questions or navigates the model in the repository's documentation; the `.play`
22
+ source is the single flow model.
23
+
13
24
  ## Verified product sources
14
25
 
15
26
  | Package | Version | Purpose |
@@ -3,6 +3,14 @@
3
3
  "input": "Declare a Screenplay command with validation, authorization and concurrency.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ {
7
+ "kind": "skill-contains",
8
+ "value": ".cratis/screenplay/"
9
+ },
10
+ {
11
+ "kind": "skill-contains",
12
+ "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`"
13
+ },
6
14
  {
7
15
  "kind": "skill-contains",
8
16
  "value": "A second `identifier` on the same command is an error"
@@ -17,6 +17,17 @@ assumptions. Keep asking *"and then what happens?"* after every event, every
17
17
  command, every answer. Use business language. Do not discuss databases, APIs, or
18
18
  frameworks during modeling.
19
19
 
20
+ ## Locate the model
21
+
22
+ Look first in `.cratis/screenplay/` at the repository root. This is the
23
+ conventional home for consumer-owned `.play` source; do not invent another
24
+ location or search the whole repository before checking it.
25
+
26
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
27
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
28
+ questions or navigates the model in the repository's documentation; the `.play`
29
+ source is the single flow model.
30
+
20
31
  ## Verified product sources
21
32
 
22
33
  | Package | Version | Purpose |
@@ -131,14 +142,24 @@ When one is found, ask the user to clarify, create the missing element, re-valid
131
142
  instances — ask *"can there be more than one of these at once?"* for each field.
132
143
  8. No cross-cutting infrastructure is modeled as a `Translate` slice.
133
144
 
134
- ## One file, or a folder
145
+ ## Choose a file layout
146
+
147
+ Treat `.cratis/screenplay/` as one application and choose the coarsest layout
148
+ that keeps both the source and its diffs readable:
149
+
150
+ - Keep one `application.play` while it stays readable top to bottom.
151
+ - Use one file per module when modules are simple.
152
+ - Use one file per feature when features have sub-features.
153
+ - Use one file per slice when the model is large enough that a change must be
154
+ reviewable in isolation.
135
155
 
136
- Start with one file, read top to bottom. Reach for a folder when it stops being
137
- navigable — the invoicing sample is 981 lines with **one** module.
156
+ Reviewability, not an arbitrary line count, triggers the next split. In a large
157
+ model, one slice per file makes a scripted edit's blast radius visible in the
158
+ diff instead of hiding cross-reference defects in a single enormous file.
138
159
 
139
- The folder layout mirrors the language, one folder per level: `application.play`
140
- at the root (`domain`, `import`, `concept`, `type`, `policy`, `persona`,
141
- `authentication`, `seed`), then `<Module>/<Module>.play`,
160
+ At the most granular layout, folders mirror the language, one folder per level:
161
+ `application.play` at the root (`domain`, `import`, `concept`, `type`, `policy`,
162
+ `persona`, `authentication`, `seed`), then `<Module>/<Module>.play`,
142
163
  `<Module>/…/<Feature>/<Feature>.play`, and `<Module>/…/<Slice>/<Slice>.play` for
143
164
  one slice, whole. A slice file restates its `module` and `feature`; nothing is
144
165
  written twice.
@@ -155,7 +176,7 @@ and slices come back sorted by name. Never encode meaning in order.
155
176
  ## Verify
156
177
 
157
178
  ```shell
158
- screenplay path/to/model --warnaserror
179
+ screenplay .cratis/screenplay/ --warnaserror
159
180
  ```
160
181
 
161
182
  - [ ] Zero errors **and zero warnings**. An unrecognized construct inside a slice
@@ -3,6 +3,18 @@
3
3
  "input": "Facilitate an event modeling session and land the model as .play source.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ {
7
+ "kind": "skill-contains",
8
+ "value": ".cratis/screenplay/"
9
+ },
10
+ {
11
+ "kind": "skill-contains",
12
+ "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`"
13
+ },
14
+ {
15
+ "kind": "skill-contains",
16
+ "value": "Use one file per slice"
17
+ },
6
18
  {
7
19
  "kind": "skill-contains",
8
20
  "value": "expected StateChange, StateView, Automation or Translate"
@@ -18,6 +18,17 @@ application.** Nothing in it emits C#, TypeScript or any target artifact — tha
18
18
  is Stage's job, and Stage admits less than Screenplay parses. Author against that
19
19
  reality, not against the ecosystem diagram.
20
20
 
21
+ ## Locate the model
22
+
23
+ Look first in `.cratis/screenplay/` at the repository root. This is the
24
+ conventional home for consumer-owned `.play` source; do not invent another
25
+ location or search the whole repository before checking it.
26
+
27
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
28
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
29
+ questions or navigates the model in the repository's documentation; the `.play`
30
+ source is the single flow model.
31
+
21
32
  ## Verified product sources
22
33
 
23
34
  | Package | Version | Purpose |
@@ -29,11 +40,32 @@ reality, not against the ecosystem diagram.
29
40
  Behavior below is read from the repository at tag `v4.12.1`. Reverify before
30
41
  claiming another version behaves the same.
31
42
 
43
+ ## Choose a file layout
44
+
45
+ Treat `.cratis/screenplay/` as one application and choose the coarsest layout
46
+ that keeps both the source and its diffs readable:
47
+
48
+ - Keep one `application.play` while it stays readable top to bottom.
49
+ - Use one file per module when modules are simple.
50
+ - Use one file per feature when features have sub-features.
51
+ - Use one file per slice when the model is large enough that a change must be
52
+ reviewable in isolation.
53
+
54
+ Reviewability, not an arbitrary line count, triggers the next split. In a large
55
+ model, one slice per file makes a scripted edit's blast radius visible in the
56
+ diff instead of hiding cross-reference defects in a single enormous file.
57
+ When files are split, restate their parent `module` and `feature`; the folder
58
+ compiler merges declarations by name before resolving references.
59
+
60
+ Always verify `.cratis/screenplay/` as a folder after a change. Verifying one
61
+ split file alone produces false unknown-name diagnostics for declarations held
62
+ in its siblings.
63
+
32
64
  ## Verify a model
33
65
 
34
66
  ```shell
35
67
  dotnet tool install -g Cratis.Screenplay.Tool
36
- screenplay # or: screenplay path/to/model
68
+ screenplay .cratis/screenplay/ --warnaserror
37
69
  ```
38
70
 
39
71
  The tool takes **one positional argument** — a directory or a single `.play`
@@ -0,0 +1,27 @@
1
+ {
2
+ "skill": "cratis-screenplay-model-authoring",
3
+ "input": "Author and organize a Screenplay model in a repository.",
4
+ "fixtures": [],
5
+ "assertions": [
6
+ {
7
+ "kind": "skill-contains",
8
+ "value": ".cratis/screenplay/"
9
+ },
10
+ {
11
+ "kind": "skill-contains",
12
+ "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`"
13
+ },
14
+ {
15
+ "kind": "skill-contains",
16
+ "value": "source is the single flow model"
17
+ },
18
+ {
19
+ "kind": "skill-contains",
20
+ "value": "Use one file per module"
21
+ },
22
+ {
23
+ "kind": "skill-contains",
24
+ "value": "Use one file per slice"
25
+ }
26
+ ]
27
+ }
@@ -10,6 +10,17 @@ A `projection` folds events into a read model. Its body is the **Projection
10
10
  Declaration Language**, an embedded sub-grammar with its own parser — not free
11
11
  text. This is half of every event model, and the half most easily got wrong.
12
12
 
13
+ ## Locate the model
14
+
15
+ Look first in `.cratis/screenplay/` at the repository root. This is the
16
+ conventional home for consumer-owned `.play` source; do not invent another
17
+ location or search the whole repository before checking it.
18
+
19
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
20
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
21
+ questions or navigates the model in the repository's documentation; the `.play`
22
+ source is the single flow model.
23
+
13
24
  ## Verified product sources
14
25
 
15
26
  | Package | Version | Purpose |
@@ -3,6 +3,8 @@
3
3
  "input": "Build a read model from events with the Projection Declaration Language.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ { "kind": "skill-contains", "value": ".cratis/screenplay/" },
7
+ { "kind": "skill-contains", "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`" },
6
8
  { "kind": "skill-contains", "value": "AutoMap is on by default" },
7
9
  { "kind": "skill-contains", "value": "PLAY0191" },
8
10
  { "kind": "skill-contains", "value": "every event type in the system" },
@@ -9,6 +9,17 @@ license: MIT
9
9
  What the system can be asked, and what a user sees. The `readmodel` declares the
10
10
  shape, the `query` is the entry point, and the `screen` renders it.
11
11
 
12
+ ## Locate the model
13
+
14
+ Look first in `.cratis/screenplay/` at the repository root. This is the
15
+ conventional home for consumer-owned `.play` source; do not invent another
16
+ location or search the whole repository before checking it.
17
+
18
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
19
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
20
+ questions or navigates the model in the repository's documentation; the `.play`
21
+ source is the single flow model.
22
+
12
23
  ## Verified product sources
13
24
 
14
25
  | Package | Version | Purpose |
@@ -3,6 +3,8 @@
3
3
  "input": "Declare a Screenplay query and the screen that binds to it.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ { "kind": "skill-contains", "value": ".cratis/screenplay/" },
7
+ { "kind": "skill-contains", "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`" },
6
8
  { "kind": "skill-contains", "value": "The tenant is the default and stays unstated" },
7
9
  { "kind": "skill-contains", "value": "belongs on a `from` parameter, never on a `filter`" },
8
10
  { "kind": "skill-contains", "value": "warnings, not errors" }
@@ -10,6 +10,17 @@ A `specification` is the acceptance criterion for a slice, written in the same
10
10
  document as the behavior it pins. Given/when/then, in business language, with
11
11
  concrete data.
12
12
 
13
+ ## Locate the model
14
+
15
+ Look first in `.cratis/screenplay/` at the repository root. This is the
16
+ conventional home for consumer-owned `.play` source; do not invent another
17
+ location or search the whole repository before checking it.
18
+
19
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
20
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
21
+ questions or navigates the model in the repository's documentation; the `.play`
22
+ source is the single flow model.
23
+
13
24
  ## Verified product sources
14
25
 
15
26
  | Package | Version | Purpose |
@@ -3,6 +3,14 @@
3
3
  "input": "Write given/when/then specifications for a Screenplay slice.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ {
7
+ "kind": "skill-contains",
8
+ "value": ".cratis/screenplay/"
9
+ },
10
+ {
11
+ "kind": "skill-contains",
12
+ "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`"
13
+ },
6
14
  {
7
15
  "kind": "skill-contains",
8
16
  "value": "**`then` contains either events or an error \u2014 never both.**"
@@ -10,6 +10,17 @@ Event Modeling's wireframe step is a first-class part of the language. The shell
10
10
  the reusable shapes inside it, the forms bound to commands, and the navigation
11
11
  entries other modules contribute are all declared in the `.play` model.
12
12
 
13
+ ## Locate the model
14
+
15
+ Look first in `.cratis/screenplay/` at the repository root. This is the
16
+ conventional home for consumer-owned `.play` source; do not invent another
17
+ location or search the whole repository before checking it.
18
+
19
+ `cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`. Never
20
+ hand-copy Screenplay source between repositories. Keep Markdown that explains,
21
+ questions or navigates the model in the repository's documentation; the `.play`
22
+ source is the single flow model.
23
+
13
24
  ## Verified product sources
14
25
 
15
26
  | Package | Version | Purpose |
@@ -3,6 +3,8 @@
3
3
  "input": "Declare the application shell, a screen template and a command form.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
+ { "kind": "skill-contains", "value": ".cratis/screenplay/" },
7
+ { "kind": "skill-contains", "value": "`cratis ai install` manages `.cratis/ai/`, not `.cratis/screenplay/`" },
6
8
  { "kind": "skill-contains", "value": "A form is discovered, not referenced" },
7
9
  { "kind": "skill-contains", "value": "declares no\n`fits slot`" },
8
10
  { "kind": "skill-contains", "value": "override-priority order" }
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: cratis-social-feed-post
3
+ description: Write or review a short post for a social feed such as LinkedIn, where the opening has to survive the feed's truncation, the body is plain text with no markup, and the common formatting tricks cost accessibility and reach. Use when drafting, adapting or reviewing a feed post. Do not use for documentation pages, release notes, long-form articles, or anything rendered as Markdown.
4
+ license: MIT
5
+ ---
6
+
7
+ # Social feed post
8
+
9
+ A feed post is not a short article. The feed shows a few lines and hides the rest behind a
10
+ "see more" control, so the opening is not an introduction to the point — it is the entire
11
+ advertisement for the post, and the decision to expand is itself a ranking signal.
12
+
13
+ Everything below assumes a plain-text feed with no markup rendering. The character and line
14
+ figures are unofficial approximations reported by third parties; no platform documents them,
15
+ and they move with interface, font size and device width. Treat them as a target zone and
16
+ re-check them against current official guidance rather than encoding them as durable rules.
17
+
18
+ ## The fold decides what the post is judged on
19
+
20
+ On LinkedIn the cut is modelled two ways at once and lands on whichever runs out first:
21
+
22
+ - a character budget of roughly 210 on desktop and 140 on mobile, and
23
+ - a budget of about three rendered lines.
24
+
25
+ **A blank line spends the line budget without spending characters.** A short opening on its
26
+ own line is therefore cut *earlier* than the same words inside a paragraph. Putting the hook
27
+ on its own line is usually still right, because it is what a scroller reads first, but it is
28
+ a trade rather than a free improvement.
29
+
30
+ ## What the opening must do
31
+
32
+ - **Finish a complete thought above the cut.** An opening severed mid-sentence has spent the
33
+ whole advertisement on half an idea.
34
+ - **Stay short on purpose.** A brief opening sentence is a hook doing its job. Do not rewrite
35
+ one into a longer, smoother sentence for the sake of rhythm; that removes the
36
+ advertisement. This is the most common way a well-meaning editing pass makes a post worse.
37
+ - **Earn the identifier before using it.** An opening that begins with a framework type or a
38
+ product name asks a scroller to care about a word they have no reason to recognize yet.
39
+ Name the friction first, then the mechanism.
40
+ - **Skip the throat-clearing.** The first line is the point, not a preamble to it.
41
+
42
+ Check the opening by reading only the first three lines and asking whether they are worth
43
+ expanding. If the answer depends on the fourth line, the opening is wrong.
44
+
45
+ ## Never use Unicode pseudo-formatting
46
+
47
+ Third-party tools offer pseudo-bold and pseudo-italic built from Mathematical Alphanumeric
48
+ Symbols — the characters that look like `𝗕𝗼𝗹𝗱` and `𝘐𝘵𝘢𝘭𝘪𝘤`. Do not use them.
49
+
50
+ - **Assistive technology cannot read them.** A screen-reader user hears "mathematical bold
51
+ capital T, mathematical bold small h" through an entire line, or hears nothing at all.
52
+ - **They are not the letters they resemble.** Platform search and ranking index the actual
53
+ code points, so a styled keyword is no longer that keyword and the term is lost.
54
+
55
+ Emphasis in a plain-text feed comes from sentence construction, line placement and what is
56
+ said first. A point that needs visual weight belongs in an image with its own alt text.
57
+
58
+ ## Two things that cost reach outright
59
+
60
+ - **No external link in the body.** Current ranking suppresses posts that carry one; the
61
+ convention is to put the link in a comment. Verify this at review rather than repeating it
62
+ as folklore, and never write the convention into the copy itself.
63
+ - **No engagement bait.** "Repost if…", "Tag someone who…", "Agree?" are treated as spam
64
+ signals rather than as engagement. A genuinely answerable question that follows from the
65
+ argument is a different thing and is welcome.
66
+
67
+ ## Structure that survives a phone
68
+
69
+ - One idea per post. A feed reader will not assemble two.
70
+ - Short paragraphs, one to three sentences, and visibly different from each other in length.
71
+ A column of identically sized blocks reads as a generated template before it reads as an
72
+ argument.
73
+ - Blank lines separate paragraphs and nothing else. Each one costs line budget above the fold.
74
+ - No Markdown. The feed renders none of it, so `**bold**` and `# heading` reach the reader
75
+ as literal characters.
76
+ - Hashtags on the last line only, never mid-sentence.
77
+ - Every image needs alt text. A post whose point lives only in an unlabeled image has no
78
+ point for part of its audience.
79
+
80
+ ## Before publishing
81
+
82
+ - The opening thought is complete above the fold on mobile as well as desktop.
83
+ - No pseudo-formatted characters anywhere, including the hook.
84
+ - No link in the body and no engagement bait in the close.
85
+ - Every image carries alt text, and the post still makes sense with the images removed.
86
+ - Every technical claim is one the underlying source actually supports, and any limitation
87
+ the post depends on is stated rather than implied.
88
+
89
+ ## Stop conditions
90
+
91
+ Stop and ask when the account owner, the author's perspective, the evidence behind a claim,
92
+ or an asset's permission is unresolved. Drafting a post is not authorization to publish,
93
+ schedule, tag, mention or upload it.
@@ -0,0 +1,14 @@
1
+ {
2
+ "skill": "cratis-social-feed-post",
3
+ "input": "Draft a LinkedIn post about a framework feature and format it for the feed.",
4
+ "fixtures": [],
5
+ "assertions": [
6
+ { "kind": "skill-contains", "value": "A blank line spends the line budget without spending characters" },
7
+ { "kind": "skill-contains", "value": "Never use Unicode pseudo-formatting" },
8
+ { "kind": "skill-contains", "value": "Assistive technology cannot read them" },
9
+ { "kind": "skill-contains", "value": "A brief opening sentence is a hook doing its job" },
10
+ { "kind": "skill-contains", "value": "No external link in the body" },
11
+ { "kind": "skill-contains", "value": "No engagement bait" },
12
+ { "kind": "skill-contains", "value": "unofficial approximations" }
13
+ ]
14
+ }
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: cratis-writing-voice-and-cadence
3
+ description: Find and remove the sentence constructions and structural sameness that make written material read as machine-generated, across documentation, release notes, pull request descriptions, posts and reviews, without changing any technical claim. Use when reviewing or rewriting existing prose for voice. Do not use for technical accuracy review, for original drafting, or as a reason to touch approved copy without authorization.
4
+ license: MIT
5
+ ---
6
+
7
+ # Writing voice and cadence
8
+
9
+ Material that is factually correct can still be unreadable in a way nobody can name. The
10
+ usual diagnosis is "it sounds like AI wrote it", and the usual response is to rewrite by feel,
11
+ which produces a second machine voice rather than a human one.
12
+
13
+ The failure is measurable, and it has two halves. The smaller half is a set of sentence
14
+ constructions used far past the density a person would use them. The larger half is
15
+ structural sameness across a whole body of material: a reader meeting the second piece
16
+ recognizes the format before reading a word of it.
17
+
18
+ ## The constructions
19
+
20
+ None of these is wrong. One of any of them is a good sentence. What turns them into a tell is
21
+ recurrence.
22
+
23
+ | Construction | What it looks like |
24
+ | --- | --- |
25
+ | **Corrective tail** | "…, not a fresh count." The sentence ends by correcting itself |
26
+ | **Balanced semicolon** | Two clauses of equal weight either side of a semicolon |
27
+ | **"rather than"** | The same correction carried by a different connective |
28
+ | **Em-dash pivot** | The dash used to swing into a closing clause |
29
+ | **"That is what X is for"** | A pointer sentence standing in for an explanation |
30
+
31
+ To measure rather than guess, count them. Searching for `, not a`, `; ` between two clauses,
32
+ `rather than`, and an em-dash followed by a short closing clause takes a few minutes across a
33
+ directory and turns an argument about taste into a number. Reading a draft aloud catches all
34
+ of them faster than any tool.
35
+
36
+ ## Structural sameness is the more damaging half
37
+
38
+ Look at ten pieces together, not one at a time:
39
+
40
+ - **Every piece the same length and shape.** If most of them are three or four paragraphs
41
+ with the same paragraph weights, that is a template.
42
+ The fix for a template is not a better template.
43
+ Do not adopt a target shape: vary the paragraph count, and let paragraphs differ visibly
44
+ in weight.
45
+ - **Every sentence the same length.** When sentence length barely varies within a piece, the
46
+ result is a monotone regardless of the words. Let it swing between four words and twenty-five.
47
+ - **Every piece opening the same way.** An abstract noun phrase making a declarative
48
+ assertion — "A screen that needs…", "A registration test can…" — is one move. Alternate it
49
+ with a question, a direct address, a concrete moment, or a number.
50
+
51
+ ## Address somebody
52
+
53
+ - **Say "you".** Material that tells a reader what to do should address that reader.
54
+ - **Attributed writing should sound attributed.** Prose published under a person's name and
55
+ written entirely in the impersonal third person reads as documentation wearing a byline.
56
+ Opinion, judgement and preference belong to the named author and are theirs to give.
57
+ - **First person is not a licence to invent.** Opinion is allowed; invented experience,
58
+ anecdotes that did not happen, and claimed observations the author did not make are not.
59
+ Where a named author owns the material, it stays blocked until that author reviews it.
60
+ - **A question is allowed when the piece has earned it.** A question that follows from the
61
+ argument is not bait; one bolted on to harvest a response is.
62
+
63
+ ## Never trade a claim for a smoother sentence
64
+
65
+ This is the part that makes a voice pass dangerous, and it is the reason to do one carefully
66
+ rather than quickly.
67
+
68
+ The risk is not an obvious rewrite. It is a hedge dissolving into nicer phrasing. "There is
69
+ no need to" becomes "without needing to", and a limit quietly widens. "Not its meaning"
70
+ becomes "and leaves its meaning alone", and a distinction softens. Both read better. Both
71
+ changed what the text asserts.
72
+
73
+ Before accepting any rewrite, confirm that:
74
+
75
+ - every identifier and every number present before is still present, and none was invented;
76
+ - every hedging word — not, never, only, may, unless, until — survives in substance;
77
+ - every stated limitation survives, including one that reads as an awkward caveat, because it
78
+ is a caveat and it is deliberate;
79
+ - the closing limitation or evidence statement is not thinned, relocated into a subordinate
80
+ clause, or dropped because it spoiled the ending.
81
+
82
+ A mechanical check over identifiers, numbers and hedge counts catches most of this before a
83
+ human reads a word, and is worth writing once for any corpus large enough to need a pass.
84
+
85
+ ## Work in tranches that can be read
86
+
87
+ Rewriting is not a batch operation. Any body of material large enough to have a detectable
88
+ voice is too large to rewrite in one pass with judgement, and a fast pass replaces one
89
+ detectable format with another. Rewrite a tranche, read it, and only then continue.
90
+
91
+ Where material carries a recorded approval, a rewrite invalidates it. Recording a fresh
92
+ approval over copy nobody has read makes the record assert something false, after which every
93
+ downstream check agrees with it. Size the tranche to what its owner will actually read.
94
+
95
+ ## Stop conditions
96
+
97
+ Stop when a rewrite would change what the material claims, when the named author has not
98
+ accepted a perspective being introduced on their behalf, or when the material is under an
99
+ approval that the rewrite would invalidate without authorization to refresh it.
@@ -0,0 +1,13 @@
1
+ {
2
+ "skill": "cratis-writing-voice-and-cadence",
3
+ "input": "This documentation reads like it was generated. Make it sound human without changing what it says.",
4
+ "fixtures": [],
5
+ "assertions": [
6
+ { "kind": "skill-contains", "value": "Never trade a claim for a smoother sentence" },
7
+ { "kind": "skill-contains", "value": "The fix for a template is not a better template" },
8
+ { "kind": "skill-contains", "value": "every hedging word" },
9
+ { "kind": "skill-contains", "value": "First person is not a licence to invent" },
10
+ { "kind": "skill-contains", "value": "Structural sameness is the more damaging half" },
11
+ { "kind": "skill-contains", "value": "Rewrite a tranche, read it, and only then continue" }
12
+ ]
13
+ }
@@ -43,6 +43,7 @@
43
43
  "cratis/cli",
44
44
  "cratis/cli/terminal-workbench",
45
45
  "cratis/components",
46
+ "cratis/content",
46
47
  "cratis/documentation",
47
48
  "cratis/full",
48
49
  "cratis/full/csharp",
@@ -559,10 +560,22 @@
559
560
  "typescript"
560
561
  ]
561
562
  },
563
+ {
564
+ "id": "cratis/content",
565
+ "availableTargets": [
566
+ "cratis-social-feed-post",
567
+ "cratis-writing-voice-and-cadence"
568
+ ],
569
+ "languages": [
570
+ "markdown",
571
+ "language-agnostic"
572
+ ]
573
+ },
562
574
  {
563
575
  "id": "cratis/documentation",
564
576
  "availableTargets": [
565
- "cratis-documentation-writing"
577
+ "cratis-documentation-writing",
578
+ "cratis-writing-voice-and-cadence"
566
579
  ],
567
580
  "languages": [
568
581
  "markdown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/pi",
3
- "version": "2.28.1",
3
+ "version": "2.30.0",
4
4
  "description": "Configuration-aware Cratis AI integration for Pi",
5
5
  "type": "module",
6
6
  "files": [