@stablebaseline/sdk 0.1.0 → 0.3.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.
package/openapi.json CHANGED
@@ -487,7 +487,7 @@
487
487
  "/tools/listArchitectureIcons": {
488
488
  "post": {
489
489
  "summary": "listArchitectureIcons",
490
- "description": "List icons for systemsarchitecture diagrams. Use returned iconPath as-is in D2 code (e.g. icon: dev/docker.svg).",
490
+ "description": "List curated software-architecture icons (AWS, Azure, GCP, Docker, Kubernetes, databases, message queues, etc.). Each result has an `iconPath` (e.g. 'dev/docker.svg'). TWO ways to use it: (1) on a WHITEBOARD, drop it via addWhiteboardElements({ type:'image', iconPath:'dev/docker.svg', x, y, width:96, height:96, text:'Docker' }); (2) in a D2 systems-architecture diagram, use the iconPath as-is in D2 code (e.g. icon: dev/docker.svg).",
491
491
  "operationId": "listArchitectureIcons",
492
492
  "tags": [
493
493
  "diagrams"
@@ -700,7 +700,7 @@
700
700
  "description": "Return the calling user's identity (user_id, display_name, full_name, email, avatar_url). Use this when the user says 'me' / 'mine' / 'I' so you can resolve to their UUID before passing it to tools like updateImprovement(owner_id=…) or filtering by owner. Read-only.",
701
701
  "operationId": "getCurrentUser",
702
702
  "tags": [
703
- "uncategorized"
703
+ "members"
704
704
  ],
705
705
  "requestBody": {
706
706
  "required": false,
@@ -791,10 +791,10 @@
791
791
  "/tools/listAssignablePrincipals": {
792
792
  "post": {
793
793
  "summary": "listAssignablePrincipals",
794
- "description": "Server-side searchable, paginated list of USERS and TEAMS that can be assigned as the owner of an improvement/task in a project. Returns two arrays — `users` (with user_id, display_name, email, avatar_url, has_explicit_permission) and `teams` (with team_id, name, member_count, has_explicit_permission). Sources: project-level grants + workspace members + organization members + members of teams granted access. Use BEFORE updateImprovement/updateTask when you need to discover an `owner_id` (kind='user') or `owner_team_id` (kind='team') by name. Supports `q` for ILIKE search on names/emails (users) or team names. Pass `kind='user'` or `kind='team'` to scope to a single section, or 'all' (default) for both. Pagination via limit (1-100, default 20) + offset.",
794
+ "description": "Server-side searchable, paginated list of USERS and TEAMS that can be assigned as the owner of an improvement/task in a project — and the canonical source for resolving a person's user_id when @-mentioning them in a document. Returns two arrays — `users` (with user_id, display_name, email, avatar_url, has_explicit_permission) and `teams` (with team_id, name, member_count, has_explicit_permission). Sources: project-level grants + workspace members + organization members + members of teams granted access. Use BEFORE: (1) updateImprovement/updateTask when you need an `owner_id` (kind='user') or `owner_team_id` (kind='team'); (2) inserting a `<!-- REFERENCE: {\"type\":\"user\",\"id\":\"…\",\"label\":\"…\"} -->` mention in document content via createDocument / editDocument / findAndReplaceTextInDocument. Supports `q` for ILIKE search on names/emails (users) or team names. Pass `kind='user'` or `kind='team'` to scope to a single section, or 'all' (default) for both. Pagination via limit (1-100, default 20) + offset.",
795
795
  "operationId": "listAssignablePrincipals",
796
796
  "tags": [
797
- "uncategorized"
797
+ "members"
798
798
  ],
799
799
  "requestBody": {
800
800
  "required": false,
@@ -1957,6 +1957,124 @@
1957
1957
  }
1958
1958
  }
1959
1959
  },
1960
+ "/tools/reorderFolders": {
1961
+ "post": {
1962
+ "summary": "reorderFolders",
1963
+ "description": "Batch-reorder folders within a parent (or project root) by setting sibling positions. Pass [{folderId, position}, ...] where position is a non-negative integer; usually you renumber siblings sequentially as 0, 1, 2…. To MOVE a folder to a different parent and set its position there, use updateFolder({parentId, position}) instead.",
1964
+ "operationId": "reorderFolders",
1965
+ "tags": [
1966
+ "folders"
1967
+ ],
1968
+ "requestBody": {
1969
+ "required": false,
1970
+ "content": {
1971
+ "application/json": {
1972
+ "schema": {
1973
+ "type": "object",
1974
+ "properties": {
1975
+ "items": {
1976
+ "type": "array",
1977
+ "description": "List of folder position updates. All folders must belong to the same project.",
1978
+ "items": {
1979
+ "type": "object",
1980
+ "properties": {
1981
+ "folderId": {
1982
+ "type": "string"
1983
+ },
1984
+ "position": {
1985
+ "type": "number"
1986
+ }
1987
+ },
1988
+ "required": [
1989
+ "folderId",
1990
+ "position"
1991
+ ]
1992
+ },
1993
+ "minItems": 1
1994
+ }
1995
+ },
1996
+ "required": [
1997
+ "items"
1998
+ ]
1999
+ }
2000
+ }
2001
+ }
2002
+ },
2003
+ "responses": {
2004
+ "200": {
2005
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
2006
+ "content": {
2007
+ "application/json": {
2008
+ "schema": {
2009
+ "type": "object",
2010
+ "additionalProperties": true
2011
+ }
2012
+ }
2013
+ }
2014
+ },
2015
+ "400": {
2016
+ "description": "Validation error.",
2017
+ "content": {
2018
+ "application/json": {
2019
+ "schema": {
2020
+ "$ref": "#/components/schemas/ErrorResponse"
2021
+ }
2022
+ }
2023
+ }
2024
+ },
2025
+ "401": {
2026
+ "description": "Missing or invalid credentials.",
2027
+ "content": {
2028
+ "application/json": {
2029
+ "schema": {
2030
+ "$ref": "#/components/schemas/ErrorResponse"
2031
+ }
2032
+ }
2033
+ }
2034
+ },
2035
+ "403": {
2036
+ "description": "Authenticated but lacking the required permission or feature flag.",
2037
+ "content": {
2038
+ "application/json": {
2039
+ "schema": {
2040
+ "$ref": "#/components/schemas/ErrorResponse"
2041
+ }
2042
+ }
2043
+ }
2044
+ },
2045
+ "404": {
2046
+ "description": "Resource not found.",
2047
+ "content": {
2048
+ "application/json": {
2049
+ "schema": {
2050
+ "$ref": "#/components/schemas/ErrorResponse"
2051
+ }
2052
+ }
2053
+ }
2054
+ },
2055
+ "422": {
2056
+ "description": "Body did not match the tool's input schema.",
2057
+ "content": {
2058
+ "application/json": {
2059
+ "schema": {
2060
+ "$ref": "#/components/schemas/ErrorResponse"
2061
+ }
2062
+ }
2063
+ }
2064
+ },
2065
+ "500": {
2066
+ "description": "Server error.",
2067
+ "content": {
2068
+ "application/json": {
2069
+ "schema": {
2070
+ "$ref": "#/components/schemas/ErrorResponse"
2071
+ }
2072
+ }
2073
+ }
2074
+ }
2075
+ }
2076
+ }
2077
+ },
1960
2078
  "/tools/listDocuments": {
1961
2079
  "post": {
1962
2080
  "summary": "listDocuments",
@@ -2469,7 +2587,7 @@
2469
2587
  "/tools/createDocument": {
2470
2588
  "post": {
2471
2589
  "summary": "createDocument",
2472
- "description": "Create a document from CDMD markdown. Call getCdmdLanguageGuide first if unfamiliar with syntax. Do not include DIAGRAM/IMAGE markers — insert them after with dedicated tools.",
2590
+ "description": "Create a document from CDMD markdown. Call getCdmdLanguageGuide first if unfamiliar with syntax. Do not include DIAGRAM/IMAGE markers — insert them after with dedicated tools. Supports @-mentioning people: embed `<!-- REFERENCE: {\"type\":\"user\",\"id\":\"<user_uuid>\",\"label\":\"Name\"} -->` to notify a teammate. Use listAssignablePrincipals to look up the user_id from a name; mentions of users outside the project are silently dropped.",
2473
2591
  "operationId": "createDocument",
2474
2592
  "tags": [
2475
2593
  "documents"
@@ -2493,6 +2611,10 @@
2493
2611
  "cdmd": {
2494
2612
  "type": "string"
2495
2613
  },
2614
+ "position": {
2615
+ "type": "number",
2616
+ "description": "Sort position within the parent folder (or project root if no folderId). When omitted, the document is appended at the end."
2617
+ },
2496
2618
  "changeSummary": {
2497
2619
  "type": "string",
2498
2620
  "description": "Version history summary."
@@ -2584,10 +2706,2086 @@
2584
2706
  "/tools/editDocument": {
2585
2707
  "post": {
2586
2708
  "summary": "editDocument",
2587
- "description": "Edit a document with line-based patches. Call getDocument first for line numbers and versionTimestamp. Call getCdmdLanguageGuide if unfamiliar with CDMD syntax. Do not edit DIAGRAM/IMAGE markers manually — use dedicated diagram/image tools.",
2709
+ "description": "Edit a document with line-based patches. Call getDocument first for line numbers and versionTimestamp. Call getCdmdLanguageGuide if unfamiliar with CDMD syntax. Do not edit DIAGRAM/IMAGE markers manually — use dedicated diagram/image tools. To @-mention a person in your patch, insert `<!-- REFERENCE: {\"type\":\"user\",\"id\":\"<user_uuid>\",\"label\":\"Name\"} -->`; look up the user_id via listAssignablePrincipals. Mentioned users are notified automatically.",
2588
2710
  "operationId": "editDocument",
2589
2711
  "tags": [
2590
- "documents"
2712
+ "documents"
2713
+ ],
2714
+ "requestBody": {
2715
+ "required": false,
2716
+ "content": {
2717
+ "application/json": {
2718
+ "schema": {
2719
+ "type": "object",
2720
+ "properties": {
2721
+ "documentId": {
2722
+ "type": "string"
2723
+ },
2724
+ "title": {
2725
+ "type": "string",
2726
+ "description": "New title."
2727
+ },
2728
+ "folderId": {
2729
+ "type": "string",
2730
+ "description": "Move to this folder."
2731
+ },
2732
+ "position": {
2733
+ "type": "number",
2734
+ "description": "Sort position within the parent folder. Use to reposition a single document. For batch sibling reorder, use reorderDocuments."
2735
+ },
2736
+ "versionTimestamp": {
2737
+ "type": "number",
2738
+ "description": "Version timestamp from getDocument() for optimistic locking."
2739
+ },
2740
+ "changeSummary": {
2741
+ "type": "string",
2742
+ "description": "Version history summary."
2743
+ },
2744
+ "patches": {
2745
+ "type": "array",
2746
+ "description": "Line-based patches. Can be empty if only updating title, folderId, or position.",
2747
+ "items": {
2748
+ "type": "object",
2749
+ "properties": {
2750
+ "startLine": {
2751
+ "type": "number",
2752
+ "description": "1-based start line."
2753
+ },
2754
+ "endLine": {
2755
+ "type": "number",
2756
+ "description": "1-based end line (inclusive)."
2757
+ },
2758
+ "replacement": {
2759
+ "type": "string",
2760
+ "description": "Replacement text. Empty string to delete lines."
2761
+ }
2762
+ },
2763
+ "required": [
2764
+ "startLine",
2765
+ "endLine",
2766
+ "replacement"
2767
+ ]
2768
+ }
2769
+ }
2770
+ },
2771
+ "required": [
2772
+ "documentId",
2773
+ "versionTimestamp"
2774
+ ]
2775
+ }
2776
+ }
2777
+ }
2778
+ },
2779
+ "responses": {
2780
+ "200": {
2781
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
2782
+ "content": {
2783
+ "application/json": {
2784
+ "schema": {
2785
+ "type": "object",
2786
+ "additionalProperties": true
2787
+ }
2788
+ }
2789
+ }
2790
+ },
2791
+ "400": {
2792
+ "description": "Validation error.",
2793
+ "content": {
2794
+ "application/json": {
2795
+ "schema": {
2796
+ "$ref": "#/components/schemas/ErrorResponse"
2797
+ }
2798
+ }
2799
+ }
2800
+ },
2801
+ "401": {
2802
+ "description": "Missing or invalid credentials.",
2803
+ "content": {
2804
+ "application/json": {
2805
+ "schema": {
2806
+ "$ref": "#/components/schemas/ErrorResponse"
2807
+ }
2808
+ }
2809
+ }
2810
+ },
2811
+ "403": {
2812
+ "description": "Authenticated but lacking the required permission or feature flag.",
2813
+ "content": {
2814
+ "application/json": {
2815
+ "schema": {
2816
+ "$ref": "#/components/schemas/ErrorResponse"
2817
+ }
2818
+ }
2819
+ }
2820
+ },
2821
+ "404": {
2822
+ "description": "Resource not found.",
2823
+ "content": {
2824
+ "application/json": {
2825
+ "schema": {
2826
+ "$ref": "#/components/schemas/ErrorResponse"
2827
+ }
2828
+ }
2829
+ }
2830
+ },
2831
+ "422": {
2832
+ "description": "Body did not match the tool's input schema.",
2833
+ "content": {
2834
+ "application/json": {
2835
+ "schema": {
2836
+ "$ref": "#/components/schemas/ErrorResponse"
2837
+ }
2838
+ }
2839
+ }
2840
+ },
2841
+ "500": {
2842
+ "description": "Server error.",
2843
+ "content": {
2844
+ "application/json": {
2845
+ "schema": {
2846
+ "$ref": "#/components/schemas/ErrorResponse"
2847
+ }
2848
+ }
2849
+ }
2850
+ }
2851
+ }
2852
+ }
2853
+ },
2854
+ "/tools/findAndReplaceTextInDocument": {
2855
+ "post": {
2856
+ "summary": "findAndReplaceTextInDocument",
2857
+ "description": "Find and replace text in a document. Searches for all occurrences and replaces them. Case-sensitive by default. Diagrams/images are automatically protected — only document text is affected. Note: when the `replace` value contains a `<!-- REFERENCE: {...} -->` marker (e.g. inserting a user mention), it round-trips losslessly through the editor and triggers notifications if it adds a new user mention.",
2858
+ "operationId": "findAndReplaceTextInDocument",
2859
+ "tags": [
2860
+ "documents"
2861
+ ],
2862
+ "requestBody": {
2863
+ "required": false,
2864
+ "content": {
2865
+ "application/json": {
2866
+ "schema": {
2867
+ "type": "object",
2868
+ "properties": {
2869
+ "documentId": {
2870
+ "type": "string"
2871
+ },
2872
+ "find": {
2873
+ "type": "string",
2874
+ "description": "Text to search for."
2875
+ },
2876
+ "replace": {
2877
+ "type": "string",
2878
+ "description": "Replacement text. Empty string to delete occurrences."
2879
+ },
2880
+ "caseSensitive": {
2881
+ "type": "boolean",
2882
+ "description": "Case-sensitive matching. Default: true."
2883
+ },
2884
+ "changeSummary": {
2885
+ "type": "string",
2886
+ "description": "Version history summary."
2887
+ }
2888
+ },
2889
+ "required": [
2890
+ "documentId",
2891
+ "find",
2892
+ "replace"
2893
+ ]
2894
+ }
2895
+ }
2896
+ }
2897
+ },
2898
+ "responses": {
2899
+ "200": {
2900
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
2901
+ "content": {
2902
+ "application/json": {
2903
+ "schema": {
2904
+ "type": "object",
2905
+ "additionalProperties": true
2906
+ }
2907
+ }
2908
+ }
2909
+ },
2910
+ "400": {
2911
+ "description": "Validation error.",
2912
+ "content": {
2913
+ "application/json": {
2914
+ "schema": {
2915
+ "$ref": "#/components/schemas/ErrorResponse"
2916
+ }
2917
+ }
2918
+ }
2919
+ },
2920
+ "401": {
2921
+ "description": "Missing or invalid credentials.",
2922
+ "content": {
2923
+ "application/json": {
2924
+ "schema": {
2925
+ "$ref": "#/components/schemas/ErrorResponse"
2926
+ }
2927
+ }
2928
+ }
2929
+ },
2930
+ "403": {
2931
+ "description": "Authenticated but lacking the required permission or feature flag.",
2932
+ "content": {
2933
+ "application/json": {
2934
+ "schema": {
2935
+ "$ref": "#/components/schemas/ErrorResponse"
2936
+ }
2937
+ }
2938
+ }
2939
+ },
2940
+ "404": {
2941
+ "description": "Resource not found.",
2942
+ "content": {
2943
+ "application/json": {
2944
+ "schema": {
2945
+ "$ref": "#/components/schemas/ErrorResponse"
2946
+ }
2947
+ }
2948
+ }
2949
+ },
2950
+ "422": {
2951
+ "description": "Body did not match the tool's input schema.",
2952
+ "content": {
2953
+ "application/json": {
2954
+ "schema": {
2955
+ "$ref": "#/components/schemas/ErrorResponse"
2956
+ }
2957
+ }
2958
+ }
2959
+ },
2960
+ "500": {
2961
+ "description": "Server error.",
2962
+ "content": {
2963
+ "application/json": {
2964
+ "schema": {
2965
+ "$ref": "#/components/schemas/ErrorResponse"
2966
+ }
2967
+ }
2968
+ }
2969
+ }
2970
+ }
2971
+ }
2972
+ },
2973
+ "/tools/getDiagramInDocument": {
2974
+ "post": {
2975
+ "summary": "getDiagramInDocument",
2976
+ "description": "Get a diagram's full details including raw DSL source code. Use diagramId from DIAGRAM_OMITTED markers in getDocument output. Returns diagramCode, type, name, nlDescription, and versionTimestamp.",
2977
+ "operationId": "getDiagramInDocument",
2978
+ "tags": [
2979
+ "diagrams"
2980
+ ],
2981
+ "requestBody": {
2982
+ "required": false,
2983
+ "content": {
2984
+ "application/json": {
2985
+ "schema": {
2986
+ "type": "object",
2987
+ "properties": {
2988
+ "diagramId": {
2989
+ "type": "string",
2990
+ "description": "Diagram ID from DIAGRAM_OMITTED markers."
2991
+ },
2992
+ "fields": {
2993
+ "type": "array",
2994
+ "items": {
2995
+ "type": "string"
2996
+ },
2997
+ "description": "Field projection. Valid fields: diagramId, documentId, type, name, diagramCode, nlDescription, colorPlan, renderStatus, renderError, createdAt, updatedAt, versionTimestamp."
2998
+ }
2999
+ },
3000
+ "required": [
3001
+ "diagramId"
3002
+ ]
3003
+ }
3004
+ }
3005
+ }
3006
+ },
3007
+ "responses": {
3008
+ "200": {
3009
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3010
+ "content": {
3011
+ "application/json": {
3012
+ "schema": {
3013
+ "type": "object",
3014
+ "additionalProperties": true
3015
+ }
3016
+ }
3017
+ }
3018
+ },
3019
+ "400": {
3020
+ "description": "Validation error.",
3021
+ "content": {
3022
+ "application/json": {
3023
+ "schema": {
3024
+ "$ref": "#/components/schemas/ErrorResponse"
3025
+ }
3026
+ }
3027
+ }
3028
+ },
3029
+ "401": {
3030
+ "description": "Missing or invalid credentials.",
3031
+ "content": {
3032
+ "application/json": {
3033
+ "schema": {
3034
+ "$ref": "#/components/schemas/ErrorResponse"
3035
+ }
3036
+ }
3037
+ }
3038
+ },
3039
+ "403": {
3040
+ "description": "Authenticated but lacking the required permission or feature flag.",
3041
+ "content": {
3042
+ "application/json": {
3043
+ "schema": {
3044
+ "$ref": "#/components/schemas/ErrorResponse"
3045
+ }
3046
+ }
3047
+ }
3048
+ },
3049
+ "404": {
3050
+ "description": "Resource not found.",
3051
+ "content": {
3052
+ "application/json": {
3053
+ "schema": {
3054
+ "$ref": "#/components/schemas/ErrorResponse"
3055
+ }
3056
+ }
3057
+ }
3058
+ },
3059
+ "422": {
3060
+ "description": "Body did not match the tool's input schema.",
3061
+ "content": {
3062
+ "application/json": {
3063
+ "schema": {
3064
+ "$ref": "#/components/schemas/ErrorResponse"
3065
+ }
3066
+ }
3067
+ }
3068
+ },
3069
+ "500": {
3070
+ "description": "Server error.",
3071
+ "content": {
3072
+ "application/json": {
3073
+ "schema": {
3074
+ "$ref": "#/components/schemas/ErrorResponse"
3075
+ }
3076
+ }
3077
+ }
3078
+ }
3079
+ }
3080
+ }
3081
+ },
3082
+ "/tools/insertDiagramInDocument": {
3083
+ "post": {
3084
+ "summary": "insertDiagramInDocument",
3085
+ "description": "Insert a new diagram into a document. Call listDiagramTypes to find your type, then getDiagramTypeGuide for DSL syntax before writing diagramCode. Always set prompt + nlDescription to describe what the diagram shows (they are its saved description) and keep them accurate. After inserting, VERIFY the render — set returnImage:true (or call getDiagramImage) to actually SEE it — and if it is wrong or ugly, correct it with updateDiagramInDocument (provide the full updated diagramCode).",
3086
+ "operationId": "insertDiagramInDocument",
3087
+ "tags": [
3088
+ "diagrams"
3089
+ ],
3090
+ "requestBody": {
3091
+ "required": false,
3092
+ "content": {
3093
+ "application/json": {
3094
+ "schema": {
3095
+ "type": "object",
3096
+ "properties": {
3097
+ "documentId": {
3098
+ "type": "string"
3099
+ },
3100
+ "documentVersionTimestamp": {
3101
+ "type": "number",
3102
+ "description": "Version timestamp from getDocument() for optimistic locking."
3103
+ },
3104
+ "type": {
3105
+ "type": "string",
3106
+ "description": "Diagram type (e.g. mermaid, plantuml, bpmn, d2). Call listDiagramTypes for all types."
3107
+ },
3108
+ "diagramCode": {
3109
+ "type": "string",
3110
+ "description": "Diagram DSL code. Call getDiagramTypeGuide for syntax."
3111
+ },
3112
+ "prompt": {
3113
+ "type": "string",
3114
+ "description": "Short description of what the diagram shows (1-2 sentences)."
3115
+ },
3116
+ "nlDescription": {
3117
+ "type": "string",
3118
+ "description": "Extended description of the diagram (2-4 sentences)."
3119
+ },
3120
+ "align": {
3121
+ "type": "string",
3122
+ "description": "Alignment.",
3123
+ "enum": [
3124
+ "left",
3125
+ "center",
3126
+ "right"
3127
+ ]
3128
+ },
3129
+ "caption": {
3130
+ "type": "string",
3131
+ "description": "Caption below the diagram."
3132
+ },
3133
+ "afterLine": {
3134
+ "type": "number",
3135
+ "description": "Insert after this line number (1-based)."
3136
+ },
3137
+ "colorPlan": {
3138
+ "type": "object",
3139
+ "description": "BPMN only. Color plan: { byElementId: { ElementId: SwatchName } }.",
3140
+ "properties": {
3141
+ "byElementId": {
3142
+ "type": "object",
3143
+ "description": "Map of element IDs to color swatch names.",
3144
+ "additionalProperties": {
3145
+ "type": "string"
3146
+ }
3147
+ }
3148
+ },
3149
+ "required": [
3150
+ "byElementId"
3151
+ ]
3152
+ },
3153
+ "returnImage": {
3154
+ "type": "boolean",
3155
+ "description": "If true, also render the inserted diagram and return it as an image inline (one-call insert-and-get-image). Defaults false."
3156
+ },
3157
+ "imageFormat": {
3158
+ "type": "string",
3159
+ "enum": [
3160
+ "png",
3161
+ "jpeg",
3162
+ "svg"
3163
+ ],
3164
+ "description": "Image format when returnImage:true (default png)."
3165
+ },
3166
+ "imageScale": {
3167
+ "type": "number",
3168
+ "enum": [
3169
+ 1,
3170
+ 2,
3171
+ 3
3172
+ ],
3173
+ "description": "Raster resolution 1x/2x/3x when returnImage:true (default 2)."
3174
+ },
3175
+ "imageBackground": {
3176
+ "type": "string",
3177
+ "description": "Background for the returned png/jpeg (e.g. '#ffffff' or 'transparent')."
3178
+ }
3179
+ },
3180
+ "required": [
3181
+ "documentId",
3182
+ "documentVersionTimestamp",
3183
+ "type",
3184
+ "diagramCode",
3185
+ "prompt",
3186
+ "nlDescription",
3187
+ "align",
3188
+ "caption",
3189
+ "afterLine"
3190
+ ]
3191
+ }
3192
+ }
3193
+ }
3194
+ },
3195
+ "responses": {
3196
+ "200": {
3197
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3198
+ "content": {
3199
+ "application/json": {
3200
+ "schema": {
3201
+ "type": "object",
3202
+ "additionalProperties": true
3203
+ }
3204
+ }
3205
+ }
3206
+ },
3207
+ "400": {
3208
+ "description": "Validation error.",
3209
+ "content": {
3210
+ "application/json": {
3211
+ "schema": {
3212
+ "$ref": "#/components/schemas/ErrorResponse"
3213
+ }
3214
+ }
3215
+ }
3216
+ },
3217
+ "401": {
3218
+ "description": "Missing or invalid credentials.",
3219
+ "content": {
3220
+ "application/json": {
3221
+ "schema": {
3222
+ "$ref": "#/components/schemas/ErrorResponse"
3223
+ }
3224
+ }
3225
+ }
3226
+ },
3227
+ "403": {
3228
+ "description": "Authenticated but lacking the required permission or feature flag.",
3229
+ "content": {
3230
+ "application/json": {
3231
+ "schema": {
3232
+ "$ref": "#/components/schemas/ErrorResponse"
3233
+ }
3234
+ }
3235
+ }
3236
+ },
3237
+ "404": {
3238
+ "description": "Resource not found.",
3239
+ "content": {
3240
+ "application/json": {
3241
+ "schema": {
3242
+ "$ref": "#/components/schemas/ErrorResponse"
3243
+ }
3244
+ }
3245
+ }
3246
+ },
3247
+ "422": {
3248
+ "description": "Body did not match the tool's input schema.",
3249
+ "content": {
3250
+ "application/json": {
3251
+ "schema": {
3252
+ "$ref": "#/components/schemas/ErrorResponse"
3253
+ }
3254
+ }
3255
+ }
3256
+ },
3257
+ "500": {
3258
+ "description": "Server error.",
3259
+ "content": {
3260
+ "application/json": {
3261
+ "schema": {
3262
+ "$ref": "#/components/schemas/ErrorResponse"
3263
+ }
3264
+ }
3265
+ }
3266
+ }
3267
+ }
3268
+ }
3269
+ },
3270
+ "/tools/updateDiagramInDocument": {
3271
+ "post": {
3272
+ "summary": "updateDiagramInDocument",
3273
+ "description": "Update a diagram's code, description, or properties. Call getDiagramTypeGuide for DSL syntax. Requires documentVersionTimestamp from getDocument. IMPORTANT: To change what the diagram visually shows, you MUST provide diagramCode with the full updated DSL source. The prompt and nlDescription fields are metadata only and do NOT change the rendered diagram. After updating, re-render with getDiagramImage to confirm it now looks right (iterate if not), and keep prompt/nlDescription in step with what the diagram now shows.",
3274
+ "operationId": "updateDiagramInDocument",
3275
+ "tags": [
3276
+ "diagrams"
3277
+ ],
3278
+ "requestBody": {
3279
+ "required": false,
3280
+ "content": {
3281
+ "application/json": {
3282
+ "schema": {
3283
+ "type": "object",
3284
+ "properties": {
3285
+ "diagramId": {
3286
+ "type": "string",
3287
+ "description": "Diagram ID from DIAGRAM_OMITTED markers."
3288
+ },
3289
+ "diagramCode": {
3290
+ "type": "string",
3291
+ "description": "New diagram DSL source code. REQUIRED to change what the diagram visually renders. Call getDiagramTypeGuide for syntax. Must provide the COMPLETE updated DSL, not just the changed parts."
3292
+ },
3293
+ "prompt": {
3294
+ "type": "string",
3295
+ "description": "New short description (metadata only — does NOT change the rendered diagram)."
3296
+ },
3297
+ "nlDescription": {
3298
+ "type": "string",
3299
+ "description": "New extended description (metadata only — does NOT change the rendered diagram)."
3300
+ },
3301
+ "align": {
3302
+ "type": "string",
3303
+ "description": "Alignment.",
3304
+ "enum": [
3305
+ "left",
3306
+ "center",
3307
+ "right"
3308
+ ]
3309
+ },
3310
+ "caption": {
3311
+ "type": "string",
3312
+ "description": "New caption."
3313
+ },
3314
+ "colorPlan": {
3315
+ "type": "object",
3316
+ "description": "BPMN only. Updated color plan. Set to null to remove.",
3317
+ "properties": {
3318
+ "byElementId": {
3319
+ "type": "object",
3320
+ "description": "Map of element IDs to color swatch names.",
3321
+ "additionalProperties": {
3322
+ "type": "string"
3323
+ }
3324
+ }
3325
+ },
3326
+ "required": [
3327
+ "byElementId"
3328
+ ]
3329
+ },
3330
+ "documentVersionTimestamp": {
3331
+ "type": "number",
3332
+ "description": "Version timestamp from getDocument() for optimistic locking."
3333
+ }
3334
+ },
3335
+ "required": [
3336
+ "diagramId",
3337
+ "documentVersionTimestamp"
3338
+ ]
3339
+ }
3340
+ }
3341
+ }
3342
+ },
3343
+ "responses": {
3344
+ "200": {
3345
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3346
+ "content": {
3347
+ "application/json": {
3348
+ "schema": {
3349
+ "type": "object",
3350
+ "additionalProperties": true
3351
+ }
3352
+ }
3353
+ }
3354
+ },
3355
+ "400": {
3356
+ "description": "Validation error.",
3357
+ "content": {
3358
+ "application/json": {
3359
+ "schema": {
3360
+ "$ref": "#/components/schemas/ErrorResponse"
3361
+ }
3362
+ }
3363
+ }
3364
+ },
3365
+ "401": {
3366
+ "description": "Missing or invalid credentials.",
3367
+ "content": {
3368
+ "application/json": {
3369
+ "schema": {
3370
+ "$ref": "#/components/schemas/ErrorResponse"
3371
+ }
3372
+ }
3373
+ }
3374
+ },
3375
+ "403": {
3376
+ "description": "Authenticated but lacking the required permission or feature flag.",
3377
+ "content": {
3378
+ "application/json": {
3379
+ "schema": {
3380
+ "$ref": "#/components/schemas/ErrorResponse"
3381
+ }
3382
+ }
3383
+ }
3384
+ },
3385
+ "404": {
3386
+ "description": "Resource not found.",
3387
+ "content": {
3388
+ "application/json": {
3389
+ "schema": {
3390
+ "$ref": "#/components/schemas/ErrorResponse"
3391
+ }
3392
+ }
3393
+ }
3394
+ },
3395
+ "422": {
3396
+ "description": "Body did not match the tool's input schema.",
3397
+ "content": {
3398
+ "application/json": {
3399
+ "schema": {
3400
+ "$ref": "#/components/schemas/ErrorResponse"
3401
+ }
3402
+ }
3403
+ }
3404
+ },
3405
+ "500": {
3406
+ "description": "Server error.",
3407
+ "content": {
3408
+ "application/json": {
3409
+ "schema": {
3410
+ "$ref": "#/components/schemas/ErrorResponse"
3411
+ }
3412
+ }
3413
+ }
3414
+ }
3415
+ }
3416
+ }
3417
+ },
3418
+ "/tools/deleteDiagramInDocument": {
3419
+ "post": {
3420
+ "summary": "deleteDiagramInDocument",
3421
+ "description": "Delete a diagram from a document.",
3422
+ "operationId": "deleteDiagramInDocument",
3423
+ "tags": [
3424
+ "diagrams"
3425
+ ],
3426
+ "requestBody": {
3427
+ "required": false,
3428
+ "content": {
3429
+ "application/json": {
3430
+ "schema": {
3431
+ "type": "object",
3432
+ "properties": {
3433
+ "diagramId": {
3434
+ "type": "string",
3435
+ "description": "Diagram ID from DIAGRAM_OMITTED markers."
3436
+ }
3437
+ },
3438
+ "required": [
3439
+ "diagramId"
3440
+ ]
3441
+ }
3442
+ }
3443
+ }
3444
+ },
3445
+ "responses": {
3446
+ "200": {
3447
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3448
+ "content": {
3449
+ "application/json": {
3450
+ "schema": {
3451
+ "type": "object",
3452
+ "additionalProperties": true
3453
+ }
3454
+ }
3455
+ }
3456
+ },
3457
+ "400": {
3458
+ "description": "Validation error.",
3459
+ "content": {
3460
+ "application/json": {
3461
+ "schema": {
3462
+ "$ref": "#/components/schemas/ErrorResponse"
3463
+ }
3464
+ }
3465
+ }
3466
+ },
3467
+ "401": {
3468
+ "description": "Missing or invalid credentials.",
3469
+ "content": {
3470
+ "application/json": {
3471
+ "schema": {
3472
+ "$ref": "#/components/schemas/ErrorResponse"
3473
+ }
3474
+ }
3475
+ }
3476
+ },
3477
+ "403": {
3478
+ "description": "Authenticated but lacking the required permission or feature flag.",
3479
+ "content": {
3480
+ "application/json": {
3481
+ "schema": {
3482
+ "$ref": "#/components/schemas/ErrorResponse"
3483
+ }
3484
+ }
3485
+ }
3486
+ },
3487
+ "404": {
3488
+ "description": "Resource not found.",
3489
+ "content": {
3490
+ "application/json": {
3491
+ "schema": {
3492
+ "$ref": "#/components/schemas/ErrorResponse"
3493
+ }
3494
+ }
3495
+ }
3496
+ },
3497
+ "422": {
3498
+ "description": "Body did not match the tool's input schema.",
3499
+ "content": {
3500
+ "application/json": {
3501
+ "schema": {
3502
+ "$ref": "#/components/schemas/ErrorResponse"
3503
+ }
3504
+ }
3505
+ }
3506
+ },
3507
+ "500": {
3508
+ "description": "Server error.",
3509
+ "content": {
3510
+ "application/json": {
3511
+ "schema": {
3512
+ "$ref": "#/components/schemas/ErrorResponse"
3513
+ }
3514
+ }
3515
+ }
3516
+ }
3517
+ }
3518
+ }
3519
+ },
3520
+ "/tools/deleteDocument": {
3521
+ "post": {
3522
+ "summary": "deleteDocument",
3523
+ "description": "Delete a document.",
3524
+ "operationId": "deleteDocument",
3525
+ "tags": [
3526
+ "documents"
3527
+ ],
3528
+ "requestBody": {
3529
+ "required": false,
3530
+ "content": {
3531
+ "application/json": {
3532
+ "schema": {
3533
+ "type": "object",
3534
+ "properties": {
3535
+ "documentId": {
3536
+ "type": "string"
3537
+ }
3538
+ },
3539
+ "required": [
3540
+ "documentId"
3541
+ ]
3542
+ }
3543
+ }
3544
+ }
3545
+ },
3546
+ "responses": {
3547
+ "200": {
3548
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3549
+ "content": {
3550
+ "application/json": {
3551
+ "schema": {
3552
+ "type": "object",
3553
+ "additionalProperties": true
3554
+ }
3555
+ }
3556
+ }
3557
+ },
3558
+ "400": {
3559
+ "description": "Validation error.",
3560
+ "content": {
3561
+ "application/json": {
3562
+ "schema": {
3563
+ "$ref": "#/components/schemas/ErrorResponse"
3564
+ }
3565
+ }
3566
+ }
3567
+ },
3568
+ "401": {
3569
+ "description": "Missing or invalid credentials.",
3570
+ "content": {
3571
+ "application/json": {
3572
+ "schema": {
3573
+ "$ref": "#/components/schemas/ErrorResponse"
3574
+ }
3575
+ }
3576
+ }
3577
+ },
3578
+ "403": {
3579
+ "description": "Authenticated but lacking the required permission or feature flag.",
3580
+ "content": {
3581
+ "application/json": {
3582
+ "schema": {
3583
+ "$ref": "#/components/schemas/ErrorResponse"
3584
+ }
3585
+ }
3586
+ }
3587
+ },
3588
+ "404": {
3589
+ "description": "Resource not found.",
3590
+ "content": {
3591
+ "application/json": {
3592
+ "schema": {
3593
+ "$ref": "#/components/schemas/ErrorResponse"
3594
+ }
3595
+ }
3596
+ }
3597
+ },
3598
+ "422": {
3599
+ "description": "Body did not match the tool's input schema.",
3600
+ "content": {
3601
+ "application/json": {
3602
+ "schema": {
3603
+ "$ref": "#/components/schemas/ErrorResponse"
3604
+ }
3605
+ }
3606
+ }
3607
+ },
3608
+ "500": {
3609
+ "description": "Server error.",
3610
+ "content": {
3611
+ "application/json": {
3612
+ "schema": {
3613
+ "$ref": "#/components/schemas/ErrorResponse"
3614
+ }
3615
+ }
3616
+ }
3617
+ }
3618
+ }
3619
+ }
3620
+ },
3621
+ "/tools/getWhiteboardGuide": {
3622
+ "post": {
3623
+ "summary": "getWhiteboardGuide",
3624
+ "description": "Get the Stable Baseline whiteboarding guide (Markdown): when to use stencils vs architecture icons vs code/BPMN diagrams vs plain shapes vs real images vs frames/presentations, how to lay out and verify a board, and how to edit a large board safely (patch by id, never replace). Call before authoring a non-trivial whiteboard.",
3625
+ "operationId": "getWhiteboardGuide",
3626
+ "tags": [
3627
+ "whiteboards"
3628
+ ],
3629
+ "requestBody": {
3630
+ "required": false,
3631
+ "content": {
3632
+ "application/json": {
3633
+ "schema": {
3634
+ "type": "object",
3635
+ "properties": {}
3636
+ }
3637
+ }
3638
+ }
3639
+ },
3640
+ "responses": {
3641
+ "200": {
3642
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3643
+ "content": {
3644
+ "application/json": {
3645
+ "schema": {
3646
+ "type": "object",
3647
+ "additionalProperties": true
3648
+ }
3649
+ }
3650
+ }
3651
+ },
3652
+ "400": {
3653
+ "description": "Validation error.",
3654
+ "content": {
3655
+ "application/json": {
3656
+ "schema": {
3657
+ "$ref": "#/components/schemas/ErrorResponse"
3658
+ }
3659
+ }
3660
+ }
3661
+ },
3662
+ "401": {
3663
+ "description": "Missing or invalid credentials.",
3664
+ "content": {
3665
+ "application/json": {
3666
+ "schema": {
3667
+ "$ref": "#/components/schemas/ErrorResponse"
3668
+ }
3669
+ }
3670
+ }
3671
+ },
3672
+ "403": {
3673
+ "description": "Authenticated but lacking the required permission or feature flag.",
3674
+ "content": {
3675
+ "application/json": {
3676
+ "schema": {
3677
+ "$ref": "#/components/schemas/ErrorResponse"
3678
+ }
3679
+ }
3680
+ }
3681
+ },
3682
+ "404": {
3683
+ "description": "Resource not found.",
3684
+ "content": {
3685
+ "application/json": {
3686
+ "schema": {
3687
+ "$ref": "#/components/schemas/ErrorResponse"
3688
+ }
3689
+ }
3690
+ }
3691
+ },
3692
+ "422": {
3693
+ "description": "Body did not match the tool's input schema.",
3694
+ "content": {
3695
+ "application/json": {
3696
+ "schema": {
3697
+ "$ref": "#/components/schemas/ErrorResponse"
3698
+ }
3699
+ }
3700
+ }
3701
+ },
3702
+ "500": {
3703
+ "description": "Server error.",
3704
+ "content": {
3705
+ "application/json": {
3706
+ "schema": {
3707
+ "$ref": "#/components/schemas/ErrorResponse"
3708
+ }
3709
+ }
3710
+ }
3711
+ }
3712
+ }
3713
+ }
3714
+ },
3715
+ "/tools/createWhiteboard": {
3716
+ "post": {
3717
+ "summary": "createWhiteboard",
3718
+ "description": "Create a whiteboard — an infinite Excalidraw canvas. A whiteboard is a hidden document (it won't appear in listDocuments) that hosts a single freeform canvas, and opens in the immersive whiteboard editor in the app. Returns documentId + diagramId. Author shapes afterwards with addWhiteboardElements (high-level specs) or updateWhiteboardScene. For anything beyond a blank board, call getWhiteboardGuide first to plan the layout (stencils vs architecture icons vs code/BPMN diagrams vs plain shapes), and render with getWhiteboardImage to verify as you go.",
3719
+ "operationId": "createWhiteboard",
3720
+ "tags": [
3721
+ "whiteboards"
3722
+ ],
3723
+ "requestBody": {
3724
+ "required": false,
3725
+ "content": {
3726
+ "application/json": {
3727
+ "schema": {
3728
+ "type": "object",
3729
+ "properties": {
3730
+ "projectId": {
3731
+ "type": "string"
3732
+ },
3733
+ "title": {
3734
+ "type": "string",
3735
+ "description": "Whiteboard title. Defaults to 'Untitled whiteboard'."
3736
+ },
3737
+ "folderId": {
3738
+ "type": "string",
3739
+ "description": "Optional folder to file the whiteboard under."
3740
+ }
3741
+ },
3742
+ "required": [
3743
+ "projectId"
3744
+ ]
3745
+ }
3746
+ }
3747
+ }
3748
+ },
3749
+ "responses": {
3750
+ "200": {
3751
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3752
+ "content": {
3753
+ "application/json": {
3754
+ "schema": {
3755
+ "type": "object",
3756
+ "additionalProperties": true
3757
+ }
3758
+ }
3759
+ }
3760
+ },
3761
+ "400": {
3762
+ "description": "Validation error.",
3763
+ "content": {
3764
+ "application/json": {
3765
+ "schema": {
3766
+ "$ref": "#/components/schemas/ErrorResponse"
3767
+ }
3768
+ }
3769
+ }
3770
+ },
3771
+ "401": {
3772
+ "description": "Missing or invalid credentials.",
3773
+ "content": {
3774
+ "application/json": {
3775
+ "schema": {
3776
+ "$ref": "#/components/schemas/ErrorResponse"
3777
+ }
3778
+ }
3779
+ }
3780
+ },
3781
+ "403": {
3782
+ "description": "Authenticated but lacking the required permission or feature flag.",
3783
+ "content": {
3784
+ "application/json": {
3785
+ "schema": {
3786
+ "$ref": "#/components/schemas/ErrorResponse"
3787
+ }
3788
+ }
3789
+ }
3790
+ },
3791
+ "404": {
3792
+ "description": "Resource not found.",
3793
+ "content": {
3794
+ "application/json": {
3795
+ "schema": {
3796
+ "$ref": "#/components/schemas/ErrorResponse"
3797
+ }
3798
+ }
3799
+ }
3800
+ },
3801
+ "422": {
3802
+ "description": "Body did not match the tool's input schema.",
3803
+ "content": {
3804
+ "application/json": {
3805
+ "schema": {
3806
+ "$ref": "#/components/schemas/ErrorResponse"
3807
+ }
3808
+ }
3809
+ }
3810
+ },
3811
+ "500": {
3812
+ "description": "Server error.",
3813
+ "content": {
3814
+ "application/json": {
3815
+ "schema": {
3816
+ "$ref": "#/components/schemas/ErrorResponse"
3817
+ }
3818
+ }
3819
+ }
3820
+ }
3821
+ }
3822
+ }
3823
+ },
3824
+ "/tools/listWhiteboards": {
3825
+ "post": {
3826
+ "summary": "listWhiteboards",
3827
+ "description": "List the whiteboards in a project (hidden whiteboard-kind documents). Returns documentId, diagramId, title and timestamps for each.",
3828
+ "operationId": "listWhiteboards",
3829
+ "tags": [
3830
+ "whiteboards"
3831
+ ],
3832
+ "requestBody": {
3833
+ "required": false,
3834
+ "content": {
3835
+ "application/json": {
3836
+ "schema": {
3837
+ "type": "object",
3838
+ "properties": {
3839
+ "projectId": {
3840
+ "type": "string"
3841
+ }
3842
+ },
3843
+ "required": [
3844
+ "projectId"
3845
+ ]
3846
+ }
3847
+ }
3848
+ }
3849
+ },
3850
+ "responses": {
3851
+ "200": {
3852
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3853
+ "content": {
3854
+ "application/json": {
3855
+ "schema": {
3856
+ "type": "object",
3857
+ "additionalProperties": true
3858
+ }
3859
+ }
3860
+ }
3861
+ },
3862
+ "400": {
3863
+ "description": "Validation error.",
3864
+ "content": {
3865
+ "application/json": {
3866
+ "schema": {
3867
+ "$ref": "#/components/schemas/ErrorResponse"
3868
+ }
3869
+ }
3870
+ }
3871
+ },
3872
+ "401": {
3873
+ "description": "Missing or invalid credentials.",
3874
+ "content": {
3875
+ "application/json": {
3876
+ "schema": {
3877
+ "$ref": "#/components/schemas/ErrorResponse"
3878
+ }
3879
+ }
3880
+ }
3881
+ },
3882
+ "403": {
3883
+ "description": "Authenticated but lacking the required permission or feature flag.",
3884
+ "content": {
3885
+ "application/json": {
3886
+ "schema": {
3887
+ "$ref": "#/components/schemas/ErrorResponse"
3888
+ }
3889
+ }
3890
+ }
3891
+ },
3892
+ "404": {
3893
+ "description": "Resource not found.",
3894
+ "content": {
3895
+ "application/json": {
3896
+ "schema": {
3897
+ "$ref": "#/components/schemas/ErrorResponse"
3898
+ }
3899
+ }
3900
+ }
3901
+ },
3902
+ "422": {
3903
+ "description": "Body did not match the tool's input schema.",
3904
+ "content": {
3905
+ "application/json": {
3906
+ "schema": {
3907
+ "$ref": "#/components/schemas/ErrorResponse"
3908
+ }
3909
+ }
3910
+ }
3911
+ },
3912
+ "500": {
3913
+ "description": "Server error.",
3914
+ "content": {
3915
+ "application/json": {
3916
+ "schema": {
3917
+ "$ref": "#/components/schemas/ErrorResponse"
3918
+ }
3919
+ }
3920
+ }
3921
+ }
3922
+ }
3923
+ }
3924
+ },
3925
+ "/tools/getWhiteboard": {
3926
+ "post": {
3927
+ "summary": "getWhiteboard",
3928
+ "description": "Read a whiteboard: its metadata plus a summary of the canvas (element count, element types, and text labels on the board). Pass includeElements=true to also return the full Excalidraw scene ({elements, appState, files}) — needed if you intend to modify it and send it back via updateWhiteboardScene. FOR BEST RESULTS, also call getWhiteboardImage to render the board to an image and actually SEE it: the visual layout (positions, spacing, overlaps, colours, how shapes connect) is far easier to understand from the rendered picture than from the element list, so view it first to truly understand the board and to propose or verify edits accurately.",
3929
+ "operationId": "getWhiteboard",
3930
+ "tags": [
3931
+ "whiteboards"
3932
+ ],
3933
+ "requestBody": {
3934
+ "required": false,
3935
+ "content": {
3936
+ "application/json": {
3937
+ "schema": {
3938
+ "type": "object",
3939
+ "properties": {
3940
+ "documentId": {
3941
+ "type": "string"
3942
+ },
3943
+ "includeElements": {
3944
+ "type": "boolean",
3945
+ "description": "When true, returns the full Excalidraw scene so it can be modified and written back."
3946
+ }
3947
+ },
3948
+ "required": [
3949
+ "documentId"
3950
+ ]
3951
+ }
3952
+ }
3953
+ }
3954
+ },
3955
+ "responses": {
3956
+ "200": {
3957
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
3958
+ "content": {
3959
+ "application/json": {
3960
+ "schema": {
3961
+ "type": "object",
3962
+ "additionalProperties": true
3963
+ }
3964
+ }
3965
+ }
3966
+ },
3967
+ "400": {
3968
+ "description": "Validation error.",
3969
+ "content": {
3970
+ "application/json": {
3971
+ "schema": {
3972
+ "$ref": "#/components/schemas/ErrorResponse"
3973
+ }
3974
+ }
3975
+ }
3976
+ },
3977
+ "401": {
3978
+ "description": "Missing or invalid credentials.",
3979
+ "content": {
3980
+ "application/json": {
3981
+ "schema": {
3982
+ "$ref": "#/components/schemas/ErrorResponse"
3983
+ }
3984
+ }
3985
+ }
3986
+ },
3987
+ "403": {
3988
+ "description": "Authenticated but lacking the required permission or feature flag.",
3989
+ "content": {
3990
+ "application/json": {
3991
+ "schema": {
3992
+ "$ref": "#/components/schemas/ErrorResponse"
3993
+ }
3994
+ }
3995
+ }
3996
+ },
3997
+ "404": {
3998
+ "description": "Resource not found.",
3999
+ "content": {
4000
+ "application/json": {
4001
+ "schema": {
4002
+ "$ref": "#/components/schemas/ErrorResponse"
4003
+ }
4004
+ }
4005
+ }
4006
+ },
4007
+ "422": {
4008
+ "description": "Body did not match the tool's input schema.",
4009
+ "content": {
4010
+ "application/json": {
4011
+ "schema": {
4012
+ "$ref": "#/components/schemas/ErrorResponse"
4013
+ }
4014
+ }
4015
+ }
4016
+ },
4017
+ "500": {
4018
+ "description": "Server error.",
4019
+ "content": {
4020
+ "application/json": {
4021
+ "schema": {
4022
+ "$ref": "#/components/schemas/ErrorResponse"
4023
+ }
4024
+ }
4025
+ }
4026
+ }
4027
+ }
4028
+ }
4029
+ },
4030
+ "/tools/updateWhiteboardScene": {
4031
+ "post": {
4032
+ "summary": "updateWhiteboardScene",
4033
+ "description": "Edit elements on a whiteboard's canvas WITHOUT dropping the rest of the scene. A board may hold many diagrams/elements, so prefer surgical edits: mode='patch' (DEFAULT) shallow-merges each incoming object into the existing element with the same `id` (send just {id, backgroundColor:'blue'} to recolour one box, or {id, x, y} to move one) and appends any elements whose id is new/absent — everything else is left untouched. `deleteIds` removes specific elements by id. mode='append' only adds. mode='replace' overwrites the ENTIRE scene (use ONLY when intentionally rewriting the whole board). To author NEW shapes/connectors from a high-level spec, prefer addWhiteboardElements — and prefer library stencils / sticky notes / architecture icons over plain rectangles wherever a standard form fits (sticky notes, kanban/scrum, flowcharts, UML/ER, BPMN, org charts, wireframes). Optional appState/files are merged in. PROCESS: for a non-trivial edit call getWhiteboardGuide FIRST; after editing, ALWAYS call getWhiteboardImage to confirm the board still looks right (layout, labels, overlaps), and patch again if it doesn't.",
4034
+ "operationId": "updateWhiteboardScene",
4035
+ "tags": [
4036
+ "whiteboards"
4037
+ ],
4038
+ "requestBody": {
4039
+ "required": false,
4040
+ "content": {
4041
+ "application/json": {
4042
+ "schema": {
4043
+ "type": "object",
4044
+ "properties": {
4045
+ "documentId": {
4046
+ "type": "string"
4047
+ },
4048
+ "elements": {
4049
+ "type": "array",
4050
+ "description": "Elements to write. For mode 'patch', each may be a partial { id, ...changedFields } merged into the matching element by id; full Excalidraw elements for 'replace'/'append' (or new ids in 'patch').",
4051
+ "items": {
4052
+ "type": "object"
4053
+ }
4054
+ },
4055
+ "mode": {
4056
+ "type": "string",
4057
+ "enum": [
4058
+ "patch",
4059
+ "append",
4060
+ "replace"
4061
+ ],
4062
+ "description": "patch (DEFAULT — merge by id, keep the rest), append (add only), or replace (overwrite the whole scene)."
4063
+ },
4064
+ "deleteIds": {
4065
+ "type": "array",
4066
+ "items": {
4067
+ "type": "string"
4068
+ },
4069
+ "description": "Element ids to remove from the scene."
4070
+ },
4071
+ "appState": {
4072
+ "type": "object",
4073
+ "description": "Optional Excalidraw appState fields to merge (e.g. viewBackgroundColor)."
4074
+ },
4075
+ "files": {
4076
+ "type": "object",
4077
+ "description": "Optional Excalidraw BinaryFiles map (for embedded images), merged in."
4078
+ },
4079
+ "versionTimestamp": {
4080
+ "type": "number",
4081
+ "description": "Optional optimistic-locking token from getWhiteboard. Only used for mode 'replace': if the board changed since you read it, the replace is rejected so you don't overwrite a collaborator's newer edits — re-read with getWhiteboard and retry. Not needed for patch/append, which automatically merge onto the latest scene."
4082
+ }
4083
+ },
4084
+ "required": [
4085
+ "documentId"
4086
+ ]
4087
+ }
4088
+ }
4089
+ }
4090
+ },
4091
+ "responses": {
4092
+ "200": {
4093
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
4094
+ "content": {
4095
+ "application/json": {
4096
+ "schema": {
4097
+ "type": "object",
4098
+ "additionalProperties": true
4099
+ }
4100
+ }
4101
+ }
4102
+ },
4103
+ "400": {
4104
+ "description": "Validation error.",
4105
+ "content": {
4106
+ "application/json": {
4107
+ "schema": {
4108
+ "$ref": "#/components/schemas/ErrorResponse"
4109
+ }
4110
+ }
4111
+ }
4112
+ },
4113
+ "401": {
4114
+ "description": "Missing or invalid credentials.",
4115
+ "content": {
4116
+ "application/json": {
4117
+ "schema": {
4118
+ "$ref": "#/components/schemas/ErrorResponse"
4119
+ }
4120
+ }
4121
+ }
4122
+ },
4123
+ "403": {
4124
+ "description": "Authenticated but lacking the required permission or feature flag.",
4125
+ "content": {
4126
+ "application/json": {
4127
+ "schema": {
4128
+ "$ref": "#/components/schemas/ErrorResponse"
4129
+ }
4130
+ }
4131
+ }
4132
+ },
4133
+ "404": {
4134
+ "description": "Resource not found.",
4135
+ "content": {
4136
+ "application/json": {
4137
+ "schema": {
4138
+ "$ref": "#/components/schemas/ErrorResponse"
4139
+ }
4140
+ }
4141
+ }
4142
+ },
4143
+ "422": {
4144
+ "description": "Body did not match the tool's input schema.",
4145
+ "content": {
4146
+ "application/json": {
4147
+ "schema": {
4148
+ "$ref": "#/components/schemas/ErrorResponse"
4149
+ }
4150
+ }
4151
+ }
4152
+ },
4153
+ "500": {
4154
+ "description": "Server error.",
4155
+ "content": {
4156
+ "application/json": {
4157
+ "schema": {
4158
+ "$ref": "#/components/schemas/ErrorResponse"
4159
+ }
4160
+ }
4161
+ }
4162
+ }
4163
+ }
4164
+ }
4165
+ },
4166
+ "/tools/addWhiteboardElements": {
4167
+ "post": {
4168
+ "summary": "addWhiteboardElements",
4169
+ "description": "Author shapes onto a whiteboard from high-level specs (you do NOT need the full Excalidraw element schema). Appends to the canvas. PREFER THE RICHEST FORM THAT FITS, not plain rectangles: for a sticky/post-it note use { type:'sticky', text, backgroundColor } (a first-class note with an auto-fitting bound label — there is NO sticky-note stencil; OMIT x/y and it is auto-placed in clear space below existing content, so it doesn't land on top of the current drawing); for kanban/scrum/story boards, flowcharts, UML/ER, BPMN, org charts, wireframes/mockups, charts or people use a LIBRARY STENCIL in ONE call — { type:'stencil', stencil:'<name e.g. decision>', x, y } fuzzy-matches by name with no prior listWhiteboardStencils call (pass width/height to SCALE the whole stencil and text to fill its single label); for cloud/software-architecture use ICONS — { type:'image', iconPath:'dev/docker.svg', x, y } (paths from listArchitectureIcons); reserve raw rectangles/ellipses for when no standard form fits. Expressive enough to reproduce real Excalidraw templates (sticky-note brainstorm grids, sketchy mind maps, flowcharts). Each spec: { type: 'rectangle'|'ellipse'|'diamond'|'sticky'|'text'|'arrow'|'line'|'frame'|'image'|'stencil', id?, x, y, width, height, text? (STRONGLY PREFER setting a shape's label via its own `text` — it becomes a centered, auto-WRAPPED bound label fitted to the shape; do NOT drop a separate type:'text' element on top of a shape as its label. Standalone type:'text' is for free-floating titles/notes and now also wraps to its width; Yes/No label on an arrow — emojis are fine, e.g. 'Risks ⚠️'), fontSize?, fontFamily? (1=hand-drawn default, 2=normal, 3=code), textAlign?, backgroundColor? (name 'blue'/'green'/'yellow'/'pink'/'violet'/'orange'/'teal'/… or hex), strokeColor?, fillStyle? ('solid'|'hachure'|'cross-hatch'), strokeStyle? ('solid'|'dashed'|'dotted' — use 'dashed' for grid/category borders), strokeWidth? (1 thin/2 bold/4 extra), roughness? (0 clean, 1 default, 2 very sketchy/hand-drawn — use 2 for organic mind maps), roundness? (number type or null for sharp), opacity?, name? (frame title), frameId? (put a shape inside a frame), start?:{id}, end?:{id} (connect arrows/lines to shapes by id — connectors AUTO-CLIP to the shape edges, never overrun to the centre, AUTO-ROUTE around any shapes in between so a decision's No/loop-back branch never cuts straight through the boxes between source and target, and bound text auto-wraps + centres), routing? ('straight' default | 'elbow' for clean right-angle flowchart/org-chart connectors | 'curved'), startArrowhead?/endArrowhead? (arrowheads are SOLID filled triangles by default — just OMIT them. Pass null for a plain mind-map spoke with no head. Do NOT pass 'arrow': that is Excalidraw's open 'V' and is auto-upgraded to a solid triangle anyway), points? ([[0,0],[dx,dy]] relative, only for manual geometry — almost never needed; binding by id is better), props? (escape hatch: any other Excalidraw field) }. ARCHITECTURE ICONS: to place a software-architecture icon (AWS/Azure/GCP/Docker/Kubernetes/databases/etc.), first call listArchitectureIcons to find one, then add a spec { type:'image', iconPath:'<relative_url e.g. dev/docker.svg>', x, y, width:96, height:96, text?:'<caption shown below>' } — the icon is stored as a URL reference (never base64). Use imageUrl instead of iconPath for any other public image. Combine icons with labelled boxes + elbow arrows for clean architecture diagrams. LIBRARY STENCILS: for hand-drawn, on-brand elements (scrum/kanban columns, flowchart symbols, UML/ER, BPMN, org-chart nodes, wireframe widgets, stick figures), FIRST call listWhiteboardStencils to find one, then add { type:'stencil', stencilKey:'<key from listWhiteboardStencils>', x, y } (or { type:'stencil', stencil:'<name e.g. decision>', pack?:'<pack>', x, y } to fuzzy-match by name). A stencil is a mini-whiteboard (a collection of elements) of kind 'symbol' or 'template' (listWhiteboardStencils returns the kind + its embedded `labels`). For a SYMBOL (one atomic labelled node — flowchart box, BPMN task, org node), pass id + text + width/height: the label auto-fits its single slot and arrows bind to it via start/end {id}. For a TEMPLATE (a multi-component layout — Alerts, Forms, Tables, Charts), place it WHOLE (no single text); the result returns its `children` (id + text + colour + position) so you retext, recolour, or DELETE specific parts by id via updateWhiteboardScene (cluster children by y to act on a whole row/variant). STRONGLY prefer stencils over plain rectangles for wireframes/mockups, kanban/scrum boards, UML/BPMN, org charts; for dense flowcharts, plain shapes with bound text + elbow arrows are equally reliable. (For a plain sticky/post-it note use type:'sticky', NOT a stencil — there is no sticky-note stencil.) FRAMES: a frame is a NON-DESTRUCTIVE, ANY-SIZE container. To enclose shapes that ALREADY exist, add ONE type:'frame' sized to cover them (Excalidraw auto-captures elements inside a frame's bounds) or set those shapes' frameId — never recreate or delete-and-redraw content just to frame it. If a frame doesn't fully cover its content, just RESIZE the frame (patch its width/height). Deleting a frame (deleteIds:[frameId]) leaves all its contents intact on the canvas — it only removes the frame border + title. PRESENTATION/SLIDES: when the user wants a presentation or slide deck, create type:'frame' slides sized width:1280,height:720 (16:9), laid out LEFT-TO-RIGHT at the same y (x: 0, then 1440, 2880, 4320, …), each with a `name` (the slide title). Put every slide's shapes/text/images INSIDE its frame by setting their frameId to that frame's id (give the frame an id and reference it). Slides play in order (left-to-right, then top-to-bottom) in the board's Present mode and export to PPTX, so one frame = one slide. FLOWCHART recipe: rectangles (roundness null for sharp process boxes), diamonds for decisions, arrows with routing:'elbow' and Yes/No as the arrow's text. Use type 'sticky' for sticky/post-it notes (a solid-fill note with an auto-fitting bound label — set text + backgroundColor); type 'line' with no arrowheads + roughness:2 for sketchy mind-map spokes. Give shapes ids and reference them from connectors. Connectors may also bind to shapes ALREADY on the board by their id (get them via getWhiteboard includeElements:true) — you do NOT need to resend existing shapes; the server reads the live scene to bind the arrow and route it around the other boxes. Great for brainstorms, mind maps, flowcharts, org charts, SWOT, retros. PROCESS: for any non-trivial board call getWhiteboardGuide FIRST to plan it; then after adding, ALWAYS call getWhiteboardImage to SEE the result and check layout, labels, spacing, overlaps and how shapes connect — if anything looks off, fix it with updateWhiteboardScene (patch by id) and render again, iterating until it looks right. RESULT: returns `added` (count), `placement` (bounding box {x,y,width,height} of what you just added) and `autoPlaced` (true when you omitted x/y so it was placed in clear space below existing content) — use placement/autoPlaced to tell the user WHERE the new elements landed, never invent a location.",
4170
+ "operationId": "addWhiteboardElements",
4171
+ "tags": [
4172
+ "whiteboards"
4173
+ ],
4174
+ "requestBody": {
4175
+ "required": false,
4176
+ "content": {
4177
+ "application/json": {
4178
+ "schema": {
4179
+ "type": "object",
4180
+ "properties": {
4181
+ "documentId": {
4182
+ "type": "string"
4183
+ },
4184
+ "shapes": {
4185
+ "type": "array",
4186
+ "description": "Non-empty array of shape specs to append. Prefer stencils / sticky notes / architecture icons over raw rectangles wherever a standard form fits (see the `type` enum below and the tool description).",
4187
+ "items": {
4188
+ "type": "object",
4189
+ "properties": {
4190
+ "type": {
4191
+ "type": "string",
4192
+ "enum": [
4193
+ "rectangle",
4194
+ "ellipse",
4195
+ "diamond",
4196
+ "sticky",
4197
+ "text",
4198
+ "arrow",
4199
+ "line",
4200
+ "frame",
4201
+ "image",
4202
+ "stencil"
4203
+ ],
4204
+ "description": "Element kind. 'sticky' = a first-class sticky/post-it note (solid fill + auto-fitting bound label; set text + backgroundColor) — use this for sticky notes, NOT a stencil. 'stencil' = a hand-drawn library graphic from listWhiteboardStencils, of kind 'symbol' (one atomic labelled node — flowchart box, BPMN task, org node: set `id` + `text` + width/height, text auto-fits, connect arrows via start/end {id}) or 'template' (a multi-element layout — Alerts, Forms, Tables, Charts: place whole, then customise its returned children by id; do NOT set a single `text`). Set `stencil` (fuzzy name, one call) or `stencilKey` (exact). 'image' with `iconPath` = a software-architecture icon from listArchitectureIcons. Reserve rectangle/ellipse/diamond for when no standard form fits."
4205
+ },
4206
+ "stencil": {
4207
+ "type": "string",
4208
+ "description": "For type:'stencil' — fuzzy-match a library stencil by name in ONE call, no prior listWhiteboardStencils needed (e.g. 'decision', 'actor', 'phone frame', 'kanban column'). NOTE: there is no sticky-note stencil — use type:'sticky' for sticky/post-it notes."
4209
+ },
4210
+ "stencilKey": {
4211
+ "type": "string",
4212
+ "description": "For type:'stencil' — exact stencil key from listWhiteboardStencils (takes precedence over `stencil`)."
4213
+ },
4214
+ "pack": {
4215
+ "type": "string",
4216
+ "description": "For type:'stencil' — optional pack to disambiguate a fuzzy `stencil` match (e.g. 'Flowchart', 'BPMN', 'UML & ER', 'Scrum Board')."
4217
+ },
4218
+ "iconPath": {
4219
+ "type": "string",
4220
+ "description": "For type:'image' — a software-architecture icon path from listArchitectureIcons (e.g. 'dev/docker.svg')."
4221
+ },
4222
+ "imageUrl": {
4223
+ "type": "string",
4224
+ "description": "For type:'image' — any other public image URL (use iconPath for curated architecture icons)."
4225
+ },
4226
+ "id": {
4227
+ "type": "string",
4228
+ "description": "Optional id so connectors (arrows/lines) can reference this shape via start/end. On a type:'stencil' it adds a transparent bindable anchor covering the stencil, so an arrow's start/end {id} connects to the whole stencil as a unit."
4229
+ },
4230
+ "groupId": {
4231
+ "type": "string",
4232
+ "description": "Join an existing group. Pass a placed stencil's `groupId` (returned in the placement result) on a type:'text' or shape spec to FILL that frame as part of the same unit — the text then moves, duplicates and renders together with the frame (e.g. a title in a UML class box's top band, members in its body)."
4233
+ },
4234
+ "x": {
4235
+ "type": "number",
4236
+ "description": "Top-left x on the canvas. OMIT both x and y to auto-place this element in clear empty space below the board's existing content. Strongly preferred when adding a note/shape to a board that already has content: a guessed coordinate usually lands ON TOP of existing shapes (the 'added a sticky but can't see it' bug). Set x/y only for deliberate layout among shapes you add in this same call."
4237
+ },
4238
+ "y": {
4239
+ "type": "number",
4240
+ "description": "Top-left y on the canvas. Omit together with x to auto-place (see x)."
4241
+ },
4242
+ "width": {
4243
+ "type": "number",
4244
+ "description": "Shape width; for type:'stencil' it scales the whole stencil to fit this width."
4245
+ },
4246
+ "height": {
4247
+ "type": "number",
4248
+ "description": "Shape height; for type:'stencil' it scales the whole stencil to fit this height."
4249
+ },
4250
+ "scale": {
4251
+ "type": "number",
4252
+ "description": "For type:'stencil' — uniform scale factor for the whole stencil (alternative to width/height)."
4253
+ },
4254
+ "text": {
4255
+ "type": "string",
4256
+ "description": "Label/caption. On a shape it's a centered auto-wrapped bound label (prefer over a separate type:'text'); on a type:'sticky' it's the note text; on a type:'stencil' of kind 'symbol' it fills + re-fits its single label (IGNORED for 'template' stencils — customise their children by id instead)."
4257
+ },
4258
+ "backgroundColor": {
4259
+ "type": "string",
4260
+ "description": "Fill colour: a name ('blue'/'green'/'yellow'/'pink'/'violet'/'orange'/'teal'/…) or a hex value."
4261
+ },
4262
+ "start": {
4263
+ "type": "object",
4264
+ "description": "For arrows/lines: { id } of the source shape (auto-clips to the edge + auto-routes around shapes in between)."
4265
+ },
4266
+ "end": {
4267
+ "type": "object",
4268
+ "description": "For arrows/lines: { id } of the target shape."
4269
+ }
4270
+ },
4271
+ "required": [
4272
+ "type"
4273
+ ],
4274
+ "additionalProperties": true
4275
+ },
4276
+ "minItems": 1
4277
+ }
4278
+ },
4279
+ "required": [
4280
+ "documentId",
4281
+ "shapes"
4282
+ ]
4283
+ }
4284
+ }
4285
+ }
4286
+ },
4287
+ "responses": {
4288
+ "200": {
4289
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
4290
+ "content": {
4291
+ "application/json": {
4292
+ "schema": {
4293
+ "type": "object",
4294
+ "additionalProperties": true
4295
+ }
4296
+ }
4297
+ }
4298
+ },
4299
+ "400": {
4300
+ "description": "Validation error.",
4301
+ "content": {
4302
+ "application/json": {
4303
+ "schema": {
4304
+ "$ref": "#/components/schemas/ErrorResponse"
4305
+ }
4306
+ }
4307
+ }
4308
+ },
4309
+ "401": {
4310
+ "description": "Missing or invalid credentials.",
4311
+ "content": {
4312
+ "application/json": {
4313
+ "schema": {
4314
+ "$ref": "#/components/schemas/ErrorResponse"
4315
+ }
4316
+ }
4317
+ }
4318
+ },
4319
+ "403": {
4320
+ "description": "Authenticated but lacking the required permission or feature flag.",
4321
+ "content": {
4322
+ "application/json": {
4323
+ "schema": {
4324
+ "$ref": "#/components/schemas/ErrorResponse"
4325
+ }
4326
+ }
4327
+ }
4328
+ },
4329
+ "404": {
4330
+ "description": "Resource not found.",
4331
+ "content": {
4332
+ "application/json": {
4333
+ "schema": {
4334
+ "$ref": "#/components/schemas/ErrorResponse"
4335
+ }
4336
+ }
4337
+ }
4338
+ },
4339
+ "422": {
4340
+ "description": "Body did not match the tool's input schema.",
4341
+ "content": {
4342
+ "application/json": {
4343
+ "schema": {
4344
+ "$ref": "#/components/schemas/ErrorResponse"
4345
+ }
4346
+ }
4347
+ }
4348
+ },
4349
+ "500": {
4350
+ "description": "Server error.",
4351
+ "content": {
4352
+ "application/json": {
4353
+ "schema": {
4354
+ "$ref": "#/components/schemas/ErrorResponse"
4355
+ }
4356
+ }
4357
+ }
4358
+ }
4359
+ }
4360
+ }
4361
+ },
4362
+ "/tools/duplicateWhiteboardElements": {
4363
+ "post": {
4364
+ "summary": "duplicateWhiteboardElements",
4365
+ "description": "Copy-paste existing whiteboard elements — the MCP equivalent of selecting a group and pressing Ctrl/Cmd+D. Clones the given elements (plus their group peers + bound text/labels) with FRESH ids, offsets the copy by dx/dy, and by default groups it into ONE new unit so it moves together. Use it to build something once (a labelled stencil frame, a kanban card, a UML class) then stamp out consistent repeats fast — then retext/recolour each copy by its new id (via the returned idMap) with updateWhiteboardScene. Pass `groupId` to copy a whole group as a unit (e.g. a placed stencil's groupId from its placement result) and/or `ids` for specific elements. Internal references (group membership, bound text containerId, arrow start/end bindings) are remapped within the copied set; a binding to an element you did NOT copy is dropped. Returns { duplicated, idMap (old id → new id), groupId (the copy's new unit group), elementCount }. Render with getWhiteboardImage afterwards to verify.",
4366
+ "operationId": "duplicateWhiteboardElements",
4367
+ "tags": [
4368
+ "uncategorized"
4369
+ ],
4370
+ "requestBody": {
4371
+ "required": false,
4372
+ "content": {
4373
+ "application/json": {
4374
+ "schema": {
4375
+ "type": "object",
4376
+ "properties": {
4377
+ "documentId": {
4378
+ "type": "string",
4379
+ "description": "The whiteboard's documentId."
4380
+ },
4381
+ "ids": {
4382
+ "type": "array",
4383
+ "items": {
4384
+ "type": "string"
4385
+ },
4386
+ "description": "Element ids to copy. Each id's full group + any bound text are auto-included. Use this and/or groupId."
4387
+ },
4388
+ "groupId": {
4389
+ "type": "string",
4390
+ "description": "Copy EVERY element in this group as one unit — e.g. a placed stencil's `groupId` returned by addWhiteboardElements."
4391
+ },
4392
+ "dx": {
4393
+ "type": "number",
4394
+ "description": "Horizontal offset for the copy (default 40). Use the element width + a gap to place copies side by side."
4395
+ },
4396
+ "dy": {
4397
+ "type": "number",
4398
+ "description": "Vertical offset for the copy (default 40)."
4399
+ },
4400
+ "group": {
4401
+ "type": "boolean",
4402
+ "description": "Group the copy into one new unit so it moves/duplicates together (default true)."
4403
+ },
4404
+ "includeGroupPeers": {
4405
+ "type": "boolean",
4406
+ "description": "Auto-include the full group of any id you pass (default true)."
4407
+ }
4408
+ },
4409
+ "required": [
4410
+ "documentId"
4411
+ ]
4412
+ }
4413
+ }
4414
+ }
4415
+ },
4416
+ "responses": {
4417
+ "200": {
4418
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
4419
+ "content": {
4420
+ "application/json": {
4421
+ "schema": {
4422
+ "type": "object",
4423
+ "additionalProperties": true
4424
+ }
4425
+ }
4426
+ }
4427
+ },
4428
+ "400": {
4429
+ "description": "Validation error.",
4430
+ "content": {
4431
+ "application/json": {
4432
+ "schema": {
4433
+ "$ref": "#/components/schemas/ErrorResponse"
4434
+ }
4435
+ }
4436
+ }
4437
+ },
4438
+ "401": {
4439
+ "description": "Missing or invalid credentials.",
4440
+ "content": {
4441
+ "application/json": {
4442
+ "schema": {
4443
+ "$ref": "#/components/schemas/ErrorResponse"
4444
+ }
4445
+ }
4446
+ }
4447
+ },
4448
+ "403": {
4449
+ "description": "Authenticated but lacking the required permission or feature flag.",
4450
+ "content": {
4451
+ "application/json": {
4452
+ "schema": {
4453
+ "$ref": "#/components/schemas/ErrorResponse"
4454
+ }
4455
+ }
4456
+ }
4457
+ },
4458
+ "404": {
4459
+ "description": "Resource not found.",
4460
+ "content": {
4461
+ "application/json": {
4462
+ "schema": {
4463
+ "$ref": "#/components/schemas/ErrorResponse"
4464
+ }
4465
+ }
4466
+ }
4467
+ },
4468
+ "422": {
4469
+ "description": "Body did not match the tool's input schema.",
4470
+ "content": {
4471
+ "application/json": {
4472
+ "schema": {
4473
+ "$ref": "#/components/schemas/ErrorResponse"
4474
+ }
4475
+ }
4476
+ }
4477
+ },
4478
+ "500": {
4479
+ "description": "Server error.",
4480
+ "content": {
4481
+ "application/json": {
4482
+ "schema": {
4483
+ "$ref": "#/components/schemas/ErrorResponse"
4484
+ }
4485
+ }
4486
+ }
4487
+ }
4488
+ }
4489
+ }
4490
+ },
4491
+ "/tools/insertWhiteboardImage": {
4492
+ "post": {
4493
+ "summary": "insertWhiteboardImage",
4494
+ "description": "Insert a real IMAGE (photo, screenshot, logo, picture) into a whiteboard — the storage-backed equivalent of insertImageInDocument. Provide the image as imageUrl (fetched and re-hosted), imageBase64, or imageBinary; for large files call createImageUploadSession(documentId) first then pass the returned assetUrl as imageUrl. The bytes are stored in the document-images bucket and the scene only holds a reference (never base64), exactly like pasted images. Options: caption (a text label placed + grouped beneath the image), width/height in px to RESIZE (if only one is given the other follows a 4:3 ratio; ~360px wide if neither), and placement via x/y (top-left) OR align ('left'|'center'|'right', positioned just below existing content) — omit both to auto-place to the right of the current content. After inserting, call getWhiteboardImage to verify. To move or resize the image later, patch its element via updateWhiteboardScene (mode:'patch' with {id, x, y, width, height}). For curated software-architecture ICONS (AWS/Docker/etc.) use addWhiteboardElements with an {type:'image', iconPath} spec instead.",
4495
+ "operationId": "insertWhiteboardImage",
4496
+ "tags": [
4497
+ "whiteboards"
4498
+ ],
4499
+ "requestBody": {
4500
+ "required": false,
4501
+ "content": {
4502
+ "application/json": {
4503
+ "schema": {
4504
+ "type": "object",
4505
+ "properties": {
4506
+ "documentId": {
4507
+ "type": "string",
4508
+ "description": "The whiteboard's documentId."
4509
+ },
4510
+ "imageUrl": {
4511
+ "type": "string",
4512
+ "description": "URL to fetch the image from, or an assetUrl returned by createImageUploadSession."
4513
+ },
4514
+ "imageBase64": {
4515
+ "type": "string",
4516
+ "description": "Base64-encoded image bytes (a data: URL prefix is allowed). Best for small images."
4517
+ },
4518
+ "imageBinary": {
4519
+ "type": "array",
4520
+ "items": {
4521
+ "type": "number"
4522
+ },
4523
+ "description": "Raw image bytes as an array of 0-255 values (alternative to imageBase64)."
4524
+ },
4525
+ "caption": {
4526
+ "type": "string",
4527
+ "description": "Optional caption shown as a text label grouped beneath the image."
4528
+ },
4529
+ "width": {
4530
+ "type": "number",
4531
+ "description": "Display width in px (resize). Defaults to ~360."
4532
+ },
4533
+ "height": {
4534
+ "type": "number",
4535
+ "description": "Display height in px. Derived from width at 4:3 if omitted."
4536
+ },
4537
+ "x": {
4538
+ "type": "number",
4539
+ "description": "Top-left x on the canvas. Omit to auto-place."
4540
+ },
4541
+ "y": {
4542
+ "type": "number",
4543
+ "description": "Top-left y on the canvas. Omit to auto-place."
4544
+ },
4545
+ "align": {
4546
+ "type": "string",
4547
+ "enum": [
4548
+ "left",
4549
+ "center",
4550
+ "right"
4551
+ ],
4552
+ "description": "Horizontal alignment relative to existing content (placed below it). Ignored if x/y are provided."
4553
+ },
4554
+ "fileName": {
4555
+ "type": "string",
4556
+ "description": "Optional original filename (for storage + type hinting)."
4557
+ }
4558
+ },
4559
+ "required": [
4560
+ "documentId"
4561
+ ]
4562
+ }
4563
+ }
4564
+ }
4565
+ },
4566
+ "responses": {
4567
+ "200": {
4568
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
4569
+ "content": {
4570
+ "application/json": {
4571
+ "schema": {
4572
+ "type": "object",
4573
+ "additionalProperties": true
4574
+ }
4575
+ }
4576
+ }
4577
+ },
4578
+ "400": {
4579
+ "description": "Validation error.",
4580
+ "content": {
4581
+ "application/json": {
4582
+ "schema": {
4583
+ "$ref": "#/components/schemas/ErrorResponse"
4584
+ }
4585
+ }
4586
+ }
4587
+ },
4588
+ "401": {
4589
+ "description": "Missing or invalid credentials.",
4590
+ "content": {
4591
+ "application/json": {
4592
+ "schema": {
4593
+ "$ref": "#/components/schemas/ErrorResponse"
4594
+ }
4595
+ }
4596
+ }
4597
+ },
4598
+ "403": {
4599
+ "description": "Authenticated but lacking the required permission or feature flag.",
4600
+ "content": {
4601
+ "application/json": {
4602
+ "schema": {
4603
+ "$ref": "#/components/schemas/ErrorResponse"
4604
+ }
4605
+ }
4606
+ }
4607
+ },
4608
+ "404": {
4609
+ "description": "Resource not found.",
4610
+ "content": {
4611
+ "application/json": {
4612
+ "schema": {
4613
+ "$ref": "#/components/schemas/ErrorResponse"
4614
+ }
4615
+ }
4616
+ }
4617
+ },
4618
+ "422": {
4619
+ "description": "Body did not match the tool's input schema.",
4620
+ "content": {
4621
+ "application/json": {
4622
+ "schema": {
4623
+ "$ref": "#/components/schemas/ErrorResponse"
4624
+ }
4625
+ }
4626
+ }
4627
+ },
4628
+ "500": {
4629
+ "description": "Server error.",
4630
+ "content": {
4631
+ "application/json": {
4632
+ "schema": {
4633
+ "$ref": "#/components/schemas/ErrorResponse"
4634
+ }
4635
+ }
4636
+ }
4637
+ }
4638
+ }
4639
+ }
4640
+ },
4641
+ "/tools/insertWhiteboardDiagram": {
4642
+ "post": {
4643
+ "summary": "insertWhiteboardDiagram",
4644
+ "description": "Insert a real DIAGRAM (BPMN, Diagrams-as-Code / any DSL: mermaid, d2, plantuml, graphviz, …) into a whiteboard as an editable SB diagram element. Provide documentId, diagramType (call listDiagramTypes / getDiagramTypeGuide), and source (the DSL). The diagram is rendered to an image stored like a pasted image, and its editable source is kept in a sidecar so it stays a live, re-openable diagram on the board (double-click on the canvas opens the BPMN / code / AI editor). Options: caption (label beneath it), width/height to size it, and x/y or align ('left'|'center'|'right') to place it (defaults to the right of existing content). After inserting, call getWhiteboardImage to see it and verify it rendered correctly (fix the source and re-insert if it is wrong). For a plain picture (not a diagram) use insertWhiteboardImage; to generate a diagram image WITHOUT inserting use renderDiagram.",
4645
+ "operationId": "insertWhiteboardDiagram",
4646
+ "tags": [
4647
+ "whiteboards"
4648
+ ],
4649
+ "requestBody": {
4650
+ "required": false,
4651
+ "content": {
4652
+ "application/json": {
4653
+ "schema": {
4654
+ "type": "object",
4655
+ "properties": {
4656
+ "documentId": {
4657
+ "type": "string",
4658
+ "description": "The whiteboard's documentId."
4659
+ },
4660
+ "diagramType": {
4661
+ "type": "string",
4662
+ "description": "Diagram language, e.g. 'bpmn', 'mermaid', 'd2', 'plantuml', 'graphviz'. See listDiagramTypes."
4663
+ },
4664
+ "source": {
4665
+ "type": "string",
4666
+ "description": "The diagram DSL / code."
4667
+ },
4668
+ "caption": {
4669
+ "type": "string",
4670
+ "description": "Optional caption shown beneath the diagram."
4671
+ },
4672
+ "width": {
4673
+ "type": "number",
4674
+ "description": "Display width in px (aspect ratio preserved). Defaults to a capped natural size."
4675
+ },
4676
+ "height": {
4677
+ "type": "number",
4678
+ "description": "Display height in px (defaults from width + aspect)."
4679
+ },
4680
+ "x": {
4681
+ "type": "number",
4682
+ "description": "Top-left x on the canvas. Omit to auto-place."
4683
+ },
4684
+ "y": {
4685
+ "type": "number",
4686
+ "description": "Top-left y on the canvas. Omit to auto-place."
4687
+ },
4688
+ "align": {
4689
+ "type": "string",
4690
+ "enum": [
4691
+ "left",
4692
+ "center",
4693
+ "right"
4694
+ ],
4695
+ "description": "Horizontal alignment relative to existing content (placed below it). Ignored if x/y given."
4696
+ }
4697
+ },
4698
+ "required": [
4699
+ "documentId",
4700
+ "diagramType",
4701
+ "source"
4702
+ ]
4703
+ }
4704
+ }
4705
+ }
4706
+ },
4707
+ "responses": {
4708
+ "200": {
4709
+ "description": "Tool result (shape varies per tool — refer to the tool's docs for the exact return value).",
4710
+ "content": {
4711
+ "application/json": {
4712
+ "schema": {
4713
+ "type": "object",
4714
+ "additionalProperties": true
4715
+ }
4716
+ }
4717
+ }
4718
+ },
4719
+ "400": {
4720
+ "description": "Validation error.",
4721
+ "content": {
4722
+ "application/json": {
4723
+ "schema": {
4724
+ "$ref": "#/components/schemas/ErrorResponse"
4725
+ }
4726
+ }
4727
+ }
4728
+ },
4729
+ "401": {
4730
+ "description": "Missing or invalid credentials.",
4731
+ "content": {
4732
+ "application/json": {
4733
+ "schema": {
4734
+ "$ref": "#/components/schemas/ErrorResponse"
4735
+ }
4736
+ }
4737
+ }
4738
+ },
4739
+ "403": {
4740
+ "description": "Authenticated but lacking the required permission or feature flag.",
4741
+ "content": {
4742
+ "application/json": {
4743
+ "schema": {
4744
+ "$ref": "#/components/schemas/ErrorResponse"
4745
+ }
4746
+ }
4747
+ }
4748
+ },
4749
+ "404": {
4750
+ "description": "Resource not found.",
4751
+ "content": {
4752
+ "application/json": {
4753
+ "schema": {
4754
+ "$ref": "#/components/schemas/ErrorResponse"
4755
+ }
4756
+ }
4757
+ }
4758
+ },
4759
+ "422": {
4760
+ "description": "Body did not match the tool's input schema.",
4761
+ "content": {
4762
+ "application/json": {
4763
+ "schema": {
4764
+ "$ref": "#/components/schemas/ErrorResponse"
4765
+ }
4766
+ }
4767
+ }
4768
+ },
4769
+ "500": {
4770
+ "description": "Server error.",
4771
+ "content": {
4772
+ "application/json": {
4773
+ "schema": {
4774
+ "$ref": "#/components/schemas/ErrorResponse"
4775
+ }
4776
+ }
4777
+ }
4778
+ }
4779
+ }
4780
+ }
4781
+ },
4782
+ "/tools/listWhiteboardStencils": {
4783
+ "post": {
4784
+ "summary": "listWhiteboardStencils",
4785
+ "description": "Search the built-in library of structural whiteboard stencils — ready-made hand-drawn graphics: flowchart/UML/ER/BPMN symbols, scrum columns, org-chart nodes, gantt, lo-fi/UX wireframe widgets (buttons, forms, tables, alerts, navs), charts, device frames, stick figures. A stencil is a MINI-WHITEBOARD (a collection of elements), NOT a single shape. Each result returns: `key`, `title` (a real human name e.g. 'Alerts', not an index), `kind` ('symbol' | 'template'), `labels` (the TEXT it actually contains — its real content, e.g. an Alerts template's variant messages), `size` ({w,h} px), `summary`, `pack`, `category`; plus the full pack/category lists. The two kinds are used DIFFERENTLY: • SYMBOL = one atomic labelled node (flowchart Process/Decision, BPMN task, org node). Place + label + connect: addWhiteboardElements({type:'stencil', stencilKey, id:'n1', text:'Review', width, height}) — the text auto-fits its single slot and an arrow's start/end {id:'n1'} binds to it like any shape. A few symbols are text-less FRAMES (e.g. a UML class box = rectangle + divider line): place create-only, then use the placement result's `children` (shapes + x/y/w/h) and `groupId` to add type:'text' specs INTO the regions — pass that groupId so the text is one unit with the frame. • TEMPLATE = a multi-component layout (Alerts, Forms, Tables, Charts, device frames). Place the WHOLE thing: addWhiteboardElements({type:'stencil', stencilKey, x, y, width?, height?}); the placement RESULT returns `stencils[].children` (each child's id + text + colour + position x/y/w/h, so you can group children into rows/sections) so you then keep / retext / recolour / DELETE specific parts via updateWhiteboardScene (e.g. delete the info + error rows to keep only the green success alert). Do NOT pass a single `text` to a template — read its `labels` to see its parts, then edit them by id. To make several similar items, build one then duplicateWhiteboardElements({groupId, dx}) to stamp consistent copies (like copy-paste in the UI). SEARCH TIPS: prefer BROAD single words ('decision','alert','form','phone','process'); content words match the embedded `labels` too (searching 'success' finds the Alerts template). If nothing exact matches, results auto-broaden (broadened:true); pass pack/category to browse. For cloud/architecture ICONS (AWS/Azure/GCP/Docker/Kubernetes/databases) use listArchitectureIcons; for a sticky/post-it use addWhiteboardElements({type:'sticky'}), not a stencil.",
4786
+ "operationId": "listWhiteboardStencils",
4787
+ "tags": [
4788
+ "whiteboards"
2591
4789
  ],
2592
4790
  "requestBody": {
2593
4791
  "required": false,
@@ -2596,56 +4794,23 @@
2596
4794
  "schema": {
2597
4795
  "type": "object",
2598
4796
  "properties": {
2599
- "documentId": {
2600
- "type": "string"
2601
- },
2602
- "title": {
4797
+ "query": {
2603
4798
  "type": "string",
2604
- "description": "New title."
4799
+ "description": "Free-text search across name + pack + category (e.g. 'decision', 'database table', 'phone frame', 'actor', 'kanban column')."
2605
4800
  },
2606
- "folderId": {
4801
+ "pack": {
2607
4802
  "type": "string",
2608
- "description": "Move to this folder."
2609
- },
2610
- "versionTimestamp": {
2611
- "type": "number",
2612
- "description": "Version timestamp from getDocument() for optimistic locking."
4803
+ "description": "Restrict to one pack, e.g. 'Flowchart', 'BPMN', 'UML & ER', 'Scrum Board', 'Lo-Fi Wireframes', 'Org Chart'."
2613
4804
  },
2614
- "changeSummary": {
4805
+ "category": {
2615
4806
  "type": "string",
2616
- "description": "Version history summary."
4807
+ "description": "Filter by category: 'Notes & Planning', 'Diagramming', 'UI & Wireframing', 'Data & Charts', 'People & Fun'."
2617
4808
  },
2618
- "patches": {
2619
- "type": "array",
2620
- "description": "Line-based patches. Can be empty if only updating title or folderId.",
2621
- "items": {
2622
- "type": "object",
2623
- "properties": {
2624
- "startLine": {
2625
- "type": "number",
2626
- "description": "1-based start line."
2627
- },
2628
- "endLine": {
2629
- "type": "number",
2630
- "description": "1-based end line (inclusive)."
2631
- },
2632
- "replacement": {
2633
- "type": "string",
2634
- "description": "Replacement text. Empty string to delete lines."
2635
- }
2636
- },
2637
- "required": [
2638
- "startLine",
2639
- "endLine",
2640
- "replacement"
2641
- ]
2642
- }
4809
+ "limit": {
4810
+ "type": "number",
4811
+ "description": "Max results (default 60, max 200)."
2643
4812
  }
2644
- },
2645
- "required": [
2646
- "documentId",
2647
- "versionTimestamp"
2648
- ]
4813
+ }
2649
4814
  }
2650
4815
  }
2651
4816
  }
@@ -2725,13 +4890,13 @@
2725
4890
  }
2726
4891
  }
2727
4892
  },
2728
- "/tools/findAndReplaceTextInDocument": {
4893
+ "/tools/getWhiteboardImage": {
2729
4894
  "post": {
2730
- "summary": "findAndReplaceTextInDocument",
2731
- "description": "Find and replace text in a document. Searches for all occurrences and replaces them. Case-sensitive by default. Diagrams/images are automatically protected only document text is affected.",
2732
- "operationId": "findAndReplaceTextInDocument",
4895
+ "summary": "getWhiteboardImage",
4896
+ "description": "Render a whiteboard to an IMAGE so you can SEE it and confirm your edits look right, then iterate — like taking a screenshot. Returns the rendered board as a viewable PNG (default) attached to the result. Pass elementIds to render only specific shapes (e.g. to inspect one section/slide), format:'svg' for vector markup instead of a raster, or background to set the canvas colour. Call this after addWhiteboardElements/updateWhiteboardScene to check layout, overlaps, labels and alignment before continuing.",
4897
+ "operationId": "getWhiteboardImage",
2733
4898
  "tags": [
2734
- "documents"
4899
+ "whiteboards"
2735
4900
  ],
2736
4901
  "requestBody": {
2737
4902
  "required": false,
@@ -2741,29 +4906,31 @@
2741
4906
  "type": "object",
2742
4907
  "properties": {
2743
4908
  "documentId": {
2744
- "type": "string"
2745
- },
2746
- "find": {
2747
4909
  "type": "string",
2748
- "description": "Text to search for."
4910
+ "description": "The whiteboard's documentId."
2749
4911
  },
2750
- "replace": {
4912
+ "format": {
2751
4913
  "type": "string",
2752
- "description": "Replacement text. Empty string to delete occurrences."
4914
+ "enum": [
4915
+ "png",
4916
+ "svg"
4917
+ ],
4918
+ "description": "png (default — a viewable raster) or svg (vector markup)."
2753
4919
  },
2754
- "caseSensitive": {
2755
- "type": "boolean",
2756
- "description": "Case-sensitive matching. Default: true."
4920
+ "elementIds": {
4921
+ "type": "array",
4922
+ "items": {
4923
+ "type": "string"
4924
+ },
4925
+ "description": "Render only these element ids (plus their bound labels + group peers) instead of the whole board."
2757
4926
  },
2758
- "changeSummary": {
4927
+ "background": {
2759
4928
  "type": "string",
2760
- "description": "Version history summary."
4929
+ "description": "Canvas background colour (default white), e.g. '#ffffff' or 'transparent'."
2761
4930
  }
2762
4931
  },
2763
4932
  "required": [
2764
- "documentId",
2765
- "find",
2766
- "replace"
4933
+ "documentId"
2767
4934
  ]
2768
4935
  }
2769
4936
  }
@@ -2844,13 +5011,13 @@
2844
5011
  }
2845
5012
  }
2846
5013
  },
2847
- "/tools/getDiagramInDocument": {
5014
+ "/tools/deleteWhiteboard": {
2848
5015
  "post": {
2849
- "summary": "getDiagramInDocument",
2850
- "description": "Get a diagram's full details including raw DSL source code. Use diagramId from DIAGRAM_OMITTED markers in getDocument output. Returns diagramCode, type, name, nlDescription, and versionTimestamp.",
2851
- "operationId": "getDiagramInDocument",
5016
+ "summary": "deleteWhiteboard",
5017
+ "description": "Delete a whiteboard (the host document and its canvas).",
5018
+ "operationId": "deleteWhiteboard",
2852
5019
  "tags": [
2853
- "diagrams"
5020
+ "whiteboards"
2854
5021
  ],
2855
5022
  "requestBody": {
2856
5023
  "required": false,
@@ -2859,20 +5026,12 @@
2859
5026
  "schema": {
2860
5027
  "type": "object",
2861
5028
  "properties": {
2862
- "diagramId": {
2863
- "type": "string",
2864
- "description": "Diagram ID from DIAGRAM_OMITTED markers."
2865
- },
2866
- "fields": {
2867
- "type": "array",
2868
- "items": {
2869
- "type": "string"
2870
- },
2871
- "description": "Field projection. Valid fields: diagramId, documentId, type, name, diagramCode, nlDescription, colorPlan, renderStatus, renderError, createdAt, updatedAt, versionTimestamp."
5029
+ "documentId": {
5030
+ "type": "string"
2872
5031
  }
2873
5032
  },
2874
5033
  "required": [
2875
- "diagramId"
5034
+ "documentId"
2876
5035
  ]
2877
5036
  }
2878
5037
  }
@@ -2953,11 +5112,11 @@
2953
5112
  }
2954
5113
  }
2955
5114
  },
2956
- "/tools/insertDiagramInDocument": {
5115
+ "/tools/renderDiagram": {
2957
5116
  "post": {
2958
- "summary": "insertDiagramInDocument",
2959
- "description": "Insert a new diagram into a document. Call listDiagramTypes to find your type, then getDiagramTypeGuide for DSL syntax before writing diagramCode.",
2960
- "operationId": "insertDiagramInDocument",
5117
+ "summary": "renderDiagram",
5118
+ "description": "Generate a diagram from its DSL/code and get the IMAGE back — WITHOUT inserting it into any document or whiteboard. For acting as a pure diagram generator. Provide diagramType (e.g. 'mermaid', 'd2', 'plantuml', 'graphviz', 'bpmn', 'vegalite'; call listDiagramTypes for the full set) and source (the diagram code). Choose format 'png' (default), 'jpeg', or 'svg'; for raster choose scale 1/2/3 for 1x/2x/3x; optional background (png only). Returns a TEMPORARY signed imageUrl that expires in 1 hour (then auto-deleted), and for png/jpeg the image inline so you can see it. To render a diagram that already lives in a document/whiteboard use getDiagramImage; to persist a new one use insertDiagramInDocument or insertWhiteboardDiagram.",
5119
+ "operationId": "renderDiagram",
2961
5120
  "tags": [
2962
5121
  "diagrams"
2963
5122
  ],
@@ -2968,73 +5127,40 @@
2968
5127
  "schema": {
2969
5128
  "type": "object",
2970
5129
  "properties": {
2971
- "documentId": {
2972
- "type": "string"
2973
- },
2974
- "documentVersionTimestamp": {
2975
- "type": "number",
2976
- "description": "Version timestamp from getDocument() for optimistic locking."
2977
- },
2978
- "type": {
2979
- "type": "string",
2980
- "description": "Diagram type (e.g. mermaid, plantuml, bpmn, d2). Call listDiagramTypes for all types."
2981
- },
2982
- "diagramCode": {
2983
- "type": "string",
2984
- "description": "Diagram DSL code. Call getDiagramTypeGuide for syntax."
2985
- },
2986
- "prompt": {
5130
+ "diagramType": {
2987
5131
  "type": "string",
2988
- "description": "Short description of what the diagram shows (1-2 sentences)."
5132
+ "description": "Diagram language, e.g. 'mermaid', 'd2', 'plantuml', 'graphviz', 'bpmn', 'vegalite'. See listDiagramTypes."
2989
5133
  },
2990
- "nlDescription": {
5134
+ "source": {
2991
5135
  "type": "string",
2992
- "description": "Extended description of the diagram (2-4 sentences)."
5136
+ "description": "The diagram DSL / code to render."
2993
5137
  },
2994
- "align": {
5138
+ "format": {
2995
5139
  "type": "string",
2996
- "description": "Alignment.",
2997
5140
  "enum": [
2998
- "left",
2999
- "center",
3000
- "right"
3001
- ]
3002
- },
3003
- "caption": {
3004
- "type": "string",
3005
- "description": "Caption below the diagram."
5141
+ "png",
5142
+ "jpeg",
5143
+ "svg"
5144
+ ],
5145
+ "description": "png (default) or jpeg = raster; svg = vector."
3006
5146
  },
3007
- "afterLine": {
5147
+ "scale": {
3008
5148
  "type": "number",
3009
- "description": "Insert after this line number (1-based)."
5149
+ "enum": [
5150
+ 1,
5151
+ 2,
5152
+ 3
5153
+ ],
5154
+ "description": "Raster resolution multiplier 1x/2x/3x (default 2). Ignored for svg."
3010
5155
  },
3011
- "colorPlan": {
3012
- "type": "object",
3013
- "description": "BPMN only. Color plan: { byElementId: { ElementId: SwatchName } }.",
3014
- "properties": {
3015
- "byElementId": {
3016
- "type": "object",
3017
- "description": "Map of element IDs to color swatch names.",
3018
- "additionalProperties": {
3019
- "type": "string"
3020
- }
3021
- }
3022
- },
3023
- "required": [
3024
- "byElementId"
3025
- ]
5156
+ "background": {
5157
+ "type": "string",
5158
+ "description": "Background for png/jpeg, e.g. '#ffffff' or 'transparent' (png only)."
3026
5159
  }
3027
5160
  },
3028
5161
  "required": [
3029
- "documentId",
3030
- "documentVersionTimestamp",
3031
- "type",
3032
- "diagramCode",
3033
- "prompt",
3034
- "nlDescription",
3035
- "align",
3036
- "caption",
3037
- "afterLine"
5162
+ "diagramType",
5163
+ "source"
3038
5164
  ]
3039
5165
  }
3040
5166
  }
@@ -3115,11 +5241,11 @@
3115
5241
  }
3116
5242
  }
3117
5243
  },
3118
- "/tools/updateDiagramInDocument": {
5244
+ "/tools/getDiagramImage": {
3119
5245
  "post": {
3120
- "summary": "updateDiagramInDocument",
3121
- "description": "Update a diagram's code, description, or properties. Call getDiagramTypeGuide for DSL syntax. Requires documentVersionTimestamp from getDocument. IMPORTANT: To change what the diagram visually shows, you MUST provide diagramCode with the full updated DSL source. The prompt and nlDescription fields are metadata only and do NOT change the rendered diagram.",
3122
- "operationId": "updateDiagramInDocument",
5246
+ "summary": "getDiagramImage",
5247
+ "description": "Render a diagram that ALREADY exists in a document to an IMAGE (svg/png/jpeg @1x/2x/3x) and return it a temporary signed URL (expires in 1 hour) plus, for png/jpeg, the image inline so you can see it. Pass the diagramId (from getDocument's DIAGRAM markers or getDiagramInDocument). Reuses the diagram's cached server render when available (pixel-identical to the editor). Use renderDiagram instead to generate from raw DSL without an existing diagram.",
5248
+ "operationId": "getDiagramImage",
3123
5249
  "tags": [
3124
5250
  "diagrams"
3125
5251
  ],
@@ -3132,57 +5258,33 @@
3132
5258
  "properties": {
3133
5259
  "diagramId": {
3134
5260
  "type": "string",
3135
- "description": "Diagram ID from DIAGRAM_OMITTED markers."
3136
- },
3137
- "diagramCode": {
3138
- "type": "string",
3139
- "description": "New diagram DSL source code. REQUIRED to change what the diagram visually renders. Call getDiagramTypeGuide for syntax. Must provide the COMPLETE updated DSL, not just the changed parts."
3140
- },
3141
- "prompt": {
3142
- "type": "string",
3143
- "description": "New short description (metadata only — does NOT change the rendered diagram)."
5261
+ "description": "The diagram's id (from getDocument markers / getDiagramInDocument)."
3144
5262
  },
3145
- "nlDescription": {
5263
+ "format": {
3146
5264
  "type": "string",
3147
- "description": "New extended description (metadata only — does NOT change the rendered diagram)."
5265
+ "enum": [
5266
+ "png",
5267
+ "jpeg",
5268
+ "svg"
5269
+ ],
5270
+ "description": "png (default) or jpeg = raster; svg = vector."
3148
5271
  },
3149
- "align": {
3150
- "type": "string",
3151
- "description": "Alignment.",
5272
+ "scale": {
5273
+ "type": "number",
3152
5274
  "enum": [
3153
- "left",
3154
- "center",
3155
- "right"
3156
- ]
5275
+ 1,
5276
+ 2,
5277
+ 3
5278
+ ],
5279
+ "description": "Raster resolution multiplier 1x/2x/3x (default 2). Ignored for svg."
3157
5280
  },
3158
- "caption": {
5281
+ "background": {
3159
5282
  "type": "string",
3160
- "description": "New caption."
3161
- },
3162
- "colorPlan": {
3163
- "type": "object",
3164
- "description": "BPMN only. Updated color plan. Set to null to remove.",
3165
- "properties": {
3166
- "byElementId": {
3167
- "type": "object",
3168
- "description": "Map of element IDs to color swatch names.",
3169
- "additionalProperties": {
3170
- "type": "string"
3171
- }
3172
- }
3173
- },
3174
- "required": [
3175
- "byElementId"
3176
- ]
3177
- },
3178
- "documentVersionTimestamp": {
3179
- "type": "number",
3180
- "description": "Version timestamp from getDocument() for optimistic locking."
5283
+ "description": "Background for png/jpeg, e.g. '#ffffff' or 'transparent' (png only)."
3181
5284
  }
3182
5285
  },
3183
5286
  "required": [
3184
- "diagramId",
3185
- "documentVersionTimestamp"
5287
+ "diagramId"
3186
5288
  ]
3187
5289
  }
3188
5290
  }
@@ -3263,13 +5365,13 @@
3263
5365
  }
3264
5366
  }
3265
5367
  },
3266
- "/tools/deleteDiagramInDocument": {
5368
+ "/tools/rebuildPlatformCatalogEmbeddings": {
3267
5369
  "post": {
3268
- "summary": "deleteDiagramInDocument",
3269
- "description": "Delete a diagram from a document.",
3270
- "operationId": "deleteDiagramInDocument",
5370
+ "summary": "rebuildPlatformCatalogEmbeddings",
5371
+ "description": "Internal maintenance (requires write). Syncs gte-small (384-dim) vector embeddings for the MCP tool, whiteboard stencil, and architecture icon catalogs into platform_catalog_embeddings, so searchTools, listWhiteboardStencils, and listArchitectureIcons can do semantic search. Incremental: scans every catalog, diffs by content hash, and re-embeds ONLY changed rows (cheap no-op when nothing changed). This normally runs automatically every hour (the platform-catalog-sync cron), so manual calls are rarely needed — use it to force an immediate sync after changing tools/stencils/icons. Embeds up to ~120 changed rows per call; if more changed, call again until allDone is true. Not part of normal authoring flows.",
5372
+ "operationId": "rebuildPlatformCatalogEmbeddings",
3271
5373
  "tags": [
3272
- "diagrams"
5374
+ "uncategorized"
3273
5375
  ],
3274
5376
  "requestBody": {
3275
5377
  "required": false,
@@ -3278,14 +5380,19 @@
3278
5380
  "schema": {
3279
5381
  "type": "object",
3280
5382
  "properties": {
3281
- "diagramId": {
3282
- "type": "string",
3283
- "description": "Diagram ID from DIAGRAM_OMITTED markers."
5383
+ "types": {
5384
+ "type": "array",
5385
+ "items": {
5386
+ "type": "string",
5387
+ "enum": [
5388
+ "tool",
5389
+ "stencil",
5390
+ "icon"
5391
+ ]
5392
+ },
5393
+ "description": "Which catalogs to sync. Defaults to all three (tool, stencil, icon)."
3284
5394
  }
3285
- },
3286
- "required": [
3287
- "diagramId"
3288
- ]
5395
+ }
3289
5396
  }
3290
5397
  }
3291
5398
  }
@@ -3365,11 +5472,11 @@
3365
5472
  }
3366
5473
  }
3367
5474
  },
3368
- "/tools/deleteDocument": {
5475
+ "/tools/reorderDocuments": {
3369
5476
  "post": {
3370
- "summary": "deleteDocument",
3371
- "description": "Delete a document.",
3372
- "operationId": "deleteDocument",
5477
+ "summary": "reorderDocuments",
5478
+ "description": "Batch-reorder documents within a folder (or project root) by setting sibling positions. Pass [{documentId, position}, ...] where position is a non-negative integer; usually you renumber siblings sequentially as 0, 1, 2…. Position-only update — does not bump version or create a snapshot. To MOVE a document to a different folder, use editDocument({folderId, position}) instead.",
5479
+ "operationId": "reorderDocuments",
3373
5480
  "tags": [
3374
5481
  "documents"
3375
5482
  ],
@@ -3380,12 +5487,29 @@
3380
5487
  "schema": {
3381
5488
  "type": "object",
3382
5489
  "properties": {
3383
- "documentId": {
3384
- "type": "string"
5490
+ "items": {
5491
+ "type": "array",
5492
+ "description": "List of document position updates. All documents must belong to the same project.",
5493
+ "items": {
5494
+ "type": "object",
5495
+ "properties": {
5496
+ "documentId": {
5497
+ "type": "string"
5498
+ },
5499
+ "position": {
5500
+ "type": "number"
5501
+ }
5502
+ },
5503
+ "required": [
5504
+ "documentId",
5505
+ "position"
5506
+ ]
5507
+ },
5508
+ "minItems": 1
3385
5509
  }
3386
5510
  },
3387
5511
  "required": [
3388
- "documentId"
5512
+ "items"
3389
5513
  ]
3390
5514
  }
3391
5515
  }
@@ -4439,7 +6563,7 @@
4439
6563
  "description": "Step 1 of file ingest. Mint a single-use PUT upload URL for a large file (PDF, DOCX, plain text, or markdown — up to 150 MB). Returns { sessionId, uploadUrl, expiresAt, maxBytes }. Upload the raw bytes to uploadUrl with PUT, then call createDocumentFromUpload({ sessionId, projectId }) to start the conversion. The file is auto-deleted once the document is created.",
4440
6564
  "operationId": "createDocumentIngestSession",
4441
6565
  "tags": [
4442
- "uncategorized"
6566
+ "documents"
4443
6567
  ],
4444
6568
  "requestBody": {
4445
6569
  "required": false,
@@ -4559,7 +6683,7 @@
4559
6683
  "description": "Step 2 of file ingest. After the file is uploaded via the PUT URL from createDocumentIngestSession, call this to start the async conversion. Returns { jobId, documentId } immediately — the document is created as a draft and progressively populated as the worker processes the file. Poll getDocumentIngestJob({ jobId }) to track progress. Idempotent: calling twice with the same sessionId returns the same job/document.",
4560
6684
  "operationId": "createDocumentFromUpload",
4561
6685
  "tags": [
4562
- "uncategorized"
6686
+ "documents"
4563
6687
  ],
4564
6688
  "requestBody": {
4565
6689
  "required": false,
@@ -4678,7 +6802,7 @@
4678
6802
  "description": "Read the current status of an ingest job. Returns { status, stage, processedImages, totalImages, documentId, error?, lastHeartbeatAt }. Stages: pending → downloaded → extracted → draft_saved → images_processing → finalized → cleaned_up. Status: queued, running, succeeded, failed, cancelled. The associated document_id is populated immediately and progressively filled in as images are processed.",
4679
6803
  "operationId": "getDocumentIngestJob",
4680
6804
  "tags": [
4681
- "uncategorized"
6805
+ "documents"
4682
6806
  ],
4683
6807
  "requestBody": {
4684
6808
  "required": false,
@@ -9043,7 +11167,7 @@
9043
11167
  "description": "Update a task. Tasks share a row with improvements (`improvement_items` with `is_task=true`), so this is a thin alias over updateImprovement — every field on updateImprovement is supported, including `checklist`, `acceptance_criteria`, status transitions (blocked/rejected/done need their respective comments), dates, owner, percent_complete, etc. Requires versionTimestamp from getTask for optimistic locking. To edit checklist items: call getTask, modify the `checklist` array (preserving each row's `id` to keep its attribution stamps), and pass the full array back here — array order is the sort order. Assignment: pass `owner_id=<uuid>` to assign to a user, `owner_team_id=<uuid>` to assign to a team (mutually exclusive — the DB enforces with a CHECK constraint). To unassign, pass `owner_id=null` AND `owner_team_id=null`. To switch owner kind, send the new value AND null the old one in the SAME call.",
9044
11168
  "operationId": "updateTask",
9045
11169
  "tags": [
9046
- "uncategorized"
11170
+ "plans"
9047
11171
  ],
9048
11172
  "requestBody": {
9049
11173
  "required": false,
@@ -10590,7 +12714,7 @@
10590
12714
  "description": "Phase 5 / E3 — Provenance-aware assessor for a set of chunk_ids returned by kg_search. Returns per-chunk bucket (authored-grounded | extracted-high-conf | extracted-low-conf | no-support), overall distribution, dominant_bucket, and recommend_refusal. Pure metadata read - no LLM cost. Used by the agent's response policy to decide whether to answer confidently, caveat, or refuse.",
10591
12715
  "operationId": "kg_evaluate_retrieval",
10592
12716
  "tags": [
10593
- "uncategorized"
12717
+ "knowledge_graph"
10594
12718
  ],
10595
12719
  "requestBody": {
10596
12720
  "required": false,
@@ -12074,7 +14198,7 @@
12074
14198
  "/tools/getSubscription": {
12075
14199
  "post": {
12076
14200
  "summary": "getSubscription",
12077
- "description": "Read the subscription state for an organisation. Returns tier, status, current billing period, seat count, member count, cancellation flag, trial end. Stripe IDs are stripped. Pair with listPaymentMethods/listInvoices for the full billing dashboard.",
14201
+ "description": "Read the subscription state for an organisation. Returns tier, status, current billing period, seat count, member count, cancellation flag, trial end. Stripe IDs are stripped. Pair with listPaymentMethods/listInvoices for the full billing dashboard. Use when the user asks 'what plan am I on', 'how many seats do I have', 'when does my subscription renew', or to check current billing status.",
12078
14202
  "operationId": "getSubscription",
12079
14203
  "tags": [
12080
14204
  "billing"
@@ -12801,7 +14925,7 @@
12801
14925
  "/tools/listResourcePermissions": {
12802
14926
  "post": {
12803
14927
  "summary": "listResourcePermissions",
12804
- "description": "List explicit permission grants on a resource (workspace/project/folder/document/improvement/plan), including principal type (user|team), level (none|read|write|admin), and 3-state overrides for documents/improvements/plans. Read-only.",
14928
+ "description": "List explicit permission grants on a resource (workspace/project/folder/document/improvement/plan), including principal type (user|team), level (none|read|write|admin), and 3-state overrides for documents/improvements/plans. Read-only. Use when the user asks 'who can see this', 'who has access', 'what permissions are set on this', or to audit existing access on a resource.",
12805
14929
  "operationId": "listResourcePermissions",
12806
14930
  "tags": [
12807
14931
  "permissions"
@@ -12916,7 +15040,7 @@
12916
15040
  "/tools/getEffectivePermission": {
12917
15041
  "post": {
12918
15042
  "summary": "getEffectivePermission",
12919
- "description": "Compute a user's effective permission level on a resource (taking team grants, inheritance, and 3-state overrides into account) and the source. Asking about another user requires can_manage_perms on the org.",
15043
+ "description": "Compute a user's effective permission level on a resource (taking team grants, inheritance, and 3-state overrides into account) and the source. Asking about another user requires can_manage_perms on the org. Use when the user asks 'can X access this', 'what level of access does X have', 'why can X see this', or to debug an unexpected permission outcome.",
12920
15044
  "operationId": "getEffectivePermission",
12921
15045
  "tags": [
12922
15046
  "permissions"
@@ -14125,7 +16249,7 @@
14125
16249
  "/tools/inviteMember": {
14126
16250
  "post": {
14127
16251
  "summary": "inviteMember",
14128
- "description": "Invite a person by email to the credential's organisation. Auth: org id must match the credential AND credential must hold can_manage_members. Rate limit 10/h. Returns invitation_id, expiry, and a seat-billing-impact summary. Email-existence is opaque: the response shape never reveals whether the email is already a member, already invited, or new.",
16252
+ "description": "Invite a person by email to the credential's organisation. Auth: org id must match the credential AND credential must hold can_manage_members. Rate limit 10/h. Returns invitation_id, expiry, and a seat-billing-impact summary. Email-existence is opaque: the response shape never reveals whether the email is already a member, already invited, or new. Use when the user asks to invite a teammate, friend, colleague, or new user to their organisation, or to onboard someone.",
14129
16253
  "operationId": "inviteMember",
14130
16254
  "tags": [
14131
16255
  "members"
@@ -14247,7 +16371,7 @@
14247
16371
  "/tools/cancelInvitation": {
14248
16372
  "post": {
14249
16373
  "summary": "cancelInvitation",
14250
- "description": "Cancel a pending invitation by id. Sets status='revoked'. Server resolves the organisation_id from the invitation row; the credential must match that org AND hold can_manage_members. Idempotent. Rate limit 30/min.",
16374
+ "description": "Cancel a pending invitation by id. Sets status='revoked'. Server resolves the organisation_id from the invitation row; the credential must match that org AND hold can_manage_members. Idempotent. Rate limit 30/min. Use when the user asks to cancel, revoke, or undo a pending invitation — for example to correct a typo'd email address before re-inviting.",
14251
16375
  "operationId": "cancelInvitation",
14252
16376
  "tags": [
14253
16377
  "members"
@@ -14349,7 +16473,7 @@
14349
16473
  "/tools/resendInvitation": {
14350
16474
  "post": {
14351
16475
  "summary": "resendInvitation",
14352
- "description": "Resend a pending invitation: extends expires_at by 7 days and re-triggers the invitation email. Server resolves the organisation_id from the invitation row. Rate limit 6/h per invitation_id.",
16476
+ "description": "Resend a pending invitation: extends expires_at by 7 days and re-triggers the invitation email. Server resolves the organisation_id from the invitation row. Rate limit 6/h per invitation_id. Use when the user asks to resend, re-send, or re-trigger an invitation email — typically because the recipient lost it or the original expired.",
14353
16477
  "operationId": "resendInvitation",
14354
16478
  "tags": [
14355
16479
  "members"
@@ -14451,7 +16575,7 @@
14451
16575
  "/tools/updateMemberRole": {
14452
16576
  "post": {
14453
16577
  "summary": "updateMemberRole",
14454
- "description": "Update an organisation member's role (admin or member). Owners cannot be changed via this tool. Refuses self-promotion. Rate limit 30/min.",
16578
+ "description": "Update an organisation member's role (admin or member). Owners cannot be changed via this tool. Refuses self-promotion. Rate limit 30/min. Use when the user asks to promote someone to admin, demote an admin to member, or change a teammate's role.",
14455
16579
  "operationId": "updateMemberRole",
14456
16580
  "tags": [
14457
16581
  "members"
@@ -14567,7 +16691,7 @@
14567
16691
  "/tools/setMemberActive": {
14568
16692
  "post": {
14569
16693
  "summary": "setMemberActive",
14570
- "description": "Soft-deactivate or reactivate an organisation member. Refuses self-deactivation, last-admin/owner deactivation, and deactivation of an owner. Rate limit 30/min.",
16694
+ "description": "Soft-deactivate or reactivate an organisation member. Refuses self-deactivation, last-admin/owner deactivation, and deactivation of an owner. Rate limit 30/min. Use when the user asks to deactivate, suspend, freeze, reactivate, or unfreeze a member without fully removing them.",
14571
16695
  "operationId": "setMemberActive",
14572
16696
  "tags": [
14573
16697
  "members"
@@ -14677,7 +16801,7 @@
14677
16801
  "/tools/removeMember": {
14678
16802
  "post": {
14679
16803
  "summary": "removeMember",
14680
- "description": "Hard-remove a member from an organisation, cascading to workspace and team memberships and resource permissions. Refuses self-removal and last-owner removal. Stripe seat downgrade is NOT performed here — pair with a Phase 6 billing tool. Rate limit 5/min.",
16804
+ "description": "Hard-remove a member from an organisation, cascading to workspace and team memberships and resource permissions. Refuses self-removal and last-owner removal. Stripe seat downgrade is NOT performed here — pair with a Phase 6 billing tool. Rate limit 5/min. Use when the user asks to remove, kick out, fire, offboard, or fully terminate a member's access to the organisation.",
14681
16805
  "operationId": "removeMember",
14682
16806
  "tags": [
14683
16807
  "members"
@@ -16122,7 +18246,7 @@
16122
18246
  "/tools/upsertResourcePermission": {
16123
18247
  "post": {
16124
18248
  "summary": "upsertResourcePermission",
16125
- "description": "Insert or update a resource_permissions row for a user OR team on a workspace/project/folder/document/improvement/plan. Refuses self-escalation. Rate limit 30/min.",
18249
+ "description": "Insert or update a resource_permissions row for a user OR team on a workspace/project/folder/document/improvement/plan. Refuses self-escalation. Rate limit 30/min. Use when the user asks to give access to, share with, grant access, add a permission, make accessible, or invite someone to a specific workspace/project/folder/document — i.e. resource-level access (not org-level membership; that's inviteMember).",
16126
18250
  "operationId": "upsertResourcePermission",
16127
18251
  "tags": [
16128
18252
  "permissions"
@@ -16373,7 +18497,7 @@
16373
18497
  "/tools/deleteResourcePermission": {
16374
18498
  "post": {
16375
18499
  "summary": "deleteResourcePermission",
16376
- "description": "Delete a resource_permissions row. Refuses if the row is the LAST admin grant on the resource. Rate limit 30/min.",
18500
+ "description": "Delete a resource_permissions row. Refuses if the row is the LAST admin grant on the resource. Rate limit 30/min. Use when the user asks to revoke access, remove access, take away access, unshare, or delete a permission grant on a specific resource.",
16377
18501
  "operationId": "deleteResourcePermission",
16378
18502
  "tags": [
16379
18503
  "permissions"
@@ -16604,7 +18728,7 @@
16604
18728
  "/tools/previewSubscriptionChange": {
16605
18729
  "post": {
16606
18730
  "summary": "previewSubscriptionChange",
16607
- "description": "Preview a subscription tier or seat change. Returns confirmation_token (10-min TTL) plus proration and next-invoice math. Cross-tier upgrades from Free return requires_checkout=true; the apply step creates a hosted Stripe Checkout session. Rate limit 30/h.",
18731
+ "description": "Preview a subscription tier or seat change. Returns confirmation_token (10-min TTL) plus proration and next-invoice math. Cross-tier upgrades from Free return requires_checkout=true; the apply step creates a hosted Stripe Checkout session. Rate limit 30/h. Use when the user asks to upgrade their plan (free→pro), downgrade, add seats, increase seats, or change subscription tier — ALWAYS call this preview first, then applySubscriptionChange with the returned token after the user confirms.",
16608
18732
  "operationId": "previewSubscriptionChange",
16609
18733
  "tags": [
16610
18734
  "billing"
@@ -16719,7 +18843,7 @@
16719
18843
  "/tools/applySubscriptionChange": {
16720
18844
  "post": {
16721
18845
  "summary": "applySubscriptionChange",
16722
- "description": "Apply a previously previewed subscription change. Same-tier seat changes update Stripe in place; cross-tier upgrades from Free return a hosted Checkout URL. Refuses target=free (use cancelSubscription) and target=enterprise (sales-led). Rate limit 5/h.",
18846
+ "description": "Apply a previously previewed subscription change. Same-tier seat changes update Stripe in place; cross-tier upgrades from Free return a hosted Checkout URL. Refuses target=free (use cancelSubscription) and target=enterprise (sales-led). Rate limit 5/h. Use only AFTER previewSubscriptionChange and after the user confirms the preview's pricing — never call apply without the user seeing the preview first.",
16723
18847
  "operationId": "applySubscriptionChange",
16724
18848
  "tags": [
16725
18849
  "billing"
@@ -16821,7 +18945,7 @@
16821
18945
  "/tools/previewSubscriptionCancellation": {
16822
18946
  "post": {
16823
18947
  "summary": "previewSubscriptionCancellation",
16824
- "description": "Preview the consequences of cancelling. Returns confirmation_token plus summary {remaining_credits, prepaid_days, prepaid_value_aud, feature_loss[], at_risk_seats}. Soft cancel only. Rate limit 30/h.",
18948
+ "description": "Preview the consequences of cancelling. Returns confirmation_token plus summary {remaining_credits, prepaid_days, prepaid_value_aud, feature_loss[], at_risk_seats}. Soft cancel only. Rate limit 30/h. Use when the user asks to cancel, end, or stop their subscription — ALWAYS call this first to show the cost of cancelling before passing the token to cancelSubscription.",
16825
18949
  "operationId": "previewSubscriptionCancellation",
16826
18950
  "tags": [
16827
18951
  "billing"
@@ -16923,7 +19047,7 @@
16923
19047
  "/tools/cancelSubscription": {
16924
19048
  "post": {
16925
19049
  "summary": "cancelSubscription",
16926
- "description": "Apply a previewed soft cancellation (cancel_at_period_end=true). Customer keeps full access until period end. Rate limit 5/h.",
19050
+ "description": "Apply a previewed soft cancellation (cancel_at_period_end=true). Customer keeps full access until period end. Rate limit 5/h. Use only AFTER previewSubscriptionCancellation and after the user confirms — never cancel without showing the preview first.",
16927
19051
  "operationId": "cancelSubscription",
16928
19052
  "tags": [
16929
19053
  "billing"
@@ -17025,7 +19149,7 @@
17025
19149
  "/tools/quoteCreditPackage": {
17026
19150
  "post": {
17027
19151
  "summary": "quoteCreditPackage",
17028
- "description": "Quote a credit-package purchase (first half of the human-in-the-loop ritual). Returns quote_token (10-min TTL) plus package + total_aud. Caller must invoke purchaseCreditPackage(quote_token) within the TTL.",
19152
+ "description": "Quote a credit-package purchase (first half of the human-in-the-loop ritual). Returns quote_token (10-min TTL) plus package + total_aud. Caller must invoke purchaseCreditPackage(quote_token) within the TTL. Use when the user asks to buy credits, purchase credits, top up credits, or add more credits — ALWAYS call this first then purchaseCreditPackage after the user confirms.",
17029
19153
  "operationId": "quoteCreditPackage",
17030
19154
  "tags": [
17031
19155
  "billing"
@@ -17132,7 +19256,7 @@
17132
19256
  "/tools/purchaseCreditPackage": {
17133
19257
  "post": {
17134
19258
  "summary": "purchaseCreditPackage",
17135
- "description": "Apply a credit-package quote by creating a hosted Stripe Checkout session. Returns checkout_url + session_id. Refuses if catalogued price has drifted. Rate limit 5/h.",
19259
+ "description": "Apply a credit-package quote by creating a hosted Stripe Checkout session. Returns checkout_url + session_id. Refuses if catalogued price has drifted. Rate limit 5/h. Use only AFTER quoteCreditPackage and after the user confirms — never start a checkout without the quote step first.",
17136
19260
  "operationId": "purchaseCreditPackage",
17137
19261
  "tags": [
17138
19262
  "billing"
@@ -17234,7 +19358,7 @@
17234
19358
  "/tools/reactivateSubscription": {
17235
19359
  "post": {
17236
19360
  "summary": "reactivateSubscription",
17237
- "description": "Reactivate a subscription that was scheduled to cancel at period end (clears cancel_at_period_end). Rate limit 5/h.",
19361
+ "description": "Reactivate a subscription that was scheduled to cancel at period end (clears cancel_at_period_end). Rate limit 5/h. Use when the user asks to reactivate, uncancel, restore, or keep their subscription after they previously cancelled but before the period ends.",
17238
19362
  "operationId": "reactivateSubscription",
17239
19363
  "tags": [
17240
19364
  "billing"