fenix-claude-plugin 0.1.3 β†’ 0.2.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 (52) hide show
  1. package/.claude-plugin/plugin.json +13 -13
  2. package/.mcp.json +11 -11
  3. package/README.md +33 -40
  4. package/artifacts/collections.html +149 -0
  5. package/artifacts/fenix-workspace.html +1285 -0
  6. package/artifacts/oa-editor.html +210 -0
  7. package/artifacts/patent-editor.html +325 -0
  8. package/artifacts/review-workspace.html +1135 -0
  9. package/commands/fenix-install.md +19 -11
  10. package/commands/fenix-setup.md +18 -13
  11. package/package.json +16 -16
  12. package/skills/fenix-application/SKILL.md +35 -12
  13. package/skills/fenix-application/VERSION +1 -1
  14. package/skills/fenix-application/references/claim1-method-drafting.md +1 -1
  15. package/skills/fenix-application/references/claims.md +4 -5
  16. package/skills/fenix-application/references/disclosure.md +116 -10
  17. package/skills/fenix-application/references/editors.md +222 -51
  18. package/skills/fenix-application/references/figure-description.md +1 -1
  19. package/skills/fenix-application/references/figure-strategy.md +166 -0
  20. package/skills/fenix-application/references/figures-guidance.md +1 -1
  21. package/skills/fenix-application/references/figures.md +51 -14
  22. package/skills/fenix-application/references/patent-review-checklist.md +3 -1
  23. package/skills/fenix-application/references/patent-review.md +6 -2
  24. package/skills/fenix-application/references/patent-safe.md +1 -1
  25. package/skills/fenix-application/references/patent.md +9 -9
  26. package/skills/fenix-application/references/spec-guidance.md +1 -1
  27. package/skills/fenix-application/references/spec.md +17 -7
  28. package/skills/fenix-application/scripts/figure_strategy_server.py +136 -0
  29. package/skills/fenix-diagram/SKILL.md +54 -0
  30. package/skills/fenix-diagram/VERSION +1 -0
  31. package/skills/fenix-diagram/references/diagram-svg-guide.md +271 -0
  32. package/skills/fenix-office-action/SKILL.md +6 -4
  33. package/skills/fenix-office-action/VERSION +1 -1
  34. package/skills/fenix-office-action/references/oa-analysis.md +14 -4
  35. package/skills/fenix-office-action/references/oa-drafting.md +98 -21
  36. package/skills/fenix-office-action/references/oa-response.md +13 -13
  37. package/skills/fenix-project/SKILL.md +4 -3
  38. package/skills/fenix-project/VERSION +1 -1
  39. package/skills/fenix-project/references/create-project.md +11 -1
  40. package/artifacts/claims-editor.html +0 -205
  41. package/artifacts/figures-editor.html +0 -237
  42. package/artifacts/oa-arguments-editor.html +0 -216
  43. package/artifacts/practice-dashboard.html +0 -469
  44. package/artifacts/project-overview.html +0 -481
  45. package/artifacts/sections-editor.html +0 -205
  46. package/artifacts/user-dashboard.html +0 -368
  47. package/skills/fenix-application/CUSTOMIZE.md +0 -1
  48. package/skills/fenix-application/assets/claims_editor.html +0 -86
  49. package/skills/fenix-application/assets/figures_editor.html +0 -86
  50. package/skills/fenix-application/assets/spec_editor.html +0 -86
  51. package/skills/fenix-office-action/CUSTOMIZE.md +0 -1
  52. package/skills/fenix-project/CUSTOMIZE.md +0 -1
@@ -1,6 +1,6 @@
1
1
  # Patent Application Review
2
2
 
3
- **Version: 21**
3
+ **Version: 48**
4
4
 
5
5
  Structured pre-filing review. Catches structural defects, malformed claims, patent profanity, and missing spec support.
6
6
 
@@ -13,7 +13,9 @@ Trigger when the user asks to review, audit, critique, or red-line a patent appl
13
13
  1. Uploaded .docx -- extract and identify sections: Title, Background, Detailed Description, Claims.
14
14
  2. Multiple files -- extract each, merge for review.
15
15
  3. Pasted text -- work with what is present.
16
- 4. Fenix project -- call `get_project({ projectId, include: ["claims","sections"] })`.
16
+ 4. Fenix project -- call `read {resource:"project", options:{projectId, include: ["claims","sections"]}}`.
17
+
18
+ **Reading (and returning) a `.docx` without losing content.** Extract the sections directly from the file. If a single read comes back truncated (long specs do), pull it **in parts / section by section** so you review the WHOLE document -- a truncated read silently drops the tail (usually the claims), and you would miss real issues. If the attorney wants a red-lined `.docx` back, edit the uploaded file **in place** with targeted changes; do **not** reconstruct the whole document from its read-back text (that is what produces "the file got truncated"). Reopen and confirm every section is present before delivering.
17
19
 
18
20
  ## Severity
19
21
  - πŸ”΄ Blocker -- must fix before filing
@@ -26,8 +28,10 @@ Trigger when the user asks to review, audit, critique, or red-line a patent appl
26
28
  - Intro (before FIG. 1): must include the problem, how the invention solves it, key term definitions, and an advantages paragraph (see `patent-review-advantages.md`).
27
29
  - Per-figure descriptions: at least two paragraphs per figure.
28
30
  - Reference numerals: every figure component must have a numeral, appear in the spec with that numeral, and be described. Flag orphans in either direction and numeral collisions.
31
+ - Figure component generation: every component of a **non-boilerplate** figure must have `generateElement: true` -- a component with it `false`/absent produces **no Visio box and no description text** (it is treated as background/boilerplate). Flag any non-boilerplate figure whose components lack `generateElement: true`. Boilerplate figures correctly leave it off. (Include `figures` in `read {resource:"project"}` to inspect the components.)
29
32
  - Cross-reference to provisional/foreign priority if applicable.
30
33
  - Equations formatted correctly; not in claims.
34
+ - Fonts: flag any non-standard or web font (e.g. Google Sans, Roboto). The USPTO requires legible, standard, fully-embedded fonts (Times New Roman, Arial, Courier) -- MPEP 608.01 / 37 CFR 1.52(b); non-standard or non-embedded fonts get rejected at Patent Center upload or draw a Notice to File Corrected Application Papers.
31
35
 
32
36
  ## Section 2 -- Claims
33
37
  Count: 3 INDs, 20 total. Acceptable: Method/CRM/System or any set with two or more classes and two or more scopes. Only flag if fewer than 3 INDs, all same scope, or all same statutory class.
@@ -1,6 +1,6 @@
1
1
  # Patent Language Guidelines
2
2
 
3
- **Version: 21**
3
+ **Version: 48**
4
4
 
5
5
  This file is the single source of truth for Fenix patent language and profanity rules.
6
6
  Both the patent drafting workflow (references/claims.md) and the patent review workflow (references/patent-review.md) reference this file for profanity guidance.
@@ -1,21 +1,21 @@
1
1
  # Patent Drafting Workflow
2
2
 
3
- **Version: 21**
3
+ **Version: 48**
4
4
 
5
5
  ## Phase overview
6
- - **Phase 1 -- Claims**: Read `references/claims.md` -> draft one-by-one (confirm each) -> save the whole set **once** at the end with `save_project(type=claims)`. Do not save after each claim.
7
- - **Phase 2 -- Figures**: agree the figure list (`save_project(type=figures)`), then draft each figure's content one-by-one (confirm each) and save the whole set **once** at the end with `save_project(type=figures)`. Do not save per figure. Then run `scripts/calculate_figure_layout.py` (pipe figure JSON) -> check warnings.
8
- - **Spec**: `get_project({ projectId, include: ["claims","figures","sections"] })` -> generate each section (see `references/spec.md`) -> `save_project(type=section)` per section as the user confirms it.
6
+ - **Phase 1 -- Claims**: Read `references/claims.md` -> draft one-by-one (confirm each) -> save the whole set **once** at the end with `write {resource:"project", action:"save", options:{type:"claims"}}`. Do not save after each claim.
7
+ - **Phase 2 -- Figures**: agree the figure list (`write {resource:"project", action:"save", options:{type:"figures"}}`), then draft each figure's content one-by-one (confirm each) and save the whole set **once** at the end with `write {resource:"project", action:"save", options:{type:"figures"}}`. Do not save per figure. Then run `scripts/calculate_figure_layout.py` (pipe figure JSON) -> check warnings.
8
+ - **Spec**: `read {resource:"project", options:{projectId, include: ["claims","figures","sections"]}}` -> generate each section (see `references/spec.md`) -> `write {resource:"project", action:"save", options:{type:"section"}}` per section as the user confirms it.
9
9
 
10
- **Do not print (generate a document/file) automatically.** Printing is a separate, explicit step -- only call `print_patent` when the user asks for the drawings, the spec document, or an export. **After any `print_patent` call, always show the returned download URL/link in your reply** -- never run a print and leave the result unshown.
10
+ **Do not print (generate a document/file) automatically.** Printing is a separate, explicit step -- only call `read {resource:"patent-document"}` when the user asks for the drawings, the spec document, or an export. **After any `read {resource:"patent-document"}` call, always show the returned download URL/link in your reply** -- never run a print and leave the result unshown.
11
11
 
12
12
  ## Intake
13
- 1. Matter -- `get_project({ identifier })` (exact) or `get_project({ query })` (keyword search)
14
- 2. Template/source -- optionally call `list_patent_templates` first to show the user the available starting templates (name, figure/claim counts) so they can pick one; then import the chosen template (or copy from another project) via `get_project({ projectId, templateId, include: ["figures","sections","template"] })` or `get_project({ projectId, sourceProjectId, include: ["figures","sections","template"] })`
13
+ 1. Matter -- `read {resource:"project", options:{identifier}}` (exact) or `read {resource:"project", options:{query}}` (keyword search)
14
+ 2. Template/source -- optionally call `read {resource:"patent-templates"}` first to show the user the available starting templates (name, figure/claim counts) so they can pick one; then import the chosen template (or copy from another project) via `read {resource:"project", options:{projectId, templateId, include: ["figures","sections","template"]}}` or `read {resource:"project", options:{projectId, sourceProjectId, include: ["figures","sections","template"]}}`
15
15
  3. Disclosure -- user describes or run `references/disclosure.md` interview
16
16
  4. Inventors -- if the user provides an inventor information sheet, declaration, or ADS (or just names), call `add_inventors({ projectId, inventors: [...] })`. Interpret the document into the Fenix person schema -- `{ name, firstName, middleName, lastName, prefix, suffix, address1, city, stateName, country, postalCode, residenceCity, residenceState, residenceCountry, email, registrationNumber }` (only `name` is required) -- or pass just names. Any number of inventors; they are upserted by name (no duplicates) and added to the matter. Never pass `clientDb`.
17
17
  5. Phase -- ask which to start
18
18
 
19
- **Use the imported data as-is -- do NOT drop or stub any of it.** When a template/source is imported, the response carries real figure data (brief descriptions, components, stencils/placeholders, steps, numbering) and sections. Carry every field through to `save_project` exactly as imported; only fill in genuinely missing pieces. Never replace an imported brief description, component list, stencil/placeholder, or section with a placeholder, an old stub, or invented content. If a field looks empty, confirm with the user rather than substituting a stub.
19
+ **Use the imported data as-is -- do NOT drop or stub any of it.** When a template/source is imported, the response carries real figure data (brief descriptions, components, stencils/placeholders, steps, numbering) and sections. Carry every field through to `write {resource:"project", action:"save"}` exactly as imported; only fill in genuinely missing pieces. Never replace an imported brief description, component list, stencil/placeholder, or section with a placeholder, an old stub, or invented content. If a field looks empty, confirm with the user rather than substituting a stub.
20
20
 
21
- Call `save_project(name, disclosure, templateId|sourceProjectId)` after intake.
21
+ Call `write {resource:"project", action:"save", options:{name, disclosure, templateId}}` (or `sourceProjectId` in place of `templateId`) after intake.
@@ -1,6 +1,6 @@
1
1
  # Spec Section Guidance
2
2
 
3
- **Version: 21**
3
+ **Version: 48**
4
4
 
5
5
  ## Background
6
6
 
@@ -1,18 +1,29 @@
1
1
  # Spec Drafting Workflow
2
2
 
3
- **Version: 21**
3
+ **Version: 48**
4
4
 
5
5
  ## Start
6
- `get_project({ projectId, include: ["claims","figures","sections"] })` -- loads claims, figure list, and any previously saved sections.
6
+ `read {resource:"project", options:{projectId, include: ["claims","figures","sections"]}}` -- loads claims, figure list, and any previously saved sections.
7
7
 
8
8
  ## Section order
9
9
  Field Of The Invention -> Background -> Summary -> Brief Description -> Introduction -> Figure 1 -> Figure 2 -> ... -> Figure N -> Examples -> Clauses -> Additional Description -> Glossary -> Abstract
10
10
 
11
+ ## Section names β€” exact save keys (read before saving ANY section)
12
+ `write {resource:"project", action:"save", options:{type: "section", sectionName, paragraphs}}` stores content under **whatever `sectionName` you pass β€” it does not validate or normalize the name**, and the document renderer looks each section up by its **exact key (case- and wording-sensitive)**. A mis-cased, re-worded, or invented section name is silently stored under that stray key and **never appears in the generated document** β€” so it looks like nothing saved. Use exactly these keys:
13
+
14
+ `Field Of The Invention`, `Background`, `Summary`, `Brief Description`, `Introduction`, `Examples`, `Clauses`, `Additional Description`, `Glossary`, `Abstract` β€” plus one `Figure N` key per figure (`Figure 1`, `Figure 2`, … `Figure 10`).
15
+
16
+ **Never save to a "Detailed Description" section β€” it is not a stored section.** The detailed description is **virtual**: it is assembled at print time from the per-figure `Figure N` sections. Content saved under `Detailed Description` (or `Detailed Description of the Invention`, etc.) is **ignored** whenever the matter has figures. In particular, an **introduction** is its own `Introduction` section β€” do **not** put it (or anything else) under `Detailed Description`.
17
+
18
+ After each save, the response returns `sectionNames` (all section keys now on the matter). Glance at it: every key should be one of the canonical names above; a key that is not means that content will not render.
19
+
20
+ **Put the whole section in ONE `paragraphs` element.** The spec-section editor reads only `paragraphs[0]`, so content split across multiple array elements is dropped there (everything after the first element disappears). Save each section's body as a **single** element β€” one HTML string holding all the `<p>…</p>` blocks: `paragraphs: ["<p>First paragraph.</p><p>Second paragraph.</p>"]`, **not** `["<p>First paragraph.</p>", "<p>Second paragraph.</p>"]`. (The print renderer splits the `<p>` tags back apart, so the Word output is unchanged.)
21
+
11
22
  ## Per-section loop
12
23
  For each section:
13
24
  (a) Generate the section text (see generation rules below). If already saved in `sections`, show that text first.
14
25
  (b) Show to user -- **END TURN**. Ask "Does [Section Name] look right, or any changes?"
15
- (c) After user confirms: `save_project({ type: "section", sectionName, paragraphs })` immediately. Never accumulate.
26
+ (c) After user confirms: `write {resource:"project", action:"save", options:{type: "section", sectionName, paragraphs}}` immediately. Never accumulate.
16
27
 
17
28
  ## How to generate each section
18
29
 
@@ -41,9 +52,8 @@ Read `references/figure-description.md` for the full protocol. Key rules:
41
52
  Read `references/spec-guidance.md` for the drafting prompt for each section.
42
53
 
43
54
  ## Editor (accordion)
44
- **Always ask the user whether they want to open the spec editor to review/edit all sections at once** -- e.g. "Want me to open the spec editor so you can review every section together?" Only open it if they say yes. **In Cowork, prefer the live spec sections editor:** `get_live_artifacts({ name: "sections-editor" })`, substitute `__PROJECT_ID__` (project id) and `__SERVER_PREFIX__` (your MCP tool prefix, e.g. `mcp__<id>__` β€” see `references/editors.md`) in the returned HTML, and open it β€” it loads the current sections and **saves them itself**; when the user pastes a `[SECTIONS SAVED - sectionsRev N]` block, apply that delta and do **not** call `save_project` again (see `references/editors.md`). **Otherwise (non-Cowork), open `assets/spec_editor.html`** with `INITIAL_CONTENT` set to the full sections object (each key a section name, including each "Figure N" as its own section). Each section is a collapsible accordion item with a text box (blank line = new paragraph). The user opens any section to edit, can add/remove sections, then clicks Copy for Save. On `[EDITOR SUBMIT - sections]`, strip the prefix and call `save_project({ type: "sections", sections: {...} })` with the returned object.
45
-
55
+ **Always ask the user whether they want to open the spec editor to review/edit all sections at once** -- e.g. "Want me to open the spec editor so you can review every section together?" Only open it if they say yes. To open it: call `write {resource:"context", options:{ids: { projectId }, label: "<matter number>"}}` to bind the matter, then tell the user to open the **installed Fenix Patent Editor** (Specification view) from their artifacts sidebar. **Never write, edit, or substitute anything into the artifact**; see `references/editors.md`. When the user pastes a `[SECTIONS SAVED - sectionsRev N]` block, apply that delta and do **not** call `write {resource:"project", action:"save"}` again.
46
56
  ## Notes
47
57
  - Claims are already saved -- do not include them as a section here.
48
- - For the one-at-a-time flow, use `save_project(type=section)` directly after the user confirms each section. For a full review pass, use the accordion editor above and save all at once with `save_project(type=sections)`.
49
- - **Do NOT print automatically.** After all sections are saved, tell the user the specification is complete and ask whether they want the Word document generated. Only call `print_patent(type=spec)` when the user explicitly asks for it. **When you do, show the returned download URL/link in your reply** (e.g. "Specification ready: <url>") -- never run the print and leave the result unshown.
58
+ - For the one-at-a-time flow, use `write {resource:"project", action:"save", options:{type:"section"}}` directly after the user confirms each section. For a full review pass, use the accordion editor above and save all at once with `write {resource:"project", action:"save", options:{type:"sections"}}`.
59
+ - **Do NOT print automatically.** After all sections are saved, tell the user the specification is complete and ask whether they want the Word document generated. Only call `read {resource:"patent-document", options:{type:"spec"}}` when the user explicitly asks for it. **When you do, show the returned download URL/link in your reply** (e.g. "Specification ready: <url>") -- never run the print and leave the result unshown.
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Serve the figure-strategy worksheet and persist the user's edits to disk.
4
+
5
+ Why this exists: a page loaded from `file://` cannot write back to itself, so an HTML file the
6
+ assistant drops in the sandbox is write-only -- the user types into it and the assistant, re-reading
7
+ the file, still sees its own original markup. This server closes the loop:
8
+
9
+ browser (edits) --POST /save--> figure-strategy.json --read--> assistant
10
+
11
+ Run it, hand the user the printed URL (NOT the .html path), and then read `figure-strategy.json`
12
+ whenever you want their current plan. That JSON is the source of truth; the HTML is just the view.
13
+
14
+ python3 figure_strategy_server.py --dir /path/to/sandbox [--port 8765]
15
+
16
+ Serves:
17
+ GET / figure-strategy.html
18
+ GET /figure-strategy.json current state (so the page can rehydrate on reload)
19
+ POST /save replace the state; body is the whole JSON document
20
+ """
21
+
22
+ import argparse
23
+ import json
24
+ import os
25
+ import shutil
26
+ import tempfile
27
+ import threading
28
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
29
+
30
+ HTML_NAME = "figure-strategy.html"
31
+ STATE_NAME = "figure-strategy.json"
32
+
33
+ # The page autosaves on every keystroke (debounced), so writes are frequent and can overlap.
34
+ _write_lock = threading.Lock()
35
+
36
+
37
+ def _write_state_atomically(path: str, raw: bytes) -> None:
38
+ """Write via a temp file + replace, so a half-written save can never truncate the plan."""
39
+ directory = os.path.dirname(path) or "."
40
+ fd, tmp = tempfile.mkstemp(dir=directory, prefix=".figure-strategy-", suffix=".tmp")
41
+ try:
42
+ with os.fdopen(fd, "wb") as f:
43
+ f.write(raw)
44
+ f.flush()
45
+ os.fsync(f.fileno())
46
+ os.replace(tmp, path)
47
+ except BaseException:
48
+ if os.path.exists(tmp):
49
+ os.unlink(tmp)
50
+ raise
51
+
52
+
53
+ class Handler(BaseHTTPRequestHandler):
54
+ directory = "."
55
+
56
+ # Keep the console readable: one line per save, no per-asset request spam.
57
+ def log_message(self, fmt, *args): # noqa: A003
58
+ if "POST" in (fmt % args):
59
+ print("saved figure-strategy.json")
60
+
61
+ def _send(self, code, body=b"", content_type="text/plain; charset=utf-8"):
62
+ self.send_response(code)
63
+ self.send_header("Content-Type", content_type)
64
+ self.send_header("Content-Length", str(len(body)))
65
+ # The page reloads its own state; never let a stale cache mask a save.
66
+ self.send_header("Cache-Control", "no-store")
67
+ self.end_headers()
68
+ if body:
69
+ self.wfile.write(body)
70
+
71
+ def _path(self, name):
72
+ return os.path.join(self.directory, name)
73
+
74
+ def do_GET(self):
75
+ route = self.path.split("?", 1)[0]
76
+
77
+ if route in ("/", "/index.html", "/" + HTML_NAME):
78
+ path = self._path(HTML_NAME)
79
+ if not os.path.exists(path):
80
+ return self._send(404, f"{HTML_NAME} not found in {self.directory}".encode())
81
+ with open(path, "rb") as f:
82
+ return self._send(200, f.read(), "text/html; charset=utf-8")
83
+
84
+ if route == "/" + STATE_NAME:
85
+ path = self._path(STATE_NAME)
86
+ if not os.path.exists(path):
87
+ return self._send(200, b"{}", "application/json; charset=utf-8")
88
+ with open(path, "rb") as f:
89
+ return self._send(200, f.read(), "application/json; charset=utf-8")
90
+
91
+ return self._send(404, b"not found")
92
+
93
+ def do_POST(self):
94
+ if self.path.split("?", 1)[0] != "/save":
95
+ return self._send(404, b"not found")
96
+
97
+ length = int(self.headers.get("Content-Length") or 0)
98
+ raw = self.rfile.read(length) if length else b""
99
+
100
+ # Validate before touching disk: a malformed body must not clobber a good plan.
101
+ try:
102
+ parsed = json.loads(raw.decode("utf-8"))
103
+ except (ValueError, UnicodeDecodeError) as e:
104
+ return self._send(400, f"invalid JSON: {e}".encode())
105
+
106
+ pretty = json.dumps(parsed, indent=2, ensure_ascii=False).encode("utf-8")
107
+ with _write_lock:
108
+ _write_state_atomically(self._path(STATE_NAME), pretty)
109
+
110
+ return self._send(200, b'{"ok":true}', "application/json; charset=utf-8")
111
+
112
+
113
+ def main():
114
+ ap = argparse.ArgumentParser(description=__doc__)
115
+ ap.add_argument("--dir", default=".", help="directory holding figure-strategy.html")
116
+ ap.add_argument("--port", type=int, default=8765)
117
+ args = ap.parse_args()
118
+
119
+ Handler.directory = os.path.abspath(args.dir)
120
+
121
+ if not os.path.exists(os.path.join(Handler.directory, HTML_NAME)):
122
+ raise SystemExit(f"{HTML_NAME} not found in {Handler.directory} β€” write it first.")
123
+
124
+ # Bind to loopback only: this serves a client's unpublished invention.
125
+ server = ThreadingHTTPServer(("127.0.0.1", args.port), Handler)
126
+ print(f"figure strategy: http://127.0.0.1:{args.port}/")
127
+ print(f"edits persist to: {os.path.join(Handler.directory, STATE_NAME)}")
128
+ print("give the user the URL above β€” NOT the .html path (file:// cannot save).")
129
+ try:
130
+ server.serve_forever()
131
+ except KeyboardInterrupt:
132
+ server.shutdown()
133
+
134
+
135
+ if __name__ == "__main__":
136
+ main()
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: fenix-diagram
3
+ description: >-
4
+ Render a patent figure as SVG: turn a claim (or a described process) into a top-to-bottom data-flow flowchart in the Fenix drawing style -- square-cornered steps, rounded input/output boxes, filled arrows, S-curve lead lines, and reference numerals.
5
+ ---
6
+
7
+ # Fenix Diagram
8
+
9
+ **Skill version: 2** (authoritative version is in the top-level `VERSION` file; this line is for reference only).
10
+
11
+ ## Triggers
12
+
13
+ - make a diagram
14
+ - make a figure
15
+ - draw a flowchart
16
+ - render the claim as a figure
17
+ - patent figure svg
18
+ - data-flow diagram
19
+ - draw claim 1
20
+ - generate a figure
21
+ - flowchart for this method
22
+ - create a patent drawing
23
+
24
+ ## Customization
25
+
26
+ User overrides for this skill live in a `CUSTOMIZE.md` file in this skill directory. This file is **not shipped with the skill** -- it belongs to the user. **If `CUSTOMIZE.md` does not already exist in this skill directory, create it now** containing exactly the single line `place custom instructions here`. **If it already exists, never overwrite it** -- it holds the user's own instructions.
27
+
28
+ Before applying any workflow in this skill, read `CUSTOMIZE.md`. If it contains anything other than the placeholder text "place custom instructions here", treat its contents as user overrides that take precedence over the default instructions in this SKILL.md and its reference files.
29
+
30
+ Apply the custom overrides **only as long as the result still satisfies every structured-output contract** this skill depends on, including:
31
+ - the JSON shapes passed to `save_project` (claims, figures, sections)
32
+ - the figure ElementSchema (`type`, `label`, `number`, `text`) and component numbering rules
33
+ - the spec section names and ordering required by the save/print tools
34
+
35
+ Custom instructions may freely change tone, phrasing, default counts, section preferences, review emphasis, and similar. If a custom instruction would break a required format, follow the default format and tell the user which customization could not be applied and why.
36
+
37
+ ## Contents
38
+ - `references/diagram-svg-guide.md` -- full SVG generation guide: conventions, building the element list from a claim, canvas/layout, reusable snippets (arrowhead + drop-shadow defs, boxes, arrows, labels, numerals), the S-curve lead line, and a finalizing checklist
39
+
40
+ ## When to use this skill
41
+
42
+ Trigger whenever the user wants a patent-style figure rendered as an SVG from a claim or a described process:
43
+ - "make a diagram / figure for claim 1", "render this claim as a figure", "draw the flowchart"
44
+ - "generate a patent figure SVG", "data-flow diagram", "FIG. N for this method"
45
+
46
+ ## How to use
47
+
48
+ Read `references/diagram-svg-guide.md` and follow it end to end:
49
+ 1. **Build the element list from the claim** -- each verb clause is a **step** (square box); each noun that flows between steps is an **input/output** (rounded box); side inputs branch in; two inputs to the first step (or two outputs of the last) share a row. Assign numerals top-to-bottom by 5, starting at FIG## * 100 + 5.
50
+ 2. **Lay out** on the 680-wide canvas: main column centered at x=300 (box width 240), side inputs at x=448, paired peers on one row.
51
+ 3. **Assemble the SVG** from the reusable snippets: the filled curvy arrowhead + drop-shadow `<defs>`, the single shadowed box group, flow arrows, centered labels, S-curve lead lines, and edge-anchored numerals.
52
+ 4. **Run the finalizing checklist** (section 6) before returning the SVG.
53
+
54
+ Return the SVG only -- do **not** include a "FIG. ##" caption (the figure template's background page supplies it).
@@ -0,0 +1 @@
1
+ 2
@@ -0,0 +1,271 @@
1
+ # Patent-Style Data-Flow Flowchart β€” SVG Generation Guide
2
+
3
+ **Version: 2**
4
+
5
+ Instructions for generating a patent figure like FIG. 10 (a claim rendered as a
6
+ top-to-bottom data-flow diagram): square-cornered **steps**, rounded-corner
7
+ **inputs/outputs**, arrows connecting them, and an S-curve **lead line** with a
8
+ reference numeral on every element.
9
+
10
+ ---
11
+
12
+ ## 1. Conventions
13
+
14
+ | Element | Shape | Meaning |
15
+ |---|---|---|
16
+ | **Step** (method operation) | Rectangle, **square corners** (`rx="0"`) | An action from the claim: "obtaining", "extracting", "repositioning", "generating". |
17
+ | **Input / Output** (data) | Rectangle, **rounded corners** (`rx="16"`) | A datum produced or consumed by a step: an image, entity information, a pose constraint, a model, the result. |
18
+ | **Flow** | Straight line with a **filled** arrowhead | Direction of data flow, generally top-to-bottom. |
19
+ | **Lead line** | Short **S-curve**, no arrowhead | Connects each box to its reference numeral. |
20
+ | **Reference numeral** | Plain text, `FIG## + nn` | Increments by **5** in reading order (top-to-bottom). |
21
+ | **Component enclosure** (optional) | Rectangle, **square corners**, **dotted** stroke, **no shadow** | The physical component that performs a step (e.g. "Encoder"). Wraps the step box; flow arrows touch the **outer dotted** box, not the inner step box. |
22
+
23
+ Black line art on white. Boxes carry a subtle **black drop shadow** to the
24
+ bottom-right for depth; arrowheads are **filled** solid triangles with gently
25
+ curved edges. Otherwise no color, no fills other than white, no shading.
26
+
27
+ ---
28
+
29
+ ## 2. Building the element list from a claim
30
+
31
+ 1. Read the independent claim. Each **verb clause** ("obtaining X", "extracting
32
+ Y") becomes a **step** (square box).
33
+ 2. Each **noun that flows between steps** β€” the thing obtained, extracted,
34
+ produced, or consumed β€” becomes an **input/output** (rounded box). Place the
35
+ output of one step as the input of the next.
36
+ 3. **Side inputs** (a constraint, a model, a reference the step uses but that is
37
+ not produced by the prior step) branch in from the side into the step that
38
+ uses them (e.g., "pose constraint" β†’ reposition; "image generation model" β†’
39
+ generate).
40
+ - **Parallel inputs/outputs β€” same row.** When the **first** step consumes two
41
+ (or more) inputs, or the **last** step produces two (or more) outputs, place
42
+ them **side by side on one row** and fan the arrows straight down into (or
43
+ out of) the step β€” do **not** put one above the step and the other coming in
44
+ from the side. A side input is reserved for something merging into a *middle*
45
+ step; peers of the first/last step share a row so the symmetry reads clearly.
46
+ 4. Assign numerals in **reading order, top to bottom**, incrementing by 5,
47
+ starting at `FIG## * 100 + 5`. For FIG. 10 that is 1005, 1010, 1015 … For
48
+ FIG. 3 it would be 305, 310, 315 …
49
+
50
+ **Worked example (claim 1 β†’ FIG. 10):**
51
+
52
+ | # | Box | Type |
53
+ |---|---|---|
54
+ | 1005 | Obtain image | step |
55
+ | 1010 | Image | output |
56
+ | 1015 | Extract entity information | step |
57
+ | 1020 | Entity information (identity, location) | output |
58
+ | 1025 | Pose constraint | side input |
59
+ | 1030 | Reposition entities | step |
60
+ | 1035 | Modified entity information (second arrangement) | output |
61
+ | 1040 | Image generation model | side input |
62
+ | 1045 | Generate modified image | step |
63
+ | 1050 | Modified image | output |
64
+
65
+ **Second worked example β€” two inputs β†’ intermediate β†’ final (claim 1 β†’ FIG. 10):**
66
+
67
+ > A method comprising: receiving a first audio signal and a second audio signal;
68
+ > combining them to produce a mixed signal; applying a noise-reduction filter to
69
+ > the mixed signal to produce a filtered signal; and encoding the filtered signal
70
+ > to produce an output audio file.
71
+
72
+ Both inputs sit on the **same top row** (1005 left, 1010 right) and fan down into
73
+ the combine step:
74
+
75
+ | # | Box | Type |
76
+ |---|---|---|
77
+ | 1005 | First audio signal | input (row, left) |
78
+ | 1010 | Second audio signal | input (row, right) |
79
+ | 1015 | Combine signals | step |
80
+ | 1020 | Mixed signal | output |
81
+ | 1025 | Apply noise-reduction filter | step |
82
+ | 1030 | Filtered signal | output |
83
+ | 1035 | Encode signal | step |
84
+ | 1040 | Output audio file | output |
85
+
86
+ ---
87
+
88
+ ## 3. Canvas and layout
89
+
90
+ - `viewBox="0 0 680 H"` β€” keep width **680**; set **H** to the last element's
91
+ bottom + ~30px. Do **not** add a "FIG. ##" caption β€” the figure number is
92
+ supplied by the template's background page, so leave it out of the SVG.
93
+ - Draw a white background rect first: `<rect x="0" y="0" width="680" height="H" fill="#ffffff"/>`.
94
+ - **Main column** centered at `x=300`, box width **240** (`x=180`β†’`420`).
95
+ - **Side inputs** at `x=448`, width **150** (`x=448`β†’`598`).
96
+ - Vertical rhythm: box height **46**, gap **~46** between a box bottom and the
97
+ next box top (leave a longer gap where a side input merges).
98
+ - **Paired-row inputs/outputs.** For two peers sharing a row, use two narrower
99
+ boxes width **190**, centered as a pair on `x=300`: left `x=90`β†’`280`
100
+ (center 185), right `x=320`β†’`510` (center 415). Fan two arrows from the pair's
101
+ bottom centers into the step's top edge, e.g. `185,88 β†’ 235,138` and
102
+ `415,88 β†’ 365,138` (mirror the endpoints for a paired-output last step). Number
103
+ left-to-right (left = lower numeral). Put the left peer's numeral + lead line on
104
+ its **left** edge (`x=90`) and the right peer's numeral + a **mirrored** lead
105
+ line on its **right** edge (`x=510`).
106
+ - Draw order (so strokes layer cleanly): connectors β†’ **shadowed box group**
107
+ (step boxes β†’ I/O boxes) β†’ labels β†’ lead lines β†’ numerals. (No caption β€” the
108
+ template's background page carries the "FIG. ##" label.)
109
+ - Wrap all step + I/O boxes in a single `<g filter="url(#sh)">` so the drop
110
+ shadow applies once to the whole group (connectors, labels, lead lines, and
111
+ numerals stay outside the group so they cast no shadow).
112
+
113
+ ---
114
+
115
+ ## 4. Reusable snippets
116
+
117
+ ### Defs β€” filled curvy arrowhead + drop shadow
118
+ ```xml
119
+ <defs>
120
+ <marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
121
+ <path d="M1,1 Q6,3 9,5 Q6,7 1,9 Q3.2,5 1,1 Z" fill="#111111" stroke="#111111" stroke-width="0.8" stroke-linejoin="round"/>
122
+ </marker>
123
+ <!-- Expanded drop shadow (feDropShadow needs Inkscape 1.0+; this chain works everywhere) -->
124
+ <filter id="sh" x="-20%" y="-20%" width="140%" height="140%">
125
+ <feGaussianBlur in="SourceAlpha" stdDeviation="0.6"/>
126
+ <feOffset dx="1.5" dy="1.5" result="off"/>
127
+ <feFlood flood-color="#000000" flood-opacity="0.85"/>
128
+ <feComposite in2="off" operator="in"/>
129
+ <feMerge>
130
+ <feMergeNode/>
131
+ <feMergeNode in="SourceGraphic"/>
132
+ </feMerge>
133
+ </filter>
134
+ </defs>
135
+ ```
136
+ The arrowhead is a solid triangle whose two long sides bow outward (`Q6,3` /
137
+ `Q6,7`) and whose back edge is slightly concave (`Q3.2,5`), giving a soft swept
138
+ look. The shadow is a tight, near-opaque black offset β€” crisp thin edge, not a
139
+ gray halo. Tune `dx`/`dy` (offset), `stdDeviation` (blur), and `flood-opacity`.
140
+
141
+ ### Shadowed box group
142
+ ```xml
143
+ <g filter="url(#sh)">
144
+ <!-- step boxes (square corners) -->
145
+ <rect x="180" y="Y" width="240" height="46" fill="#ffffff" stroke="#111111" stroke-width="2"/>
146
+ <!-- input/output boxes (rounded corners) -->
147
+ <rect x="180" y="Y" width="240" height="46" rx="16" fill="#ffffff" stroke="#111111" stroke-width="2"/>
148
+ </g>
149
+ ```
150
+
151
+ ### Step box (square corners)
152
+ ```xml
153
+ <rect x="180" y="Y" width="240" height="46" fill="#ffffff" stroke="#111111" stroke-width="2"/>
154
+ ```
155
+
156
+ ### Input/output box (rounded corners)
157
+ ```xml
158
+ <rect x="180" y="Y" width="240" height="46" rx="16" fill="#ffffff" stroke="#111111" stroke-width="2"/>
159
+ ```
160
+
161
+ ### Flow arrow
162
+ ```xml
163
+ <line x1="300" y1="Ybottom" x2="300" y2="Ytop_next" stroke="#111111" stroke-width="2" marker-end="url(#ar)"/>
164
+ ```
165
+
166
+ ### Label (centered; use two `<text>` lines for long labels β€” SVG does not wrap)
167
+ ```xml
168
+ <text x="300" y="Yc" font-family="Arial, sans-serif" font-size="13" text-anchor="middle">Reposition entities</text>
169
+ ```
170
+
171
+ ### Reference numeral
172
+ Anchor the numeral on the edge nearest its lead line and offset it by a small
173
+ gap, so numeral **width never crowds the lead line** regardless of digit count
174
+ (a 3-digit `905` and a 4-digit `1115` then keep the same clearance):
175
+ - **Left-side numeral** (lead line starts at `xβ‰ˆ155`): right-anchor it just
176
+ before that β€” `text-anchor="end"` at `x=152` (~3px gap).
177
+ - **Right-side numeral** (mirrored lead line, free end at `xβ‰ˆ535`): left-anchor
178
+ it just after β€” `text-anchor="start"` at `x=538`.
179
+ - **Left input of a paired row** (lead line starts at `xβ‰ˆ65`): `text-anchor="end"`
180
+ at `x=62`.
181
+
182
+ ```xml
183
+ <!-- left-side numeral -->
184
+ <text x="152" y="Yc" font-family="Arial, sans-serif" font-size="15" text-anchor="end">1030</text>
185
+ ```
186
+
187
+ If you prefer to keep numerals center-anchored, instead nudge the center **away
188
+ from the lead line by ~4px for each digit beyond three** (e.g. 3-digit centered
189
+ at `x=138`; 4-digit at `x=134`). Anchoring is preferred β€” it needs no per-width math.
190
+
191
+ ### Component enclosure (optional β€” show what performs a step)
192
+ When a step is performed by a named component, wrap the step box in a **dotted,
193
+ square-cornered** rectangle with **no shadow**, and label the component (italic)
194
+ at the top inside the enclosure. Pad ~14px on the sides and bottom of the step
195
+ box and ~30px on top (to seat the label). **Retarget the flow arrows to the outer
196
+ dotted box**, not the inner step box: the incoming arrow ends at the enclosure's
197
+ top edge and the outgoing arrow starts at its bottom edge.
198
+
199
+ **Spacing is measured to the enclosure, not the inner step box.** Treat the whole
200
+ dotted box as the row element: leave the normal ~46px gap between the previous
201
+ box's bottom and the enclosure's top, and between the enclosure's bottom and the
202
+ next box's top. Because the enclosure is taller than a bare step (the ~30px top
203
+ pad + ~14px bottom pad), everything below it shifts down and the `viewBox` height
204
+ grows accordingly. The step's numeral/lead line still points at the **inner**
205
+ step box (at its center), even though the lead line crosses the dotted border.
206
+
207
+ ```xml
208
+ <!-- draw OUTSIDE the shadowed box group (no shadow), before/behind the step box -->
209
+ <rect x="166" y="508" width="268" height="90" fill="none" stroke="#111111" stroke-width="1.5" stroke-dasharray="4 3"/>
210
+ <text x="300" y="527" font-family="Arial, sans-serif" font-size="12" font-style="italic" text-anchor="middle">Encoder</text>
211
+ ```
212
+ Worked example (from FIG. 11): the previous box (output) bottom is `462`; the
213
+ enclosure sits `46px` below at `x=166,y=508,w=268,h=90` (so `508`β†’`598`); the
214
+ inner step box is `x=180,y=538,w=240,h=46`. The incoming arrow runs `462`β†’`508`
215
+ (enclosure top); the outgoing arrow runs `598`β†’`644` (enclosure bottom to the
216
+ next box `46px` further down).
217
+
218
+ ---
219
+
220
+ ## 5. The S-curve lead line (the important part)
221
+
222
+ Profile taken from the Visio **"Lead Line - Right"** stencil: two cubic BΓ©ziers
223
+ that start and end at the same baseline with a shallow S wiggle, spanning ~25px.
224
+
225
+ **Horizontal lead line** β€” numeral on the left at height `y`, curving into the
226
+ box's left edge (`xβ‰ˆ180`). Substitute `y`:
227
+ ```xml
228
+ <path d="M155,{y} C162.64,{y-2.55} 164.04,{y-1.76} 165.51,{y-0.9} C170.14,{y+1.8} 175.36,{y+5.09} 180.46,{y}"
229
+ fill="none" stroke="#111111" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
230
+ ```
231
+
232
+ **Vertical lead line** β€” numeral above a side box at column `x`, curving down
233
+ onto the box top (`y0` = numeral-side start). Same profile rotated 90Β°:
234
+ ```xml
235
+ <path d="M{x},{y0} C{x-2.55},{y0+7.64} {x-1.76},{y0+9.04} {x-0.9},{y0+10.51} C{x+1.8},{y0+15.14} {x+5.09},{y0+20.36} {x},{y0+25.46}"
236
+ fill="none" stroke="#111111" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
237
+ ```
238
+
239
+ **Mirrored (right-edge) lead line** β€” for the right peer of a paired row, the
240
+ numeral sits to the right and the curve enters the box's **right** edge (`xr`).
241
+ Reflect the horizontal profile; e.g. for `xr=510`:
242
+ ```xml
243
+ <path d="M535.46,{y} C527.82,{y-2.55} 526.42,{y-1.76} 524.95,{y-0.9} C520.32,{y+1.8} 515.1,{y+5.09} 509.54,{y}"
244
+ fill="none" stroke="#111111" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
245
+ ```
246
+
247
+ Keep lead lines short (~24–26px run), no arrowhead, `stroke-width` ~1.4 with
248
+ round caps. Place the numeral just beyond the free end of the curve. Lead lines
249
+ and numerals stay **outside** the shadowed box group.
250
+
251
+ ---
252
+
253
+ ## 6. Checklist before finalizing
254
+
255
+ - [ ] Every step is a **square** box; every input/output is a **rounded** box.
256
+ - [ ] Each step's output feeds the next step's input; side inputs branch in.
257
+ - [ ] Two inputs to the first step (or two outputs of the last step) sit **on the
258
+ same row**, fanned in/out β€” not one from the top and one from the side.
259
+ - [ ] Every box has exactly one lead line and one numeral.
260
+ - [ ] Numerals are edge-anchored (or width-nudged) so no numeral touches its lead
261
+ line β€” check the widest (4-digit) numerals.
262
+ - [ ] Arrowheads are **filled** (solid, curvy) β€” not open line strokes.
263
+ - [ ] All boxes sit in one `<g filter="url(#sh)">`; connectors, labels, lead
264
+ lines, and numerals are outside it (no stray shadows).
265
+ - [ ] Numerals increase by **5** in top-to-bottom reading order, prefixed by the
266
+ figure number (`FIG## * 100 + 5, +10, …`).
267
+ - [ ] No numeral collisions; no numeral appears in the drawing without a matching
268
+ description in the specification (and vice-versa).
269
+ - [ ] All black on white; nothing relies on color.
270
+ - [ ] `viewBox` height leaves ~30px below the last element; **no** "FIG. ##"
271
+ caption in the SVG (the template background supplies it).