fenix-claude-plugin 0.1.2 → 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 (48) 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 +38 -11
  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 +228 -39
  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 +60 -9
  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 +11 -10
  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 +9 -7
  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 +144 -50
  36. package/skills/fenix-office-action/references/oa-response.md +31 -18
  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/practice-dashboard.html +0 -469
  41. package/artifacts/project-overview.html +0 -481
  42. package/artifacts/user-dashboard.html +0 -368
  43. package/skills/fenix-application/CUSTOMIZE.md +0 -1
  44. package/skills/fenix-application/assets/claims_editor.html +0 -86
  45. package/skills/fenix-application/assets/figures_editor.html +0 -86
  46. package/skills/fenix-application/assets/spec_editor.html +0 -86
  47. package/skills/fenix-office-action/CUSTOMIZE.md +0 -1
  48. package/skills/fenix-project/CUSTOMIZE.md +0 -1
@@ -1,6 +1,6 @@
1
1
  # Office Action Rejection Analysis
2
2
 
3
- **Version: 4**
3
+ **Version: 25**
4
4
 
5
5
  This file is how you turn the imported `oa_data` into a response strategy. The method is **classify → select → fill**:
6
6
 
@@ -15,7 +15,7 @@ Then present the per-rejection strategy to the attorney and **stop for approval
15
15
  Each entry in `oa_data.oa_rejections` has:
16
16
  - `status_type` / `status_type_extended` — the rejection basis (e.g. contains "101", "102", "103", "112").
17
17
  - `status_claims` — the claim numbers under this rejection.
18
- - `reject_refs` / `status_refs` — the references applied (resolve to citations; their disclosure text is on the citation's `plainText` after `import_oa_references`).
18
+ - `reject_refs` / `status_refs` — the references applied (resolve to citations; their disclosure text is on the citation's `plainText` after `write {resource:"oa", action:"import-references"}`).
19
19
  - `match`, `page` — the verbatim rejection text and page in the OA.
20
20
 
21
21
  `oa_data.claim_dispositions` tells you the big picture: `allowed_claims`, `rejected_claims`, `objected_claims`, `withdrawn_claims`, `restriction_or_election`.
@@ -34,10 +34,20 @@ Before working rejection-by-rejection, orient the attorney with two things:
34
34
  |---|---|---|
35
35
  | _e.g. "a processor configured to…"_ | _e.g. Smith ¶[0042], Fig. 3_ | _e.g. Questionable — Smith discloses X but not the claimed Y_ |
36
36
 
37
- Fill the middle column from the rejection's `match`/`page` and the cited reference's disclosure text — call `get_reference_text({ citationId })` for the references the examiner applied (the `citationId` comes from the `import_oa_references` list). Fill the right column with your element-by-element read: is the examiner's mapping correct, a stretch, or wrong, and why. This table is the backbone of the §102/§103 analysis — the strongest distinctions surface here.
37
+ Fill the middle column from the rejection's `match`/`page` and the cited reference's disclosure text — call `read {resource:"reference-text", options:{citationId, query}}` for the references the examiner applied, passing the claim limitation (or the concept the examiner cited) as `query` to pull just the most relevant passages with paragraph numbers (`maxPassages` caps how many). The `citationId` comes from the `write {resource:"oa", action:"import-references"}` list. Fill the right column with your element-by-element read: is the examiner's mapping correct, a stretch, or wrong, and why. This table is the backbone of the §102/§103 analysis — the strongest distinctions surface here.
38
38
 
39
39
  Present the overview + table to the attorney, then proceed to the per-rejection analysis below.
40
40
 
41
+ ## Analyzing the cited references — fan out when there are several
42
+
43
+ The element-by-element mapping below depends on each cited reference's disclosure text (via `read {resource:"reference-text"}`). **If more than two references are cited** across the office action, analyze them **in parallel** rather than one at a time:
44
+
45
+ - Launch the reference-analysis agents in a single message (one Agent call per reference) so they run concurrently.
46
+ - Each agent's prompt must include the `projectId`, the `citationId`, and the claim language to map (the limitations of the rejected claim(s) the reference is applied against).
47
+ - Agents must **not** call `write {resource:"project", action:"save"}` — collect their findings and save once from the main conversation.
48
+
49
+ Each agent returns its reference's element-by-element mapping and the disclosure gaps it found; you assemble those into the per-rejection analysis. With two or fewer references, just analyze them inline — the fan-out overhead isn't worth it.
50
+
41
51
  ## §101 — Subject-matter eligibility (MPEP 2106)
42
52
 
43
53
  **Classify** the rejection into the Alice/Mayo step it turns on, and the abstract-idea grouping it asserts:
@@ -61,7 +71,7 @@ Present the overview + table to the attorney, then proceed to the per-rejection
61
71
  2. For each, find where (if anywhere) the reference discloses it; quote the passage.
62
72
  3. Identify at least one element that is **absent** from the reference (or not arranged as claimed). That gap is the anticipation argument.
63
73
 
64
- To get a reference's text, call `get_reference_text({ citationId })` (the `citationId` comes from the `import_oa_references` list). It returns clean EPO text, or the PDF as base64 to read, or a Google Patents link, or captured OCR text, and only asks the attorney as a last resort. Never guess a reference's contents.
74
+ To get a reference's text, call `read {resource:"reference-text", options:{citationId, query, maxPassages}}` (the `citationId` comes from the `write {resource:"oa", action:"import-references"}` list). Pass the claim limitation or the examiner's cited concept as `query` to retrieve just the most relevant passages (with ¶ numbers) instead of the whole disclosure — better for element mapping and far smaller. It returns clean EPO text or targeted passages, a presigned PDF download URL (`pdf_url`) to read, a Google Patents link, or captured OCR text, and only asks the attorney as a last resort. Never guess a reference's contents.
65
75
 
66
76
  ## §103 — Obviousness (MPEP 2141–2145)
67
77
 
@@ -1,68 +1,154 @@
1
1
  # Office Action Response Drafting & Save Contracts
2
2
 
3
- **Version: 4**
3
+ **Version: 25**
4
4
 
5
5
  This file defines how drafted amendments and arguments are written back to Fenix. Everything here happens **after** the attorney approves the strategy (Phase 4) and the draft (Phases 5–6).
6
6
 
7
+ ## The model in one paragraph
8
+
9
+ You save **clean data**; Fenix renders the document. Save the **amended claim text** (clean — no markup) with status `Currently Amended`, the **per-rejection argument** prose, and the **amendment bookkeeping**. The OAR document generator then derives amendment markup (underline additions / strikethrough deletions) by diffing your amended claims against the as-pending snapshot, and inserts each argument after its boilerplate — automatically. You do **not** produce markup or hand-fill the document.
10
+
7
11
  ## Where each artifact is saved
8
12
 
9
13
  | Artifact | Saved to | How |
10
14
  |---|---|---|
11
- | Amended claim text | `Project.claims` | `save_project({ type: "claims" })` |
12
- | Which claims were amended / cancelled / added | `oa_data.amendmentsStatus` | `save_project({ fields: { oa_data } })` (read-merge-write) |
13
- | Per-rejection drafted argument | `oa_data.oa_rejections[i].argument` / `.response_strategy` | `save_project({ fields: { oa_data } })` (read-merge-write) |
14
- | Final remarks prose | `Project.sections` | `save_project({ type: "sections" })` |
15
+ | One amended/new claim | `Project.claims` (by claimNumber) | `write {resource:"project", action:"save", options:{type: "claim", claim}}` — **preferred** |
16
+ | Several claims at once | `Project.claims` | `write {resource:"project", action:"save", options:{type: "claims", claims: [...]}}` |
17
+ | Which claims were amended / cancelled / added | `oa_data.amendmentsStatus` | `write {resource:"project", action:"save", options:{fields: { oa_data }}}` (read-merge-write) |
18
+ | Per-rejection drafted argument | `oa_data.oa_rejections[i].argument` / `.response_strategy` | `write {resource:"project", action:"save", options:{fields: { oa_data }}}` (read-merge-write) |
19
+ | Final remarks prose | `Project.sections` | `write {resource:"project", action:"save", options:{type: "sections"}}` |
15
20
 
16
- ## Save efficientlybatch in ONE call
21
+ ## Amendment markup is automatic save clean text
17
22
 
18
- At the end of drafting you typically save several things: the updated `oa_data` (amendmentsStatus + per-rejection arguments), the amended `claims`, and the remarks `sections`. **Do them in a single `save_project` call using the `operations` array** do not make a separate call for each:
23
+ When you amend a claim, save the **final amended claim text only** (the clean "after" version) with `claimStatus: "Currently Amended"`. Fenix keeps an immutable snapshot of the as-pending claims (`oa_data.original_claims`) and, when it generates the OAR document, diffs your amended claim against that snapshot to produce the underline/strikethrough markup and the `(Currently Amended)` heading. **Do not** embed underline/strikethrough, brackets, or any markup in `claimText` — just the clean amended language.
19
24
 
20
- ```
21
- save_project({
22
- projectId,
23
- operations: [
24
- { fields: { oa_data: <full merged oa_data> } }, // amendmentsStatus + oa_rejections[].argument (read-merge-write)
25
- { type: "claims", claims: [ ... ] }, // amended claims
26
- { type: "sections", sections: { ... } } // remarks
27
- ]
28
- })
29
- ```
25
+ ### Use the LEAST markup possible — minimal, surgical edits
26
+
27
+ The markup is a **word-level diff** against the as-pending claim, so every word you change becomes strikethrough (deletion) or underline (addition). Make the amendment as small as the change requires:
28
+
29
+ - **Start from the exact as-pending claim text** and edit only the words the amendment actually needs. Keep all surrounding language **verbatim** — same words, same order.
30
+ - **Do not reword, rephrase, "clean up," reorder, or re-punctuate** any part you are not deliberately amending. Rewording untouched text produces large, noisy markup that overstates the scope of the amendment (and can create unintended prosecution-history estoppel).
31
+ - If your edit to a limitation changes more than the words you intend, you have reworded too much — revert to the original wording and make a tighter change.
32
+
33
+ ### Preserve the claim's existing formatting
34
+
35
+ Keep the as-pending claim's structure so the diff lines up cleanly limitation-by-limitation:
36
+
37
+ - Keep the **same line breaks between limitations** — one `claimText` array entry per limitation/line, exactly as in the as-pending claim. Edit *within* the existing lines; do not merge limitations onto one line or re-split them.
38
+ - Keep the same punctuation, indentation, and ordering of limitations.
39
+
40
+ If the `claimText` array structure changes, the diff can no longer align limitations and instead strikes an entire limitation and re-inserts it — turning a one-word change into a whole-paragraph rewrite in the markup. Matching the original structure keeps the markup minimal and readable.
30
41
 
31
- The operations run in order; the response returns a `steps` array — check each `ok`, and the claims step's `parseVerification.ok`. The single-operation params still work for one-off saves.
42
+ ## Prefer single-claim saves
43
+
44
+ Amendments usually touch a few claims out of many. Save each amended (or new) claim on its own with `write {resource:"project", action:"save", options:{type: "claim", claim: { ... }}}` — it upserts that one claim by `claimNumber` and re-derives the claim tree, instead of re-sending the whole set. Use the bulk `type: "claims"` only when you are replacing most/all of the claims.
32
45
 
33
46
  ## CRITICAL: read-merge-write for `oa_data`
34
47
 
35
- `save_project({ fields: { oa_data } })` **replaces the entire `oa_data` object** (it is a `$set`). To avoid wiping the imported rejections, dispositions, and references, you must:
48
+ `write {resource:"project", action:"save", options:{fields: { oa_data }}}` **replaces the entire `oa_data` object** (it is a `$set`). To avoid wiping the imported rejections, dispositions, references, and the `original_claims` snapshot, you must:
36
49
 
37
- 1. Load the current full object: `get_project({ projectId, include: ["oa_data"] })`.
38
- 2. Modify the in-memory object (add `amendmentsStatus`, set `oa_rejections[i].argument`, etc.) **without dropping any existing keys**.
39
- 3. Save the complete merged object back: `save_project({ projectId, fields: { oa_data: <full merged object> } })`.
50
+ 1. Load the current full object: `read {resource:"project", options:{projectId, include: ["oa_data"]}}`.
51
+ 2. Modify the in-memory object (set `amendmentsStatus`, `oa_rejections[i].argument`, etc.) **without dropping any existing keys**.
52
+ 3. Save the complete merged object back: `write {resource:"project", action:"save", options:{projectId, fields: { oa_data: <full merged object> }}}`.
40
53
 
41
- Never send a partial `oa_data`.
54
+ Never send a partial `oa_data`. (Single-claim and `type:"claims"` saves write `Project.claims`, not `oa_data`, so they never touch `original_claims`.)
42
55
 
43
56
  ## Amendment status conventions (37 CFR 1.121)
44
57
 
45
- Every claim presented in an amendment carries a status identifier. Use these exact `claimStatus` values:
46
- - **(Original)** — unchanged since filing.
47
- - **(Currently Amended)** — being changed in this response (show changes with underline/strikethrough in the remarks/document, not in the stored `claimText`).
48
- - **(Previously Presented)** — added/amended in an earlier response, unchanged now.
49
- - **(Canceled)** — removed; no claim text.
50
- - **(New)** — newly added in this response.
51
- - **(Withdrawn)** — non-elected; not under examination.
52
-
53
- ## Saving amended claims
58
+ Use these exact `claimStatus` values:
59
+ - **Original** — unchanged since filing.
60
+ - **Currently Amended** — changed in this response. Save the clean amended text; markup + heading are derived.
61
+ - **Previously Presented** — amended in an earlier response, unchanged now.
62
+ - **Canceled** — removed; no claim text.
63
+ - **New** — newly added in this response.
64
+ - **Withdrawn** — non-elected; not under examination.
54
65
 
55
- `save_project({ type: "claims", claims: [ ... ] })` where each claim is:
66
+ ## Saving a claim
56
67
 
57
68
  ```
58
- { claimNumber: "1", claimStatus: "Currently Amended", claimType: "independent",
59
- claimText: ["...limitation...", "...limitation..."], parent: "", independentParent: "" }
69
+ write {resource:"project", action:"save", options:{type: "claim", claim: {
70
+ claimNumber: "7", claimStatus: "Currently Amended", claimType: "dependent",
71
+ claimText: ["...clean amended limitation...", "..."], parent: "1", independentParent: "1"
72
+ }}}
60
73
  ```
61
74
 
62
- - Dependent claims set `claimType: "dependent"`, `parent` to the claim they depend from, and `independentParent` to the root independent claim.
63
- - You may instead pass `rawClaims` (text); the server parses it and returns `parseVerification`.
75
+ - Independent claims set `claimType: "independent"` and empty `parent`/`independentParent`.
76
+ - For a bulk `type:"claims"` save with `rawClaims` text, the response includes `parseVerification`. **You MUST evaluate `parseVerification.ok`** — if `false`, parse the claims yourself into the structured array and re-save; do not just resend raw text.
77
+ - Optional optimistic concurrency: pass `baseRev` (the `claimsRev` you loaded) to have a stale save rejected (409) instead of overwriting.
78
+
79
+ ## Save efficiently — batch in ONE call
64
80
 
65
- **You MUST evaluate `parseVerification.ok` in the response.** If it is `false` (gaps in numbering, suspected merged claims, or count mismatch vs. `sourceClaimMarkers`), the auto-parse failed: parse the claims yourself into the structured array above and re-call `save_project({ type: "claims", claims: [...] })` with your corrected JSON. Do not just resend raw text.
81
+ Save several things in a single `write {resource:"project", action:"save"}` call with the `operations` array (runs in order; returns a `steps` array check each `ok`):
82
+
83
+ ```
84
+ write {resource:"project", action:"save", options:{projectId,
85
+ operations: [
86
+ { fields: { oa_data: <full merged oa_data> } }, // amendmentsStatus + oa_rejections[].argument (read-merge-write)
87
+ { type: "claim", claim: { claimNumber: "1", claimStatus: "Currently Amended", ... } },
88
+ { type: "claim", claim: { claimNumber: "7", claimStatus: "Currently Amended", ... } },
89
+ { type: "section", sectionName: "Conclusion", paragraphs: [ "..." ] } // ONE remarks section (repeat the op for more)
90
+ ]}}
91
+ ```
92
+
93
+ ## Hand a big save to a background agent
94
+
95
+ A full `oa_data` — every rejection with its drafted argument, the amendment
96
+ bookkeeping, and the `original_claims` snapshot you must carry through — is a
97
+ large payload, and in the main conversation it costs you **twice**: once in the
98
+ call you write out, and again in the result echoed back. When the content is
99
+ **settled** (the attorney has approved it), delegate the save and keep working.
100
+
101
+ The two payload shapes here are not equally safe to delegate, and the difference
102
+ matters:
103
+
104
+ **Claims** (`type: "claim"` / `type: "claims"`) are revision-checked. Write the
105
+ approved claim objects to a file, and have the agent make one call passing
106
+ `baseRev` (the `claimsRev` you loaded). A stale save is then rejected with a 409
107
+ instead of overwriting whoever moved first.
108
+
109
+ **`oa_data` is NOT revision-checked.** It is saved through `fields`, which is a
110
+ whole-object `$set` — there is no `baseRev` for it and no 409 to catch a race.
111
+ Two writers silently produce one survivor. So for `oa_data`:
112
+
113
+ - **Give the agent the PATCH, not the merged object.** Put only what you drafted
114
+ (the per-rejection `argument` / `response_strategy`, `amendmentsStatus`) in the
115
+ file, and have the agent do the whole read-merge-write itself: load the current
116
+ `oa_data`, apply your patch over it without dropping any existing keys, save the
117
+ complete object. That keeps the READ fresh. A merged object computed in the main
118
+ conversation and saved minutes later silently reverts anything that changed in
119
+ between — the exact failure `original_claims` cannot survive.
120
+ - **Never run two agents against `oa_data`,** and do not run one while the
121
+ attorney is editing rejections in the OA editor. With no rev check, the loser's
122
+ work is simply gone.
123
+
124
+ A prompt of the right shape:
125
+
126
+ > Read `<path>/oa-patch.json`. Then: (1) load the current `oa_data` with
127
+ > `read {resource:"project", options:{projectId:"<id>", include:["oa_data"]}}`;
128
+ > (2) apply the patch over it — set only the keys the patch names, drop nothing,
129
+ > and leave `original_claims` and every existing rejection key untouched;
130
+ > (3) save the COMPLETE merged object with
131
+ > `write {resource:"project", action:"save", options:{projectId:"<id>", fields:{oa_data:<merged>}}}`.
132
+ > Do not edit, re-word, re-order or add to any argument text — it is
133
+ > attorney-approved work product. Reply with the rejection count and which keys
134
+ > you set, or the full error if it failed.
135
+
136
+ **Rules**
137
+
138
+ - The agent **saves; it does not draft.** Amendments and arguments are legal work
139
+ product approved by the attorney in the main conversation. An agent asked to
140
+ "finish" or "improve" anything will write text nobody approved.
141
+ - **Only for saves that are large and settled.** One argument, or a two-claim
142
+ amendment, costs more to delegate than to call.
143
+ - **One save per agent.** Writing the file is the step that actually saves
144
+ anything — the agent reads it, so the JSON never passes through the conversation
145
+ a second time. Pasting the payload into the agent's prompt saves nothing.
146
+ - **Check its result before you rely on the save**, and before you generate the
147
+ response document. A save you never confirmed is not a save, and Phase 7 prints
148
+ from whatever is actually stored.
149
+ - **If your host cannot run a background agent,** or the agent cannot reach the
150
+ Fenix tools, just make the call yourself — that is always the fallback, and a
151
+ delegated save that never happened is worse than a slow one.
66
152
 
67
153
  ## Saving the amendment bookkeeping
68
154
 
@@ -80,25 +166,33 @@ amendmentsStatus: {
80
166
 
81
167
  ## Saving the per-rejection arguments
82
168
 
83
- For each rejection you responded to, set two keys on that entry in `oa_data.oa_rejections` (read-merge-write):
169
+ For each rejection you responded to, set on that entry in `oa_data.oa_rejections` (read-merge-write):
84
170
  - `response_strategy`: `"amend"` | `"argue"` | `"both"`.
85
- - `argument`: the drafted argument prose for that rejection.
171
+ - `argument`: the drafted argument prose.
86
172
 
87
- This keeps each argument co-located with the rejection it answers. Do not remove or reorder the existing keys (`status_type`, `status_claims`, `status_refs`, etc.).
173
+ These are **rendered automatically** into the OAR document — each argument is inserted right after that rejection's static boilerplate. Keep the argument as clean prose (blank lines separate paragraphs). Do not remove or reorder the existing rejection keys (`status_type`, `status_claims`, `status_refs`, etc.).
88
174
 
89
- ## Saving the remarks
175
+ ## Editors (Cowork live artifacts)
90
176
 
91
- Write the Remarks as project `sections`: a claim-status summary section, then one section per rejection (in OA order) containing the approved argument. Save with `save_project({ type: "sections", sections: { ... } })` (bulk) or `save_project({ type: "section", sectionName, paragraphs: [<HTML strings>] })` per section. Keep the section names stable — the OA shell print consumes them.
177
+ For a review/revision pass after the one-by-one drafting, offer a live editor (ask first never open unprompted):
92
178
 
93
- ## Remarks structure (recommended)
179
+ - **Rejections & arguments** — bind the matter with `write {resource:"context", options:{ids: { projectId }, label: "<matter number>"}}`, then have the attorney open the **installed Fenix OA editor** from their artifacts sidebar. **Never write, edit, or substitute anything into the artifact**; see `references/editors.md` in fenix-application. It loads the rejections (and reference labels) and lets the attorney edit each rejection's **type, claims, applied references, response strategy, and argument** (and add/remove rejections), **read-merge-writes the full `oa_data` itself**, and returns a `[OA REJECTIONS SAVED]` diff. When the attorney pastes that diff, **do not re-save** — it already persisted; just apply the delta to your working copy.
180
+ - **Amendments (claims)** — use the `claims-editor` artifact to edit the amended claim text. Save the **clean** amended text with status `Currently Amended`; the document derives the underline/strikethrough markup on print.
94
181
 
95
- 1. **Status of the claims** — what is pending, amended, canceled, new; which are allowed/objected.
96
- 2. **Claim amendments** — the marked-up claims (handled by the claims save + the document).
97
- 3. **Arguments**, one heading per rejection, in OA order — for each: restate the rejection briefly, then the approved argument (the element gap for §102/§103, the eligibility/practical-application argument for §101, the spec citations for §112, etc.).
98
- 4. **Conclusion** — request allowance / reconsideration; offer an interview if appropriate.
182
+ ## Remarks
99
183
 
100
- Always confirm the full remarks with the attorney before saving.
184
+ Save any standalone remarks (claim-status summary, conclusion) as `sections`. **Two shapes — pick the right one (a wrong shape costs a failed save + retry):**
185
+ - **One section** (the usual case): `write {resource:"project", action:"save", options:{type: "section", sectionName: "Conclusion", paragraphs: ["<html paragraph>", "..."]}}`.
186
+ - **All sections at once:** `write {resource:"project", action:"save", options:{type: "sections", sections: { "Conclusion": {...}, "Status of the Claims": {...} }}}` — here `sections` is a **map of name → content**, never a single section.
187
+
188
+ In a batch `operations` array, save each remarks section with its own `type: "section"` op (`sectionName` + `paragraphs`); do **not** put a single section under `type: "sections"`. The per-rejection arguments live on `oa_data` (above) and are auto-inserted — do not duplicate them in `sections`.
101
189
 
102
190
  ## Assembling the response document
103
191
 
104
- After the amendments and arguments are saved, assemble the Word response document per **Phase 7** of `oa-response.md`: `get_oa_shell_doc({ projectId })` returns a direct `downloadUrl` to the formatted Fenix shell; download it to an authorized folder (or use `delivery: "base64"` if you can't download a URL), use your docx skill to insert the saved arguments and amended-claim text into the blanks, and present the filled document to the attorney. The attorney does not need to download or upload anything.
192
+ Because the amended-claim markup and the per-rejection arguments are rendered from the saved data, the generated OAR document already contains them there is no manual hand-filling for those:
193
+
194
+ 1. `write {resource:"oa", action:"generate-shell", options:{projectId}}` → returns a direct `downloadUrl` to the formatted OAR document (now populated with the marked-up claims and the arguments).
195
+ 2. Download it and review. Use your docx skill only for any residual blanks the template leaves that are **not** driven by saved data (e.g. signature/date).
196
+ 3. Present the document to the attorney. (If you can't download a URL, pass `delivery: "base64"`.)
197
+
198
+ **Avoiding "the file got truncated."** The OAR document from `write {resource:"oa", action:"generate-shell"}` is generated **whole** — treat it as the finished file, not a draft to rebuild. Do **not** read its full text back and regenerate the `.docx` from that: a long document gets truncated on read, so the rebuilt file silently loses whatever fell past the cutoff. For the residual blanks only (signature/date), make **targeted, in-place edits** to the downloaded file (find-and-replace the specific text/field with your docx skill) and leave the rest byte-for-byte untouched — never re-emit the whole document. After editing, reopen it and confirm the last section (signature block / conclusion) is present before presenting it.
@@ -1,32 +1,32 @@
1
1
  # Office Action Response Workflow
2
2
 
3
- **Version: 4**
3
+ **Version: 25**
4
4
 
5
5
  This is the end-to-end workflow for responding to a USPTO Office Action. Work through the phases in order. **Each drafting phase ends with attorney approval before anything is saved** — you draft, the attorney approves, then you save. This is legal work product; never save amendments or arguments the attorney has not approved.
6
6
 
7
7
  ## Invariants (always)
8
8
 
9
- - **Never pass `clientDb`.** It is inferred from the connector's API key. Passing it is an error.
10
- - **Never auto-generate a document.** Only call `print_patent({ type: "oa_shell" })` when the attorney explicitly asks for the Word document.
9
+ - **Never pass `clientDb`.** The tools no longer accept it — the firm is fixed by the connector you signed in to (each firm authenticates to its own MCP endpoint), so there is nothing to override.
10
+ - **Never auto-generate a document.** Only call `read {resource:"patent-document", options:{type: "oa_shell"}}` when the attorney explicitly asks for the Word document.
11
11
  - **Approval gate before every save.** Show the draft, ask for changes, save only after the attorney confirms.
12
12
  - **Never fabricate prior-art content.** Only distinguish a reference whose disclosure text you actually have (see Phase 3).
13
13
 
14
14
  ## Phase 1 — Identify the matter and the OA project
15
15
 
16
- 1. Identify the matter: `get_project({ identifier })` (exact app/matter number) or `get_project({ query })` (keyword). Confirm the matter with the attorney.
16
+ 1. Identify the matter: `read {resource:"project", options:{identifier}}` (exact app/matter number) or `read {resource:"project", options:{query}}` (keyword). Confirm the matter with the attorney.
17
17
  2. The response includes a `projects` array. Look for an existing Office-Action-response project. If one exists, use its `projectId`.
18
18
  3. If none exists, create one: `list_project_types` → `create_project` (matter/app number, notification date, due date, type, and the assignee's **initials** — pass the initials directly; the backend resolves them to the user, so you do **not** need to look the user up first) → `assign_project` only if WA1/WA2 need changing. (The `fenix-project` skill covers the intake flow.)
19
19
 
20
20
  ## Phase 2 — Pull the Office Action facts from USPTO
21
21
 
22
- 1. `populate_project_from_uspto({ projectId })`. If `matter.applicationNum` is missing it will tell you — ask the attorney for the application number and pass it as `applicationNum`.
23
- 2. Load the full state: `get_project({ projectId, include: ["matter", "claims", "oa_data"] })`.
22
+ 1. `write {resource:"project", action:"populate-from-uspto", options:{projectId}}`. If `matter.applicationNum` is missing it will tell you — ask the attorney for the application number and pass it as `applicationNum`.
23
+ 2. Load the full state: `read {resource:"project", options:{projectId, include: ["matter", "claims", "oa_data"]}}`.
24
24
  3. **Report to the attorney and stop:** OA date and type (Non-Final / Final / Restriction), examiner, the rejections grouped by statute, which claims are rejected/objected/allowed, the cited references, and whether claims/spec/figures amendments are flagged. Let the attorney confirm the picture before you analyze.
25
25
 
26
26
  ## Phase 3 — Pull the cited-reference text
27
27
 
28
- 1. `import_oa_references({ projectId })` — downloads the cited references and returns a **compact list** (`references[]` with `citationId`, `label`, `number`, `pubType`, `fileUrl`, `ocrTextChars`). It does **not** return the full text (that would flood the context). The response also includes the project `dashboardUrl` (→ Citations tab) you can share.
29
- 2. For each reference you actually need to read — usually the ones the examiner applied against the claims you are arguing — call `get_reference_text({ citationId })`. It walks a fallback chain and returns whichever source worked (`source` tells you which):
28
+ 1. `write {resource:"oa", action:"import-references", options:{projectId}}` — downloads the cited references and returns a **compact list** (`references[]` with `citationId`, `label`, `number`, `pubType`, `fileUrl`, `ocrTextChars`). It does **not** return the full text (that would flood the context). The response also includes the project `dashboardUrl` (→ Citations tab) you can share.
29
+ 2. For each reference you actually need to read — usually the ones the examiner applied against the claims you are arguing — call `read {resource:"reference-text", options:{citationId}}`. It walks a fallback chain and returns whichever source worked (`source` tells you which):
30
30
  - **`epo`** — clean structured claims + description in `text`; use it directly.
31
31
  - **`google_patents_url`** — read the `url` with your web tools.
32
32
  - **`pdf_url`** — download the `downloadUrl` to a local `.pdf` and read it with your pdf/Read tools (don't WebFetch it). (`source: "pdf_base64"` returns the bytes inline only if you can't download a URL.)
@@ -40,19 +40,32 @@ Read `references/oa-analysis.md`. For each rejection, classify it into a sub-typ
40
40
 
41
41
  ## Phase 5 — Draft and save the amendments
42
42
 
43
- Read `references/oa-drafting.md`. Draft amended claim text with the correct claim status. Confirm with the attorney, then save: amended claims via `save_project({ type: "claims" })` (and you **must** check `parseVerification.ok`), and the amendment bookkeeping into `oa_data.amendmentsStatus`.
43
+ Read `references/oa-drafting.md`. Draft amended claim text with the correct claim status. Confirm with the attorney, then save: amended claims via `write {resource:"project", action:"save", options:{type: "claims"}}` (and you **must** check `parseVerification.ok`), and the amendment bookkeeping into `oa_data.amendmentsStatus`.
44
44
 
45
- ## Phase 6 — Draft and save the remarks
45
+ ## Phase 6 — Draft the arguments, one rejection at a time
46
46
 
47
- Read `references/oa-drafting.md`. Write the Remarks: a claim-status summary followed by one argument section per rejection, using the analysis from Phase 4. Confirm with the attorney, then save the per-rejection argument text into `oa_data.oa_rejections[i]` and the final prose as project `sections`.
47
+ Read `references/oa-drafting.md`. Draft the arguments **one rejection at a time** (like the figure-description flow), not all in a single dump:
48
48
 
49
- ## Phase 7 Assemble the response document
49
+ For each rejection, in OA order:
50
+ 1. Draft the argument from the Phase-4 analysis (the §102/§103 element gap, the §101 eligibility/practical-application argument, the §112 spec citations, etc.) and the firm's scaffolds.
51
+ 2. **Present that one argument to the attorney and END TURN.** Wait for confirmation or edits.
52
+ 3. Once approved, move to the next rejection — hold the approved arguments, don't save yet.
50
53
 
51
- Once the amendments and arguments are drafted, saved, and approved, assemble the actual response document. The Fenix shell is the firm's formatted template, but it leaves the arguments and amended-claim text **blank** you fill those in (the attorney does not need to download or upload anything):
54
+ After all arguments are approved, save them in **one** read-merge-write: set each `oa_data.oa_rejections[i].argument` (and `response_strategy`) on the full `oa_data` and save once. Also save any standalone remarks as `sections` (use the exact save shape in `references/oa-drafting.md` getting it wrong wastes a retry).
52
55
 
53
- 1. `get_oa_shell_doc({ projectId })` returns a direct `downloadUrl` (presigned, ~1 hour) to the shell.
54
- 2. **Download** `downloadUrl` into a folder you are authorized to write to — it is a direct, public file URL, so save it to disk; do **not** WebFetch it (WebFetch returns text and cannot handle a binary `.docx`). If your environment cannot download a URL to a file, call `get_oa_shell_doc({ projectId, delivery: "base64" })` and write the returned `base64` to a local `.docx` instead.
55
- 3. Use your **docx skill** to insert the drafted arguments and amended claims into the blanks. You already have this content from Phases 4–6 and from the saved project data (`oa_data.oa_rejections[].argument`, `oa_data.amendmentsStatus`, `claims`, `sections`).
56
- 4. Present the filled `.docx` to the attorney for review. Share the `dashboardUrl` so they can open the case in Fenix.
56
+ ### Required before printing offer the arguments editor
57
57
 
58
- (If the attorney only wants the blank shell, `print_patent({ type: "oa_shell" })` still returns just the download link.)
58
+ Once the arguments are saved, you **must offer the arguments editor before generating any document.** This is a required step; do not skip it and do not jump straight to printing. Say it explicitly, e.g.:
59
+
60
+ > "The arguments are saved. Want me to open the **OA rejections & arguments editor** so you can review and revise them all together before I generate the response? (Or I can generate it now.)"
61
+
62
+ If yes, open the `oa-arguments-editor` live artifact (see `references/oa-drafting.md`) — it lets the attorney adjust each rejection's type, claims, applied references, response strategy, and argument (and add/remove rejections), saves itself, and returns a `[OA REJECTIONS SAVED]` diff to paste back (apply the diff; do not re-save). Only move to Phase 7 after the attorney has used the editor or explicitly declined it. (Amendments are reviewed in the `claims-editor`; markup is derived on print.)
63
+
64
+ ## Phase 7 — Generate and review the response document
65
+
66
+ Only after you have offered the arguments editor (Phase 6) and the attorney has used or declined it, generate the response document. Fenix renders the **amended-claim markup** (underline/strikethrough, derived from the saved clean claims) and the **per-rejection arguments** (inserted after each boilerplate) directly from the saved data — so the document already contains them. There is no manual hand-filling for those.
67
+
68
+ 1. `write {resource:"oa", action:"generate-shell", options:{projectId}}` → returns a direct `downloadUrl` (presigned, ~1 hour) to the formatted OAR document, populated with the marked-up claims and the arguments.
69
+ 2. **Download** `downloadUrl` to a folder you can write to — it is a direct, public file URL, so save it to disk; do **not** WebFetch it. If your environment cannot download a URL, call `write {resource:"oa", action:"generate-shell", options:{projectId, delivery: "base64"}}` and write the `base64` to a local `.docx`.
70
+ 3. **Scan the document for anything left to fill.** Read the downloaded `.docx` and find any remaining blanks, highlighted fields, bracketed placeholders, or template variables (e.g. `[ … ]`, `{{ … }}`, highlighted runs, and signature / date / customer-number / attorney-docket blanks). List exactly what you found and **ask the attorney whether to fill each one in, and with what** — then apply the answers with your **docx skill**. Do not silently leave them or guess values.
71
+ 4. Present the document to the attorney for review. Share the `dashboardUrl` so they can open the case in Fenix.
@@ -6,7 +6,7 @@ description: >-
6
6
 
7
7
  # Fenix Project
8
8
 
9
- **Skill version: 2** (authoritative version is in the top-level `VERSION` file; this line is for reference only).
9
+ **Skill version: 4** (authoritative version is in the top-level `VERSION` file; this line is for reference only).
10
10
 
11
11
  ## Triggers
12
12
 
@@ -16,11 +16,12 @@ description: >-
16
16
 
17
17
  ## Customization
18
18
 
19
- Before applying any workflow in this skill, read the `CUSTOMIZE.md` file in this skill directory. 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.
19
+ 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.
20
+
21
+ 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.
20
22
 
21
23
  Apply the custom overrides **only as long as the result still satisfies every structured-output contract** this skill depends on, including:
22
24
  - the JSON shapes passed to `save_project` (claims, figures, sections)
23
- - the `[EDITOR SUBMIT - <type>]` clipboard prefixes produced by the HTML editors
24
25
  - the figure ElementSchema (`type`, `label`, `number`, `text`) and component numbering rules
25
26
  - the spec section names and ordering required by the save/print tools
26
27
 
@@ -1 +1 @@
1
- 2
1
+ 4
@@ -1,9 +1,19 @@
1
1
  # Create Project
2
2
 
3
- **Version: 2**
3
+ **Version: 4**
4
4
 
5
5
  1. **Collect** -- matter/app number, notification date, project type ('list_project_types'), due date, assignee initials
6
6
  2. **Confirm** -- show all values. Ask 'Ready to create -- any changes?' **END TURN**
7
7
  3. **Create** -- 'create_project' once confirmed. Pass the assignee **initials** directly -- the backend resolves initials to the user automatically (no need to call 'get_user_by_initials'). If the initials are not recognised, create_project returns an error so you can ask for the correct initials.
8
8
 
9
+ ## The notification date is the date the USER gives you -- never today
10
+
11
+ `notificationDate` is a REQUIRED field and it is **whatever date the user states** for this filing or action -- the date on the office action, the date the notice was received, the filing/receipt date for a new application. If the user gives you a date at any point during intake, that date is the notificationDate; do **not** quietly substitute today's date, and do not put the user's date in `dueDate` instead.
12
+
13
+ **Why it matters: it is the one field that tells two projects on the same matter apart.** A matter can carry several projects -- two office actions, an application and its continuation, refilings -- and they share a matter number and an invention title, so in every list and in the editor's matter switcher they look identical. The notification date is the disambiguator. Getting it wrong (or defaulting it to today) leaves the user with two rows they cannot tell apart and cannot reliably pick between.
14
+
15
+ If the user has not given a date, **ask for it** rather than inventing one. For a brand-new application with no notice, ask which date they want recorded (filing date, receipt date); it still has to be a real, deliberate value, because it is what will distinguish this project later.
16
+
17
+ `dueDate` is a DIFFERENT field -- the response/action deadline. Keep the two separate; if the user gives only one date, confirm which it is before creating.
18
+
9
19
  If any field is missing: render a React form with all fields. On submit show confirmation block, then 'create_project'.