Skip to main content

post_cortex_daemon/daemon/mcp_service/
requests.rs

1// Copyright (c) 2025, 2026 Julius ML
2// MIT License
3
4//! Request payload structs for the 9 consolidated MCP tools.
5//!
6//! All schemars-decorated fields are kept verbatim so the JSON Schema that
7//! `#[tool(input_schema = ...)]` emits matches the previous monolith — clients
8//! see the same hints.
9
10use schemars::JsonSchema;
11use serde::Deserialize;
12
13// =============================================================================
14// Tool 7: assemble_context
15// =============================================================================
16
17/// Request payload for the `assemble_context` tool.
18#[derive(Deserialize, JsonSchema, Debug)]
19pub struct AssembleContextRequest {
20    /// Optional session UUID; ignored when `workspace_id` is set.
21    #[schemars(
22        description = r#"Session UUID. Required when workspace_id is not provided.
23
24Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
25
26Note: If both session_id and workspace_id are provided, workspace_id takes precedence
27(context is merged across all sessions in the workspace)."#
28    )]
29    pub session_id: Option<String>,
30    /// Optional workspace UUID; takes precedence over `session_id`.
31    #[schemars(
32        description = r#"Workspace UUID. When provided, context is merged across all sessions in the workspace.
33
34Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
35
36Note: Takes precedence over session_id."#
37    )]
38    pub workspace_id: Option<String>,
39    /// Query topic used to seed entity extraction and graph traversal.
40    #[schemars(description = r#"The query/topic to assemble context for.
41
42Example: "How does authentication interact with the user profile service?"
43
44Note: Entity extraction runs on this query to seed graph traversal."#)]
45    pub query: String,
46    /// Maximum token budget for assembled context output.
47    #[schemars(
48        description = r#"Token budget for the assembled context (default: 4000).
49
50Examples:
51- 2000: tight context window
52- 4000: default (matches Axon's per-call budget)
53- 8000: extended chains / orchestration
54
55Note: Must be > 0. Items are packed highest-score-first until budget is consumed."#
56    )]
57    pub token_budget: Option<u32>,
58}
59
60// =============================================================================
61// Tool 8: manage_entity
62// =============================================================================
63
64/// Request payload for the `manage_entity` tool.
65#[derive(Deserialize, JsonSchema, Debug)]
66pub struct ManageEntityRequest {
67    /// Entity management action (`delete` or `delete_update`).
68    #[schemars(description = r#"Action to perform on session content.
69
70Valid values:
71- delete: Remove an entity from the session (cascades typed edges). Requires entity_name.
72- delete_update: Remove a single context update (ghost / bad row) by entry_id. Requires entry_id.
73
74Note: Must be lowercase. Additional actions may be added later."#)]
75    pub action: String,
76    /// Session UUID that contains the target entity or update.
77    #[schemars(description = r#"Session UUID containing the entity/update.
78
79Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"#)]
80    pub session_id: String,
81    /// Entity name for the `delete` action.
82    #[schemars(
83        description = r#"Entity name to operate on (required for action=delete).
84
85Example: "RocksDB"
86
87Note: Names are matched case-insensitively in the entity graph."#
88    )]
89    pub entity_name: Option<String>,
90    /// Context-update ID for the `delete_update` action.
91    #[schemars(
92        description = r#"Context-update id (required for action=delete_update).
93
94Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
95
96Note: This is the `entry_id` returned by `assemble_context` items, or the id of a
97ContextUpdate stored in the session. Use it to remove ghost / mis-shaped writes."#
98    )]
99    pub entry_id: Option<String>,
100}
101
102// =============================================================================
103// Tool 9: admin
104// =============================================================================
105
106/// Request payload for the `admin` tool.
107#[derive(Deserialize, JsonSchema, Debug)]
108pub struct AdminRequest {
109    /// Administrative action (`health`, `vectorize_session`, `vectorize_stats`, `create_checkpoint`).
110    #[schemars(description = r#"Administrative action on the Post-Cortex daemon.
111
112Valid values:
113- health: Report daemon health (active sessions, embeddings status, version)
114- vectorize_session: Backfill embeddings for an existing session (requires session_id)
115- vectorize_stats: Return embedding-pipeline statistics as JSON
116- create_checkpoint: Persist a snapshot of a session for later recall (requires session_id)
117
118Examples:
119✅ {"action": "health"}
120✅ {"action": "vectorize_session", "session_id": "60c598e2-..."}
121✅ {"action": "vectorize_stats"}
122✅ {"action": "create_checkpoint", "session_id": "60c598e2-..."}
123
124Note: Must be lowercase."#)]
125    pub action: String,
126    /// Session UUID for actions that target a specific session.
127    #[schemars(
128        description = r#"Session UUID for vectorize_session and create_checkpoint.
129
130Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"#
131    )]
132    pub session_id: Option<String>,
133}
134
135// =============================================================================
136// Tool 1: session
137// =============================================================================
138
139/// Request payload for the `session` tool.
140#[derive(Deserialize, JsonSchema, Debug)]
141pub struct SessionRequest {
142    /// Session management action (`create`, `list`, `load`, `search`, `update_metadata`, `delete`).
143    #[schemars(description = r#"Action to perform on sessions.
144
145Valid values:
146- create: Create a new session and return a UUID (optional: name, description)
147- list: List all existing sessions
148- load: Load metadata for a single session (requires session_id)
149- search: Find sessions by name or description substring (requires query)
150- update_metadata: Update session name and/or description (requires session_id; provide name and/or description)
151- delete: Permanently delete a session and its updates (requires session_id)
152
153Examples:
154✅ {"action": "create", "name": "Auth", "description": "OAuth2 work"}
155✅ {"action": "load", "session_id": "60c598e2-..."}
156✅ {"action": "search", "query": "auth"}
157✅ {"action": "update_metadata", "session_id": "60c598e2-...", "name": "New name"}
158✅ {"action": "delete", "session_id": "60c598e2-..."}
159
160Note: Must be lowercase."#)]
161    pub action: String,
162    /// Session name (used by `create` and `update_metadata`).
163    #[schemars(description = r#"Session name (used by create and update_metadata).
164
165Examples:
166- "Feature: Authentication"
167- "Bug Fix: Memory Leak"
168
169Note: For update_metadata, only provided fields are changed."#)]
170    pub name: Option<String>,
171    /// Session description (used by `create` and `update_metadata`).
172    #[schemars(
173        description = r#"Session description (used by create and update_metadata).
174
175Example: "Working on implementing OAuth2 login flow"
176
177Note: For update_metadata, only provided fields are changed."#
178    )]
179    pub description: Option<String>,
180    /// Session UUID (required for `load`, `update_metadata`, `delete`).
181    #[schemars(
182        description = r#"Session UUID (required for load, update_metadata, delete).
183
184Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
185
186Example: "60c598e2-d602-4e07-a328-c458006d48c7""#
187    )]
188    pub session_id: Option<String>,
189    /// Search query for the `search` action.
190    #[schemars(description = r#"Search query for the search action.
191
192Examples:
193- "authentication"
194- "image pipeline"
195
196Note: Matches session name or description (case-insensitive substring)."#)]
197    pub query: Option<String>,
198}
199
200// =============================================================================
201// Tool 2: update_conversation_context (single + bulk)
202// =============================================================================
203
204/// Single context-update item used in bulk mode.
205#[derive(Deserialize, JsonSchema, Debug, Clone)]
206pub struct ContextUpdateItem {
207    /// Interaction type classifier (e.g., `qa`, `decision_made`).
208    #[schemars(description = r#"Type of interaction (must be exact lowercase value).
209
210Valid values:
211- qa: Questions and answers about the codebase
212- decision_made: Architectural decisions and trade-offs
213- problem_solved: Bug fixes and solutions to technical problems
214- code_change: Code modifications and refactoring
215- requirement_added: New requirements or constraints
216- concept_defined: Technical concepts and patterns explained
217
218Examples:
219✅ "decision_made" (correct)
220❌ "DecisionMade" (wrong - must be lowercase)
221❌ "made_decision" (wrong - use exact term)"#)]
222    pub interaction_type: String,
223    /// Key-value content payload for the update.
224    #[schemars(
225        description = r#"Content as key-value pairs (all values must be strings).
226
227Format: HashMap<String, String> where both keys and values are strings.
228
229Examples:
230Simple: {"decision": "Use Rust", "rationale": "Performance"}
231Complex: {"criteria": "{\"performance\": 9, \"safety\": 10}", "date": "2025-01-12"}
232
233Note: For complex nested data, stringify as JSON first. Do not pass nested objects directly."#
234    )]
235    pub content: std::collections::HashMap<String, String>,
236    /// Named entities mentioned in this update. Required by the canonical
237    /// write path so the entity graph is never silently empty.
238    #[serde(default)]
239    #[schemars(description = r#"Named entities mentioned in this update.
240
241Each entry: {"name": "<unique name>", "entity_type": "concept|technology|problem|solution|decision|code_component"}.
242Required (must contain at least one entity) so the entity graph captures every write."#)]
243    pub entities: Vec<post_cortex_mcp::EntityItem>,
244    /// Relations between the entities listed above.
245    #[serde(default)]
246    #[schemars(description = r#"Relations between the entities listed above.
247
248Each entry: {"from_entity": "<name>", "to_entity": "<name>", "relation_type": "depends_on|implements|caused_by|leads_to|related_to|required_by|conflicts_with|solves", "context": "<short why>"}.
249Required (must contain at least one relation). Both endpoints must appear in the `entities` array; self-relations and dangling references are rejected with InvalidArgument."#)]
250    pub relations: Vec<post_cortex_mcp::RelationItem>,
251    /// Optional code location reference.
252    #[schemars(description = r#"Optional code reference for context.
253
254Can be a simple string or complex object:
255
256Examples:
257- Simple: "src/main.rs:42"
258- Complex: {"file": "src/main.rs", "line": 42, "function": "process_data"}
259
260Note: Helps link context to specific code locations."#)]
261    pub code_reference: Option<serde_json::Value>,
262}
263
264/// Request payload for the `update_conversation_context` tool.
265#[derive(Deserialize, JsonSchema, Debug)]
266pub struct UpdateConversationContextRequest {
267    /// Session UUID to add context to.
268    #[schemars(description = r#"Session ID (36-char UUID format with hyphens).
269
270Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
271
272How to get:
2731. Create session: Use session tool with action='create'
2742. Find session: Use semantic_search to search for previous sessions
275
276Example: "60c598e2-d602-4e07-a328-c458006d48c7"
277
278Note: Must be a string, not a number. UUIDs are always strings."#)]
279    pub session_id: String,
280    /// Interaction type for single-update mode.
281    #[schemars(
282        description = r#"Type of interaction for single update (must be exact lowercase value).
283
284Valid values:
285- qa: Questions and answers about the codebase
286- decision_made: Architectural decisions and trade-offs
287- problem_solved: Bug fixes and solutions to technical problems
288- code_change: Code modifications and refactoring
289- requirement_added: New requirements or constraints
290- concept_defined: Technical concepts and patterns explained
291
292Note: Required for single update mode (when 'updates' array is not provided)."#
293    )]
294    pub interaction_type: Option<String>,
295    /// Key-value content for single-update mode.
296    #[schemars(
297        description = r#"Content as key-value pairs for single update (all values must be strings).
298
299Format: HashMap<String, String> where both keys and values are strings.
300
301Examples:
302Simple: {"decision": "Use Rust", "rationale": "Performance"}
303Complex: {"criteria": "{\"performance\": 9}", "date": "2025-01-12"}
304
305Note: For complex nested data, stringify as JSON first. Required for single update mode."#
306    )]
307    pub content: Option<std::collections::HashMap<String, String>>,
308    /// Named entities mentioned in this update (single-update mode).
309    /// Required by the canonical write path.
310    #[serde(default)]
311    #[schemars(description = r#"Named entities mentioned in this update.
312
313Each entry: {"name": "<unique name>", "entity_type": "concept|technology|problem|solution|decision|code_component"}.
314Required (must contain at least one entity) so the entity graph captures every write."#)]
315    pub entities: Vec<post_cortex_mcp::EntityItem>,
316    /// Relations between the entities listed above (single-update mode).
317    #[serde(default)]
318    #[schemars(description = r#"Relations between the entities listed above.
319
320Each entry: {"from_entity": "<name>", "to_entity": "<name>", "relation_type": "depends_on|implements|caused_by|leads_to|related_to|required_by|conflicts_with|solves", "context": "<short why>"}.
321Required (must contain at least one relation). Both endpoints must appear in the `entities` array; self-relations and dangling references are rejected with InvalidArgument."#)]
322    pub relations: Vec<post_cortex_mcp::RelationItem>,
323    /// Optional code reference for single-update mode.
324    #[schemars(description = r#"Optional code reference for single update.
325
326Can be a simple string or complex object:
327
328Examples:
329- Simple: "src/main.rs:42"
330- Complex: {"file": "src/main.rs", "line": 42, "function": "process_data"}"#)]
331    pub code_reference: Option<serde_json::Value>,
332    /// Bulk update array; overrides single-update fields when present.
333    #[schemars(
334        description = r#"Array of updates for bulk operation (overrides single fields if provided).
335
336Use this mode to add multiple updates at once.
337
338Format: Array of objects, each with interaction_type and content.
339
340Example:
341{
342  "session_id": "60c598e2-d602-4e07-a328-c458006d48c7",
343  "updates": [
344    {
345      "interaction_type": "decision_made",
346      "content": {"decision": "Use Rust", "rationale": "Performance"}
347    },
348    {
349      "interaction_type": "code_change",
350      "content": {"file": "main.rs", "change": "Add error handling"}
351    }
352  ]
353}
354
355Note: When provided, 'interaction_type' and 'content' fields are ignored."#
356    )]
357    pub updates: Option<Vec<ContextUpdateItem>>,
358    /// Validate without persisting when `true`.
359    #[schemars(
360        description = r#"If true, validate the request without making any changes.
361
362When dry_run is true, the request will be validated and a preview of what would happen will be returned, but no data will be stored.
363
364Use cases:
365- Test if your request format is correct
366- Preview what would be stored
367- Validate interaction_type and content structure
368- Check if session exists
369
370Example: {"dry_run": true, "session_id": "...", "interaction_type": "decision_made", "content": {...}}
371
372Note: No changes are made to the session when dry_run is true."#
373    )]
374    pub dry_run: Option<bool>,
375}
376
377// =============================================================================
378// Tool 3: semantic_search (unified)
379// =============================================================================
380
381/// Request payload for the `semantic_search` tool.
382#[derive(Deserialize, JsonSchema, Debug)]
383pub struct SemanticSearchRequest {
384    /// Natural-language search query.
385    #[schemars(description = r#"Search query for semantic search.
386
387Examples:
388- "How did we handle authentication?"
389- "What were the performance issues?"
390- "decision_made API design"
391
392Note: Natural language queries work best. The search understands context."#)]
393    pub query: String,
394    /// Search scope (`session`, `workspace`, or `global`).
395    #[schemars(
396        description = r#"Search scope: 'session', 'workspace', or 'global' (default: 'global').
397
398Valid values:
399- session: Search within a specific session (requires scope_id)
400- workspace: Search within a workspace (requires scope_id)
401- global: Search across all data (default, no scope_id needed)
402
403Examples:
404✅ {"query": "performance", "scope": "global"} (default, searches everywhere)
405✅ {"query": "auth", "scope": "session", "scope_id": "60c598e2-d602-4e07-a328-c458006d48c7"} (search specific session)
406✅ {"query": "API", "scope": "workspace", "scope_id": "f1d2e3a4-b5c6-7d8e-9f0a-1b2c3d4e5f6f"} (search specific workspace)
407
408Note: scope must be lowercase. When using 'session' or 'workspace', you must provide scope_id."#
409    )]
410    pub scope: Option<String>,
411    /// UUID identifying the session or workspace to search.
412    #[schemars(
413        description = r#"Session ID or Workspace ID (required when scope is 'session' or 'workspace').
414
415Format: 36-char UUID string (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
416
417When to use:
418- Required when scope='session' (provide session UUID)
419- Required when scope='workspace' (provide workspace UUID)
420- Ignored when scope='global' or not specified
421
422Examples:
423✅ {"scope": "session", "scope_id": "60c598e2-d602-4e07-a328-c458006d48c7"} (correct)
424❌ {"scope": "session"} (missing scope_id - will error)
425❌ {"scope": "global", "scope_id": "..."} (scope_id ignored for global)
426
427Note: Must be a valid UUID string. Use 'session' or 'semantic_search' tools to find UUIDs."#
428    )]
429    pub scope_id: Option<String>,
430    /// Maximum number of results to return.
431    #[schemars(
432        description = r#"Maximum number of results to return (default: 10, max: 100).
433
434Examples:
435- 5: Return top 5 most relevant results
436- 20: Return top 20 results
437- null or omit: Use default of 10
438
439Note: Higher values may slow down search. Maximum allowed is 100."#
440    )]
441    pub limit: Option<usize>,
442    /// ISO 8601 lower bound for date filtering.
443    #[schemars(
444        description = r#"Filter results from this date onwards (ISO 8601 format).
445
446Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ
447
448Examples:
449- "2025-01-01": Results from January 1st, 2025 onwards
450- "2025-01-15T10:00:00Z": Results from January 15th, 2025 at 10am UTC onwards
451
452Note: Use with date_to to specify a date range."#
453    )]
454    pub date_from: Option<String>,
455    /// ISO 8601 upper bound for date filtering.
456    #[schemars(description = r#"Filter results up to this date (ISO 8601 format).
457
458Format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ
459
460Examples:
461- "2025-01-31": Results up to January 31st, 2025
462- "2025-01-15T10:00:00Z": Results up to January 15th, 2025 at 10am UTC
463
464Note: Use with date_from to specify a date range."#)]
465    pub date_to: Option<String>,
466    /// Filter results to these interaction types.
467    #[schemars(description = r#"Filter by interaction types (array of strings).
468
469Valid types:
470- qa: Questions and answers
471- decision_made: Architectural decisions
472- problem_solved: Bug fixes and solutions
473- code_change: Code modifications
474- requirement_added: New requirements
475- concept_defined: Technical concepts
476
477Examples:
478- ["decision_made"]: Only show decisions
479- ["decision_made", "problem_solved"]: Show decisions and solutions
480- null or omit: Show all interaction types
481
482Note: Must be exact lowercase values. Filters reduce results to only these types."#)]
483    pub interaction_type: Option<Vec<String>>,
484    /// Temporal decay factor favouring recent content.
485    #[schemars(
486        description = r#"Temporal decay factor to prioritize recent content (default: 0.0 = disabled).
487
488Valid values:
489- 0.0: Disabled - pure relevance ranking (default, backward compatible)
490- 0.1 - 0.5: Soft bias toward recent content
491- 0.5 - 1.0: Moderate bias toward recent content
492- 1.0+: Aggressive bias toward recent content
493
494How it works:
495- Uses exponential decay: score × e^(-λ × days/365)
496- Older content gets progressively lower scores
497- Fresh content (1 day) retains ~99.9% score at λ=0.5
498- Year-old content retains ~60.6% score at λ=0.5, ~36.8% at λ=1.0
499
500When to use:
501- Debugging recent issues: 0.5 - 1.0
502- Finding latest solutions: 0.3 - 0.7
503- Architecture docs (timeless): 0.0 or omit
504- Current context: 1.0+
505
506Examples:
507✅ {"query": "timeout error", "recency_bias": 0.5} (recent bugs prioritized)
508✅ {"query": "authentication", "recency_bias": 0.0} (all docs equal)
509✅ {"query": "performance", "recency_bias": 1.0} (very recent)
510
511Note: Only affects ranking order, doesn't filter out old results."#
512    )]
513    pub recency_bias: Option<f32>,
514}
515
516// =============================================================================
517// Tool 4: get_structured_summary (extended)
518// =============================================================================
519
520/// Request payload for the `get_structured_summary` tool.
521#[derive(Deserialize, JsonSchema, Debug)]
522pub struct GetStructuredSummaryRequest {
523    /// Session UUID to summarize.
524    #[schemars(description = "Session ID")]
525    pub session_id: String,
526    /// Sections to include (`decisions`, `insights`, `entities`, `all`).
527    #[schemars(
528        description = "Sections to include: decisions, insights, entities, all (default: all)"
529    )]
530    pub include: Option<Vec<String>>,
531    /// Maximum number of decisions to include.
532    #[schemars(description = "Maximum decisions to include")]
533    pub decisions_limit: Option<usize>,
534    /// Maximum number of entities to include.
535    #[schemars(description = "Maximum entities to include")]
536    pub entities_limit: Option<usize>,
537    /// Maximum number of questions to include.
538    #[schemars(description = "Maximum questions to include")]
539    pub questions_limit: Option<usize>,
540    /// Maximum number of concepts to include.
541    #[schemars(description = "Maximum concepts to include")]
542    pub concepts_limit: Option<usize>,
543    /// Minimum confidence level for included items.
544    #[schemars(description = "Minimum confidence level")]
545    pub min_confidence: Option<f32>,
546    /// Whether to use compact output format.
547    #[schemars(description = "Use compact format for large sessions")]
548    pub compact: Option<bool>,
549}
550
551// =============================================================================
552// Tool 5: query_conversation_context
553// =============================================================================
554
555/// Request payload for the `query_conversation_context` tool.
556#[derive(Deserialize, JsonSchema, Debug)]
557pub struct QueryConversationContextRequest {
558    /// Session UUID to query.
559    #[schemars(description = "Session ID")]
560    pub session_id: String,
561    /// Query type selector.
562    #[schemars(
563        description = "Query type. Supported: find_related_entities, get_entity_context, search_updates, entity_importance, entity_network, find_related_content (topic, max_results), key_decisions, key_insights (limit), session_statistics, structured_summary, decisions, open_questions, related_entities, all_entities, trace_relationships, get_most_important_entities, get_recently_mentioned_entities, analyze_entity_importance, find_entities_by_type, assemble_context, recent_changes, code_references."
564    )]
565    pub query_type: String,
566    /// Key-value query parameters.
567    #[schemars(description = "Query parameters as key-value pairs")]
568    pub parameters: std::collections::HashMap<String, String>,
569}
570
571// =============================================================================
572// Tool 6: manage_workspace
573// =============================================================================
574
575/// Request payload for the `manage_workspace` tool.
576#[derive(Deserialize, JsonSchema, Debug)]
577pub struct ManageWorkspaceRequest {
578    /// Workspace action (`create`, `list`, `get`, `delete`, `add_session`, `remove_session`).
579    #[schemars(description = r#"Action to perform on workspaces.
580
581Valid values:
582- create: Create a new workspace (requires name and description)
583- list: List all workspaces
584- get: Get workspace details (requires workspace_id)
585- delete: Delete a workspace (requires workspace_id)
586- add_session: Add a session to workspace (requires workspace_id, session_id, optional role)
587- remove_session: Remove a session from workspace (requires workspace_id, session_id)
588
589Examples:
590✅ {"action": "create", "name": "Auth Feature", "description": "OAuth2 work"}
591✅ {"action": "get", "workspace_id": "f1d2e3a4-..."}
592✅ {"action": "add_session", "workspace_id": "...", "session_id": "...", "role": "primary"}
593
594Note: Must be lowercase. Different actions require different parameters."#)]
595    pub action: String,
596    /// Workspace UUID for actions that target a specific workspace.
597    #[schemars(
598        description = r#"Workspace ID (36-char UUID) for get/delete/add_session/remove_session actions.
599
600Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
601
602When to use:
603- Required for: get, delete, add_session, remove_session
604- Not used for: create, list
605
606How to get:
607- Use manage_workspace with action='list' to see all workspaces
608- Use semantic_search to find workspaces by name
609
610Example: "f1d2e3a4-b5c6-7d8e-9f0a-1b2c3d4e5f6f"
611
612Note: Must be a valid UUID string. Not a number."#
613    )]
614    pub workspace_id: Option<String>,
615    /// Session UUID for `add_session`/`remove_session`.
616    #[schemars(
617        description = r#"Session ID (36-char UUID) for add_session/remove_session actions.
618
619Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
620
621When to use:
622- Required for: add_session, remove_session
623- Not used for: create, list, get, delete
624
625How to get:
626- Use session tool with action='list' to see all sessions
627- Use semantic_search to find sessions
628
629Example: "60c598e2-d602-4e07-a328-c458006d48c7"
630
631Note: Must be a valid UUID string. Not a number."#
632    )]
633    pub session_id: Option<String>,
634    /// Workspace name (used by `create`).
635    #[schemars(description = r#"Workspace name (for create action).
636
637Example: "Authentication Feature" or "API Design"
638
639Note: Only used when action='create'. Helps identify the workspace."#)]
640    pub name: Option<String>,
641    /// Workspace description (used by `create`).
642    #[schemars(description = r#"Workspace description (for create action).
643
644Example: "Working on OAuth2 authentication and user management"
645
646Note: Only used when action='create'. Provides context for the workspace."#)]
647    pub description: Option<String>,
648    /// Session role within the workspace (used by `add_session`).
649    #[schemars(
650        description = r#"Session role in workspace (for add_session action, default: 'related').
651
652Valid values:
653- primary: Main session for this workspace
654- related: Related context session
655- dependency: Required dependency session
656- shared: Shared reference session
657
658Examples:
659✅ {"action": "add_session", "workspace_id": "...", "session_id": "...", "role": "primary"}
660✅ {"action": "add_session", "workspace_id": "...", "session_id": "...", "role": "related"}
661✅ {"action": "add_session", "workspace_id": "...", "session_id": "..."} (defaults to "related")
662
663Note: Only used when action='add_session'. Defaults to 'related' if omitted."#
664    )]
665    pub role: Option<String>,
666}