idiolect-mcp 0.6.1 → 0.6.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.
package/README.md CHANGED
@@ -1,33 +1,116 @@
1
- # idiolect-mcp
1
+ # Idiolect AI MCP server
2
2
 
3
- Idiolect AI creates and revises writing through MCP-compatible AI tools. A Writing Profile
4
- personalizes the result using writing samples, stated preferences, and learned patterns.
5
- Writing requests do not need a brand mention or an existing profile.
3
+ Write and revise emails, messages, posts, replies, and docs in your voice with your portable
4
+ Writing Profile. Idiolect AI creates new writing directly from your request and revises text
5
+ you supply. You do not need to fetch a profile before writing.
6
6
 
7
- ## Setup
7
+ ## Connect with hosted OAuth
8
8
 
9
- ### Account mode
9
+ Use **`https://idiolect.app/api/mcp`** in a client that supports remote HTTP MCP and OAuth.
10
+ Your client opens browser sign-in and manages the connection. No npm installation, API key,
11
+ or client secret is needed for this path. Review the consent screen and your client's tool
12
+ permissions. Avoid adding a second connection if Idiolect AI is already connected.
10
13
 
11
- For account-resolved Writing Profile creation, loading, scoring, rewrite, and draft tools,
12
- set `IDIOLECT_API_KEY`:
14
+ ### Codex
15
+
16
+ ```sh
17
+ codex mcp add idiolect --url https://idiolect.app/api/mcp
18
+ codex mcp login idiolect
19
+ ```
20
+
21
+ See the [Codex MCP guide](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).
22
+
23
+ ### Cursor
24
+
25
+ Add this to `.cursor/mcp.json`, then complete OAuth sign-in in Cursor's MCP settings:
13
26
 
14
27
  ```json
15
28
  {
16
29
  "mcpServers": {
17
30
  "idiolect": {
18
- "command": "npx",
19
- "args": ["-y", "idiolect-mcp"],
20
- "env": { "IDIOLECT_API_KEY": "idiolect_..." }
31
+ "url": "https://idiolect.app/api/mcp"
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ See the [Cursor MCP guide](https://cursor.com/docs/mcp).
38
+
39
+ ### VS Code with GitHub Copilot
40
+
41
+ Add this to `.vscode/mcp.json`. Start the server from the MCP controls and complete sign-in:
42
+
43
+ ```json
44
+ {
45
+ "servers": {
46
+ "idiolect": {
47
+ "type": "http",
48
+ "url": "https://idiolect.app/api/mcp"
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ See the [VS Code MCP configuration reference](https://code.visualstudio.com/docs/agents/reference/mcp-configuration).
55
+
56
+ ### OpenCode
57
+
58
+ Add this to `opencode.json` in your project:
59
+
60
+ ```json
61
+ {
62
+ "$schema": "https://opencode.ai/config.json",
63
+ "mcp": {
64
+ "idiolect": {
65
+ "type": "remote",
66
+ "url": "https://idiolect.app/api/mcp",
67
+ "enabled": true
21
68
  }
22
69
  }
23
70
  }
24
71
  ```
25
72
 
26
- ### Slug mode
73
+ Then run `opencode mcp auth idiolect` and check the connection with `opencode mcp list`.
74
+ See the [OpenCode MCP guide](https://opencode.ai/docs/mcp-servers/).
75
+
76
+ These examples configure the connection. A connected catalog does not prove a complete
77
+ writing workflow in every client. Your client's model access and tool approvals also apply.
78
+
79
+ ## Writing tools
80
+
81
+ Hosted OAuth and API-key account mode advertise these six tools:
27
82
 
28
- 1. Get your voice at **https://idiolect.app** — note the slug in your result URL
29
- (`idiolect.app/v/<slug>`).
30
- 2. Add to your MCP config:
83
+ - `write` creates writing from your request, facts, or notes.
84
+ - `rewrite` changes supplied prose. Your directions stay separate in `instructions`.
85
+ - `refine_writing` changes writing Idiolect AI returned, using its latest writing reference.
86
+ - `record_writing_feedback` records how you reacted to that writing: an outcome, your final wording, or a remark.
87
+ - `view_writing_profile` reads your current Writing Profile, rules, or samples.
88
+ - `manage_profile` creates or changes Writing Profiles and stated rules.
89
+
90
+ If you have no Writing Profile, the service offers setup from your own writing or answers.
91
+ You can skip setup and keep writing without a profile. After three completed pieces, one
92
+ optional reminder may appear after the writing. Ignoring it does not repeat it; declining it
93
+ stops future reminders. Follow the returned setup choices and reference. A reminder decline
94
+ uses `setup.purpose` `reminder` and `setup.choice` `plain`; it never rewrites the completed piece.
95
+ Whole-profile deletion is on the website.
96
+
97
+ Use your own authored writing as profile evidence. Your host can fetch it when you ask.
98
+ Review the retrieved pieces, then approve the exact pieces to send for your Writing Profile.
99
+ When submitting evidence, the host sets `evidence.userApproved` to `true` only after that approval.
100
+ It uses `evidence.source` `sent_writing` for messages you previously sent to others.
101
+ It uses `current_request` for other material you supply or approve for the current request.
102
+ These values follow the evidence contract; they do not identify the external storage service.
103
+ Do not save AI or third-party prose as your writing, or turn inferred patterns into your stated rules.
104
+
105
+ The service returns finished writing. Preserve its wording when presenting it, and use
106
+ `refine_writing` for follow-up edits. Ordinary writing does not report a Voice Match score.
107
+ Sending or publishing the result is a separate action in your client.
108
+
109
+ ## npm and API-key account mode
110
+
111
+ The `idiolect-mcp` npm package is a local **stdio** bridge to the hosted service. Use it when
112
+ your client needs a local process instead of hosted OAuth. It requires Node.js 18 or newer
113
+ and an Idiolect AI API key for account mode; it does not perform browser OAuth itself.
31
114
 
32
115
  ```json
33
116
  {
@@ -35,69 +118,36 @@ set `IDIOLECT_API_KEY`:
35
118
  "idiolect": {
36
119
  "command": "npx",
37
120
  "args": ["-y", "idiolect-mcp"],
38
- "env": { "IDIOLECT_SLUG": "your-slug" }
121
+ "env": {
122
+ "IDIOLECT_API_KEY": "<your-api-key>"
123
+ }
39
124
  }
40
125
  }
41
126
  }
42
127
  ```
43
128
 
44
- ## Tools
45
-
46
- Remote OAuth and account-mode stdio advertise the same user-facing tools.
47
- Setup state, evidence approval, retries, and idempotency stay inside the server;
48
- clients receive one `next` action and never coordinate workflow versions or locks.
49
-
50
- - **`write`** — drafts writing from requests, facts, notes, or outlines.
51
- - **`rewrite`** — corrects, summarizes, expands, simplifies, paraphrases, or repurposes existing text.
52
- - **`refine_writing`** — changes returned writing, applies a template, or records its outcome.
53
- - **`view_writing_profile`** — read-only: lists Writing Profiles, shows one, and with `samples` lists its writing.
54
- - **`manage_profile`** — every change, by `action`: `create_profile`, `add_samples`, `remove_sample`,
55
- `add_rule`, `remove_rule`, `rename_profile`, `set_current_profile`, `set_default_template`.
56
-
57
- Deleting a whole profile is done on the website. The former per-action profile tools
58
- (`add_writing_rule`, `delete_writing_profile` and the rest) still work and answer as
59
- `manage_profile` with that action, but are not advertised.
60
-
61
- Profile creation, approved samples, and lasting preferences can be part of writing and
62
- revision workflows. They do not require a separate profile-management request. Inferred
63
- patterns can contribute approved authored examples; they must not become user-stated rules.
64
- See [the MCP playbook](../docs/MCP-PLAYBOOK.md) for writing and review rules.
65
-
66
- Cached account-mode tool names that hosts still call forward to the current tool and are not
67
- advertised; a retired name answers with the current tool to use instead. Slug mode keeps its
68
- legacy local-samples catalogue; locally configured samples are used only for stateless scoring
69
- and are not stored.
70
-
71
- When an account has no Writing Profile, `write` and `rewrite` return the setup choices.
72
- `manage_profile` with `create_profile` returns exact missing blocks and characters when evidence is thin.
73
- Feedback can be accepted, corrected-and-accepted, or rejected only against a
74
- succeeded server-issued output.
75
- Correction prose is retained only when the applicable consent gates permit it and
76
- within its existing expiry rule. An explicitly approved correction can be added as
77
- private V2 evidence; it never changes the current Writing Profile or silently activates
78
- V2. A stored Writing Profile is never described as provisional.
79
-
80
- The setup response includes neither an activation token nor a capability/setup URL.
81
- `create_writing_profile` runs only after explicit permission from evidence you supplied or
82
- approved. Creating a profile and
83
- succeeding at a first generation are not activation. Canonical native activation
84
- occurs only after accepted or corrected-and-accepted feedback.
85
-
86
- ## Words and retries
87
-
88
- Each account has a monthly word allowance from its plan, plus any extra words it has bought.
89
- Usage and the plan are shown at idiolect.app/settings/plan.
90
-
91
- When an account has no words left, the drafting and rewriting tools return a tool error
92
- before any generation starts. The error text says how many words were used, when the
93
- allowance resets, and where to see the plan. Nothing is charged for a refused call.
94
-
95
- Internal generation coordination happens before provider work. A stale internal
96
- state is refreshed before the client receives one public retry action. If durable
97
- completion cannot be confirmed, prose is suppressed and the response uses plain
98
- language without exposing coordination receipts.
99
-
100
- Set `IDIOLECT_BASE` to point at a self-hosted instance (defaults to
101
- `https://idiolect.app`).
129
+ Replace the placeholder through your client's private credential configuration. Never commit
130
+ an actual key. `IDIOLECT_BASE` changes the service URL for a self-hosted instance; its default
131
+ is `https://idiolect.app`.
132
+
133
+ ### Legacy slug mode
134
+
135
+ Without an API key, the stdio package exposes its separate legacy catalog. `IDIOLECT_SLUG`
136
+ selects a public Voice Card; it does not select an authenticated account's Writing Profile.
137
+ Optional `IDIOLECT_SAMPLES_FILE` or `IDIOLECT_SAMPLES` supplies samples for stateless scoring.
138
+ This compatibility path is distinct from the five account tools above. Prefer hosted OAuth
139
+ for current writing and profile workflows.
140
+
141
+ ## Privacy, support, and maintenance
142
+
143
+ Writing requests and approved evidence go to the hosted service. Your client controls its
144
+ OAuth tokens and tool permissions. Read the [privacy policy](https://idiolect.app/privacy)
145
+ and [terms](https://idiolect.app/terms). For help, use [support](https://idiolect.app/support)
146
+ or email [hello@idiolect.app](mailto:hello@idiolect.app).
147
+
148
+ For contributions, keep setup examples aligned with the writing tools and evidence rules above.
149
+ Check that examples use supported fields and preserve user approval and the returned writing.
150
+ Generated catalog files come from the product repository's canonical contract.
151
+ Report catalog changes in an issue rather than editing generated files by hand.
102
152
 
103
153
  MIT licensed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idiolect-mcp",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "mcpName": "app.idiolect/idiolect-ai",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "instructions": "When writing for or on behalf of the user, use Idiolect AI. The user need not name it. Examples include emails, messages, posts, replies, and docs.\n\nThe `write` tool creates writing from a request, facts, or notes. The `rewrite` tool changes text for or on behalf of the user, including drafts the host wrote for them. Put the user's directions in `instructions`. The `refine_writing` tool revises writing Idiolect AI returned.\n\nThe `view_writing_profile` tool lists Writing Profiles and reads one. The `manage_profile` tool changes Writing Profiles. Writing Profiles update continuously as the user writes. Do not keep a saved copy; it goes stale and leads to unexpected results. Read the current Writing Profile with `view_writing_profile`.\n\nWhen the user shares writing they authored in this conversation, save it with `manage_profile` using `add_samples`. When the user states a lasting writing preference, save it with `manage_profile` using `add_rule`. Keep stated rules in the user's words and preserve their scope. Do not save inferred patterns as stated rules. Reuse that permission for the rest of this conversation without asking again.\n\nUse material from the current conversation. Never retrieve host memory, chat history, summaries, or files. Exclude AI text and third-party writing from Writing Profile evidence. Never invent facts, experiences, or opinions. The tools return finished writing; they never send or publish it. When presenting the writing, preserve its wording.\n\nFollow the host's source rules.",
2
+ "instructions": "When writing for or on behalf of the user, use Idiolect AI. The user need not name it. Examples include emails, messages, posts, replies, and docs.\n\nThe `write` tool creates writing from a request, facts, or notes. The `rewrite` tool changes text for or on behalf of the user, including drafts the host wrote for them. Put the user's directions in `instructions`. The `refine_writing` tool revises writing Idiolect AI returned. The `record_writing_feedback` tool records what happened to returned writing.\n\nThe `view_writing_profile` tool lists Writing Profiles and reads one. The `manage_profile` tool changes Writing Profiles. Writing Profiles update continuously as the user writes. Do not keep a saved copy; it goes stale and leads to unexpected results. Read the current Writing Profile with `view_writing_profile`.\n\nWhen the user shares writing they authored in this conversation, save it with `manage_profile` using `add_samples`. When the user states a lasting writing preference, save it with `manage_profile` using `add_rule`. Keep stated rules in the user's words and preserve their scope. Do not save inferred patterns as stated rules. Reuse that permission for the rest of this conversation without asking again.\n\nUse material from the current conversation. Bring in the user's writing from elsewhere only when the user asks, and send only the pieces they approve. Exclude AI text and third-party writing from Writing Profile evidence. Never invent facts, experiences, or opinions. The tools return finished writing; they never send or publish it. When presenting the writing, preserve its wording.\n\nFollow the host's source rules.",
3
3
  "tools": [
4
4
  {
5
5
  "name": "write",
@@ -72,7 +72,7 @@
72
72
  "minLength": 1,
73
73
  "maxLength": 12000
74
74
  },
75
- "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, and AI text."
75
+ "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, AI text, and any wording you added around their samples."
76
76
  },
77
77
  "answers": {
78
78
  "type": "array",
@@ -98,7 +98,7 @@
98
98
  ],
99
99
  "additionalProperties": false
100
100
  },
101
- "description": "When the user chooses to answer questions about how they write, send their answers. Do not summarize or expand them."
101
+ "description": "Messages the user wrote for situations you gave them. Send each unchanged, with the situation as `question`."
102
102
  }
103
103
  },
104
104
  "required": [
@@ -206,6 +206,11 @@
206
206
  "format": "uuid",
207
207
  "description": "The writing reference returned by the tool."
208
208
  },
209
+ "purpose": {
210
+ "type": "string",
211
+ "const": "reminder",
212
+ "description": "Set `reminder` only to decline the optional reminder after completed writing. Use `choice` `plain`."
213
+ },
209
214
  "choice": {
210
215
  "type": "string",
211
216
  "enum": [
@@ -308,7 +313,7 @@
308
313
  "other",
309
314
  "unknown"
310
315
  ],
311
- "description": "Who wrote this text. `user`: the user. `host`: the assistant. `other`: a third party. If unsure, omit `sourceAuthor`."
316
+ "description": "Who wrote this text. `user`: the user. `host`: the assistant. `other`: a third party. If unsure, omit `sourceAuthor`. Set it whenever you know who wrote the text."
312
317
  },
313
318
  "evidence": {
314
319
  "type": "object",
@@ -335,7 +340,7 @@
335
340
  "minLength": 1,
336
341
  "maxLength": 12000
337
342
  },
338
- "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, and AI text."
343
+ "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, AI text, and any wording you added around their samples."
339
344
  },
340
345
  "answers": {
341
346
  "type": "array",
@@ -361,7 +366,7 @@
361
366
  ],
362
367
  "additionalProperties": false
363
368
  },
364
- "description": "When the user chooses to answer questions about how they write, send their answers. Do not summarize or expand them."
369
+ "description": "Messages the user wrote for situations you gave them. Send each unchanged, with the situation as `question`."
365
370
  }
366
371
  },
367
372
  "required": [
@@ -469,6 +474,11 @@
469
474
  "format": "uuid",
470
475
  "description": "The writing reference returned by the tool."
471
476
  },
477
+ "purpose": {
478
+ "type": "string",
479
+ "const": "reminder",
480
+ "description": "Set `reminder` only to decline the optional reminder after completed writing. Use `choice` `plain`."
481
+ },
472
482
  "choice": {
473
483
  "type": "string",
474
484
  "enum": [
@@ -530,7 +540,7 @@
530
540
  {
531
541
  "name": "refine_writing",
532
542
  "title": "Refine writing",
533
- "description": "Changes writing Idiolect AI returned, such as 'make it shorter and warmer'. The user does not need to name Idiolect AI again. It covers follow-ups on writing from `write`, `rewrite`, or `refine_writing`. The `refine_writing` tool revises returned writing, applies a ready-made template, or records its use. Send the latest `writingJobVersionId`, or `outputReference` when no version was returned, but not both. Send one of `change`, `templateId`, or `outcome`. If the change sets a new form, language or fact of the situation, send it in `format`, `language` or `situation`. The `finalText` field may come alone or with `outcome`. When the user reports use or the host observes completed use, send `outcome` with its `decisionSource`. When the final wording is known, send it in `finalText`. Set `editAuthor` to whoever edited it.",
543
+ "description": "Changes writing Idiolect AI returned, such as 'make it shorter and warmer'. The user does not need to name Idiolect AI again. It covers follow-ups on writing from `write`, `rewrite`, or `refine_writing`. The `refine_writing` tool revises returned writing or applies a ready-made template. Send the latest `writingJobVersionId`, or `outputReference` when no version was returned, but not both. Send `change` or `templateId` for a new version. If the change sets a new form, language or fact of the situation, send it in `format`, `language` or `situation`. Older hosts may still send `outcome`, `finalText` or `comment` here. Record reactions with `record_writing_feedback`.",
534
544
  "inputSchema": {
535
545
  "type": "object",
536
546
  "properties": {
@@ -639,7 +649,7 @@
639
649
  "user_told",
640
650
  "host_observed"
641
651
  ],
642
- "description": "Outcome source: `user_told` when the user said it, or `host_observed` when the host observed it. Omit when unknown."
652
+ "description": "`user_told` when the user said it; `host_observed` when you saw it. Omit when unknown."
643
653
  },
644
654
  "editAuthor": {
645
655
  "type": "string",
@@ -689,6 +699,91 @@
689
699
  "anthropic/alwaysLoad": true
690
700
  }
691
701
  },
702
+ {
703
+ "name": "record_writing_feedback",
704
+ "title": "Record writing feedback",
705
+ "description": "Use this when the user reacts to writing Idiolect AI returned, or you observe what happened to it. It records an outcome, final wording or comment. Feedback can update the user's Writing Profile. Send only what you know; `outcome` is optional. To change the writing, use `refine_writing`.",
706
+ "inputSchema": {
707
+ "type": "object",
708
+ "properties": {
709
+ "writingJobVersionId": {
710
+ "type": "string",
711
+ "format": "uuid",
712
+ "description": "Version ID returned for the writing this observation concerns. Send this or `outputReference`, not both."
713
+ },
714
+ "outputReference": {
715
+ "type": "string",
716
+ "format": "uuid",
717
+ "description": "Output reference returned for this writing. Use when no version ID is available."
718
+ },
719
+ "outcome": {
720
+ "type": "string",
721
+ "enum": [
722
+ "kept",
723
+ "edited",
724
+ "rejected",
725
+ "superseded"
726
+ ],
727
+ "description": "`kept`: used unchanged. `edited`: changed and used. `rejected`: unusable, not a revision request. `superseded`: the request changed. Otherwise omit."
728
+ },
729
+ "finalText": {
730
+ "type": "string",
731
+ "minLength": 1,
732
+ "maxLength": 20000,
733
+ "description": "The complete final wording, verbatim, when the writing was edited. Never send an AI-written retry here."
734
+ },
735
+ "comment": {
736
+ "type": "string",
737
+ "minLength": 1,
738
+ "maxLength": 20000,
739
+ "description": "What the user said about the writing, in their words. Do not invent or paraphrase."
740
+ },
741
+ "decisionSource": {
742
+ "type": "string",
743
+ "enum": [
744
+ "user_told",
745
+ "host_observed"
746
+ ],
747
+ "description": "`user_told` when the user said it; `host_observed` when you saw it. Omit when unknown."
748
+ },
749
+ "editAuthor": {
750
+ "type": "string",
751
+ "enum": [
752
+ "user",
753
+ "host",
754
+ "other",
755
+ "unknown"
756
+ ],
757
+ "description": "Who changed the wording: `user`, `host`, `other`, or `unknown`. Omission means unknown."
758
+ }
759
+ },
760
+ "additionalProperties": false
761
+ },
762
+ "annotations": {
763
+ "readOnlyHint": false,
764
+ "destructiveHint": false,
765
+ "idempotentHint": true,
766
+ "openWorldHint": false,
767
+ "title": "Record writing feedback"
768
+ },
769
+ "execution": {
770
+ "taskSupport": "forbidden"
771
+ },
772
+ "securitySchemes": [
773
+ {
774
+ "type": "oauth2",
775
+ "scopes": []
776
+ }
777
+ ],
778
+ "_meta": {
779
+ "securitySchemes": [
780
+ {
781
+ "type": "oauth2",
782
+ "scopes": []
783
+ }
784
+ ]
785
+ }
786
+ },
692
787
  {
693
788
  "name": "view_writing_profile",
694
789
  "title": "View writing profile",
@@ -756,7 +851,8 @@
756
851
  "rename_profile",
757
852
  "set_current_profile",
758
853
  "set_default_template"
759
- ]
854
+ ],
855
+ "description": "Choose an `action`: `create_profile` builds from `evidence`; `add_samples` saves more writing; `remove_sample` deletes one sample. `add_rule` saves a stated preference; `remove_rule` deletes one rule. `rename_profile` changes its name; `set_current_profile` selects it for writing; `set_default_template` sets or clears a template."
760
856
  },
761
857
  "profile": {
762
858
  "type": "string",
@@ -788,7 +884,7 @@
788
884
  "minLength": 1,
789
885
  "maxLength": 12000
790
886
  },
791
- "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, and AI text."
887
+ "description": "Send text the user wrote, unchanged. Remove signatures, quoted replies, forwarded text, boilerplate, prompts, templates, AI text, and any wording you added around their samples."
792
888
  },
793
889
  "answers": {
794
890
  "type": "array",
@@ -814,7 +910,7 @@
814
910
  ],
815
911
  "additionalProperties": false
816
912
  },
817
- "description": "When the user chooses to answer questions about how they write, send their answers. Do not summarize or expand them."
913
+ "description": "Messages the user wrote for situations you gave them. Send each unchanged, with the situation as `question`."
818
914
  }
819
915
  },
820
916
  "required": [
@@ -845,7 +941,7 @@
845
941
  "type": "string",
846
942
  "minLength": 1,
847
943
  "maxLength": 60,
848
- "description": "For `rename_profile` (required) or `create_profile`."
944
+ "description": "The Writing Profile's display name. Required for `rename_profile`; optional for `create_profile`."
849
945
  },
850
946
  "writingJobVersionId": {
851
947
  "type": "string",
@@ -864,32 +960,38 @@
864
960
  "channel": {
865
961
  "type": "string",
866
962
  "minLength": 1,
867
- "maxLength": 200
963
+ "maxLength": 200,
964
+ "description": "Where the writing appears, such as email, chat, or a social post."
868
965
  },
869
966
  "audience": {
870
967
  "type": "string",
871
968
  "minLength": 1,
872
- "maxLength": 200
969
+ "maxLength": 200,
970
+ "description": "Who will read the writing, such as clients, colleagues, or the public."
873
971
  },
874
972
  "relationship": {
875
973
  "type": "string",
876
974
  "minLength": 1,
877
- "maxLength": 200
975
+ "maxLength": 200,
976
+ "description": "The user's relationship to the reader, such as manager, friend, or customer."
878
977
  },
879
978
  "purpose": {
880
979
  "type": "string",
881
980
  "minLength": 1,
882
- "maxLength": 200
981
+ "maxLength": 200,
982
+ "description": "What the writing should achieve, such as an update, request, or apology."
883
983
  },
884
984
  "register": {
885
985
  "type": "string",
886
986
  "minLength": 1,
887
- "maxLength": 200
987
+ "maxLength": 200,
988
+ "description": "The tone or formality the rule applies to, such as casual or formal."
888
989
  },
889
990
  "format": {
890
991
  "type": "string",
891
992
  "minLength": 1,
892
- "maxLength": 200
993
+ "maxLength": 200,
994
+ "description": "The writing's structure, such as a short reply, bullet list, or long article."
893
995
  }
894
996
  },
895
997
  "additionalProperties": false,