# Graph Report - /home/runner/work/fpt-mcp/fpt-mcp/src  (2026-06-24)

## Corpus Check
- 40 files · ~55,301 words
- Verdict: corpus is large enough that graph structure adds value.

## Summary
- 523 nodes · 1025 edges · 36 communities (31 shown, 5 thin omitted)
- Extraction: 97% EXTRACTED · 3% INFERRED · 0% AMBIGUOUS · INFERRED: 34 edges (avg confidence: 0.76)
- Token cost: 0 input · 0 output

## Community Hubs (Navigation)
- [[_COMMUNITY_chat_window|chat_window]]
- [[_COMMUNITY_search|search]]
- [[_COMMUNITY_app|app]]
- [[_COMMUNITY_launcher|launcher]]
- [[_COMMUNITY_claude_worker|claude_worker]]
- [[_COMMUNITY_tk_config|tk_config]]
- [[_COMMUNITY__session_stats|_session_stats]]
- [[_COMMUNITY_client|client]]
- [[_COMMUNITY_models|models]]
- [[_COMMUNITY_sg_find_one|sg_find_one]]
- [[_COMMUNITY_editorial|editorial]]
- [[_COMMUNITY_software_resolver|software_resolver]]
- [[_COMMUNITY_sg_create|sg_create]]
- [[_COMMUNITY_suggestions|suggestions]]
- [[_COMMUNITY_TkConfig|TkConfig]]
- [[_COMMUNITY_handler|handler]]
- [[_COMMUNITY_BulkDispatchInput|BulkDispatchInput]]
- [[_COMMUNITY_sg_batch|sg_batch]]
- [[_COMMUNITY_paths|paths]]
- [[_COMMUNITY_SgDownloadInput|SgDownloadInput]]
- [[_COMMUNITY_build_index|build_index]]
- [[_COMMUNITY_Any|Any]]
- [[_COMMUNITY_logging_config|logging_config]]
- [[_COMMUNITY_Path|Path]]
- [[_COMMUNITY__validate_entity_ref|_validate_entity_ref]]
- [[_COMMUNITY_sg_update|sg_update]]
- [[_COMMUNITY_BulkAction|BulkAction]]
- [[_COMMUNITY_filters|filters]]
- [[_COMMUNITY_SgSchemaInput|SgSchemaInput]]
- [[_COMMUNITY__sg_call|_sg_call]]
- [[_COMMUNITY_sg_find|sg_find]]
- [[_COMMUNITY_config|config]]
- [[_COMMUNITY_ami package|ami package]]
- [[_COMMUNITY_fpt_mcp package|fpt_mcp package]]
- [[_COMMUNITY_qt package|qt package]]
- [[_COMMUNITY_rag package|rag package]]

## God Nodes (most connected - your core abstractions)
1. `ChatWindow` - 25 edges
2. `get_sg()` - 22 edges
3. `_tok()` - 13 edges
4. `tk_publish_impl()` - 13 edges
5. `TkConfig` - 12 edges
6. `ClaudeWorker` - 11 edges
7. `TkConfigError` - 11 edges
8. `FPTApplication` - 10 edges
9. `sg_download_impl()` - 10 edges
10. `resolve_app()` - 10 edges

## Surprising Connections (you probably didn't know these)
- `fpt_launch_app_impl()` --calls--> `get_sg()`  [INFERRED]
  fpt_mcp/launcher.py → fpt_mcp/client.py
- `_project_id_for_entity()` --calls--> `get_sg()`  [INFERRED]
  fpt_mcp/launcher.py → fpt_mcp/client.py
- `_do_sg_delete()` --calls--> `get_sg()`  [INFERRED]
  fpt_mcp/shotgrid.py → fpt_mcp/client.py
- `sg_find_impl()` --calls--> `sg_find()`  [INFERRED]
  fpt_mcp/shotgrid.py → fpt_mcp/client.py
- `_toolkit_enrichment()` --calls--> `sg_find()`  [INFERRED]
  fpt_mcp/software_resolver.py → fpt_mcp/client.py

## Import Cycles
- None detected.

## Communities (36 total, 5 thin omitted)

### Community 0 - "chat_window"
Cohesion: 0.05
Nodes (33): QMainWindow, ChatWindow, _inline_fmt(), _md_to_html(), _ProjectDetector, Native Qt chat window for the FPT-MCP console.  Advantages over the HTML AMI con, Convert simple markdown to HTML for QTextBrowser.      Handles: **bold**, *itali, Apply inline markdown formatting. (+25 more)

### Community 1 - "search"
Cohesion: 0.09
Nodes (32): LearnPatternInput, SearchSgDocsInput, learn_pattern_impl(), rag_tools.py — bodies of search_sg_docs and learn_pattern.  Extracted from serve, Body of search_sg_docs_tool. See server.py for user-facing docstring., Body of learn_pattern_tool. See server.py for user-facing docstring., search_sg_docs_impl(), learn_pattern_tool() (+24 more)

### Community 2 - "app"
Cohesion: 0.11
Nodes (22): QApplication, QEvent, _enrich_with_entity_code(), fetch_ami_payload(), FPTApplication, _launch_log(), _load_sg_credentials(), main() (+14 more)

### Community 3 - "launcher"
Cohesion: 0.10
Nodes (26): BaseException, error_scrub.py — OPSEC-safe error-message sanitisation shared across the MCP eco, Redact credential-shaped values embedded in free text.      Replaces the *value*, Return a scrubbed, length-bounded string for *exc*.      Scrub FIRST, then trunc, safe_error_message(), scrub_secrets(), _compose_flame_direct(), _flame_running() (+18 more)

### Community 4 - "claude_worker"
Cohesion: 0.10
Nodes (22): build_backend_env(), capture_suggestions(), _find_claude(), _load_config(), log_usage(), _preload_ollama_mac_model(), project_env_override(), Background worker that runs Claude Code CLI and emits the response.  Runs in a Q (+14 more)

### Community 5 - "tk_config"
Cohesion: 0.12
Nodes (23): _build_from_config_path(), clear_cache(), context_from_path(), discover_config(), discover_or_fallback(), _get_bundle_cache_root(), _get_platform_path(), _match_template_path() (+15 more)

### Community 6 - "_session_stats"
Cohesion: 0.12
Nodes (22): datetime, _get_config(), _get_current_model(), _model_can_write(), Resolve the active model id.      Priority: FPT_MCP_RUNTIME_MODEL env var (set b, F0: ring-buffer (max 20) + best-effort enriched JSONL append for     cross-sessi, _track_timing(), apply_idle_reset() (+14 more)

### Community 7 - "client"
Cohesion: 0.12
Nodes (22): get_project_filter(), get_sg(), ShotGrid API client wrapper with async support.  Wraps shotgun_api3.Shotgun (syn, Return a cached ShotGrid connection (thread-safe singleton)., Return the project entity dict for filters. Uses PROJECT_ID from env., Async wrapper around sg.upload()., Async wrapper around sg.upload_thumbnail()., Async wrapper around sg.schema_field_read(). (+14 more)

### Community 8 - "models"
Cohesion: 0.16
Nodes (18): BaseModel, FptLaunchAppInput, models.py — Pydantic input models for every MCP tool.  Extracted from server.py, Input for ``fpt_bulk(action="editorial")``.      Deterministically build and cre, SgActivityInput, SgEditorialInput, SgNoteThreadInput, SgSummarizeInput (+10 more)

### Community 9 - "sg_find_one"
Cohesion: 0.15
Nodes (20): Async wrapper around sg.find_one()., sg_find_one(), TkResolvePathInput, Build the allowed-roots set: discovered ``project_root`` ∪ env allowlist.      A, resolve_allowed_roots(), _build_template_fields(), _get_tk_config(), Get or discover the TkConfig for the current project.      Returns TkConfig if t (+12 more)

### Community 10 - "editorial"
Cohesion: 0.15
Nodes (17): compute_editorial_cut(), editorial.py — deterministic Cut / CutItem timecode auto-calc.  PURE functions o, Compute the field dicts for one Cut and its ordered CutItems.      This is a PUR, SgDeleteInput, SgFindInput, SgReviveInput, _rag_skipped_warning(), Return a soft-warning dict if search_sg_docs has not been called yet     in this (+9 more)

### Community 11 - "software_resolver"
Cohesion: 0.16
Nodes (17): _flame_sort_key(), _os_scan(), _os_scan_flame(), _os_scan_maya(), _pick_fpt_version(), Software resolver — locate DCC applications on this machine and enrich them with, Scan the filesystem for Maya installs.      Returns a list of ``(binary, version, Scan the filesystem for Flame installs.      Returns ``(startApplication_path, v (+9 more)

### Community 12 - "sg_create"
Cohesion: 0.16
Nodes (14): Async wrapper around sg.create()., sg_create(), SgCreateInput, check_dangerous(), safety.py ========= Dangerous pattern detection for ShotGrid API operations.  Sc, Scan serialized tool parameters for dangerous patterns.      Args:         param, Create any entity in ShotGrid.      Works with ALL entity types. Project is auto, sg_create_tool() (+6 more)

### Community 13 - "suggestions"
Cohesion: 0.17
Nodes (14): Per-tool chaining hints emitted alongside normal tool responses.  Design doc: ``, Rule 4 — publish success → note_thread + sequence scope.      Trigger: ``id`` +, Rule 5 — successful soft-delete → offer revive as safety net.      Trigger: ``de, Kill switch for the whole feature. Set FPT_MCP_DISABLE_SUGGESTIONS=1     to emit, One chaining hint. Keys match the schema in the design doc §3.1., Rule 1 + 2 from design doc §5.      - Asset rows with non-empty ``image`` → sg_d, Rule 3 — downloaded image file → maya_vision3d(generate_image).      Trigger: ``, _suggest_after_fpt_bulk() (+6 more)

### Community 14 - "TkConfig"
Cohesion: 0.18
Nodes (8): Get a resolved template string by name, with aliases expanded., List all templates, optionally filtered by pattern in name., Resolve a template to a full filesystem path.          Args:             templat, Find the next available version number by scanning the filesystem.          Reso, Resolved Toolkit configuration for a specific project.      Lazily loads and cac, Parse templates.yml paths section into resolved template strings., Expand @alias references in a template string.          Example: '@asset_root/pu, TkConfig

### Community 15 - "handler"
Cohesion: 0.20
Nodes (6): AMIHandler, AMI (Action Menu Item) HTTP handler for ShotGrid.  Receives AMI requests from Sh, Receives AMI requests and launches the Qt console., Launch the Qt console app with entity context., Extract AMI params from query string., BaseHTTPRequestHandler

### Community 16 - "BulkDispatchInput"
Cohesion: 0.15
Nodes (14): BulkDispatchInput, Input for the fpt_bulk dispatch tool., Input for the fpt_reporting dispatch tool., ReportingDispatchInput, _count_turn(), fpt_bulk(), fpt_reporting(), Idle-gap auto-reset of _stats. Called at dispatcher + RAG/stats entry. (+6 more)

### Community 17 - "sg_batch"
Cohesion: 0.22
Nodes (10): Async wrapper around sg.batch(). Transactional — all or nothing., sg_batch(), SgBatchInput, SgUploadInput, Upload a file to any entity field in ShotGrid.      Use field_name='image' for t, sg_upload_tool(), _do_sg_batch(), Body of sg_upload_tool. (+2 more)

### Community 18 - "paths"
Cohesion: 0.21
Nodes (10): Exception, enforce_write_containment(), ensure_within_roots(), is_strict_paths(), PathContainmentError, paths.py — write-path containment guard for the file-writing tools.  Two MCP too, Return the realpath of *candidate* if it lies inside one of *roots*.      Both t, Apply the WARN/STRICT containment policy to a write destination.      This is th (+2 more)

### Community 19 - "SgDownloadInput"
Cohesion: 0.18
Nodes (12): SgDownloadInput, TkPublishInput, fpt_launch_app_tool(), Rough token estimate: 1 token ≈ 3 characters., Download an attachment from any entity field in ShotGrid., Publish a file to ShotGrid.      Two modes:     - With PipelineConfiguration: re, Launch a DCC application scoped to a ShotGrid entity.      Discovery is OS-first, sg_download_tool() (+4 more)

### Community 20 - "build_index"
Cohesion: 0.24
Nodes (11): build(), chunk_markdown(), collect_docs(), _load_config(), _make_embedding_fn(), _method_group_chunks(), build_index.py ============== Indexes ShotGrid API documentation into a local Ch, Split a markdown file into chunks by ## headers, with method sub-chunking. (+3 more)

### Community 21 - "Any"
Cohesion: 0.27
Nodes (7): Any, Download an attachment or thumbnail URL from ShotGrid.      Handles two cases:, Async wrapper around sg.note_thread_read(). Returns full reply thread., sg_download_attachment(), sg_note_thread_read(), _coerce_to_json_str(), Normalise a JSON-as-string field that may arrive as a native value.      Several

### Community 22 - "logging_config"
Cohesion: 0.31
Nodes (8): configure_logging(), get_logger(), logging_config.py — rotating-file logging for the fpt-mcp tool boundary.  Before, Return the log directory, honoring ``FPT_MCP_LOG_DIR`` if set., Install the rotating file handler on the ``fpt_mcp`` logger (idempotent).      R, Return a child logger under the configured ``fpt_mcp`` root., _resolve_log_dir(), Logger

### Community 23 - "Path"
Cohesion: 0.31
Nodes (8): enforce_read_containment(), _is_sensitive_source(), Return ``True`` when *real* (an already-``realpath``'d path) is a known     cred, Guard the copy/read SOURCE of ``tk_publish`` against credential exfil.      Unli, Path, build_bundle(), main(), Create the .app bundle and return its path.

### Community 24 - "_validate_entity_ref"
Cohesion: 0.25
Nodes (6): EditorialCutSpec, EditorialShot, Cut-level spec for ``fpt_bulk(action="editorial")``.      Describes the Cut enti, One ordered shot entry for ``fpt_bulk(action="editorial")``.      List position, Validate a ShotGrid entity reference dict (``{"type": ..., "id": ...}``).      R, _validate_entity_ref()

### Community 25 - "sg_update"
Cohesion: 0.33
Nodes (7): Async wrapper around sg.update()., sg_update(), SgUpdateInput, Update any entity's fields in ShotGrid., sg_update_tool(), Body of sg_update_tool., sg_update_impl()

### Community 26 - "BulkAction"
Cohesion: 0.40
Nodes (6): Enum, BulkAction, Actions available in the fpt_bulk dispatch tool., Actions available in the fpt_reporting dispatch tool., ReportingAction, str

### Community 27 - "filters"
Cohesion: 0.40
Nodes (3): filters.py — ShotGrid filter validation and safety constants.  Extracted from se, C.3 — structural validation for ShotGrid filter lists.      Walks every filter a, _validate_filter_triples()

### Community 28 - "SgSchemaInput"
Cohesion: 0.50
Nodes (5): SgSchemaInput, Get the field schema for any ShotGrid entity type.      Returns field names, typ, sg_schema_tool(), Body of sg_schema_tool., sg_schema_impl()

### Community 29 - "_sg_call"
Cohesion: 0.50
Nodes (4): Run one ShotGrid SDK call under the shared-connection lock with logging.      Th, _sg_call(), Recursively redact credential-shaped keys and truncate long values.      A log f, sanitize_for_log()

### Community 30 - "sg_find"
Cohesion: 0.50
Nodes (4): Async wrapper around sg.find()., sg_find(), Query the SG ``Software`` entity for the given engine.      Prefers rows with a, _sg_software_enrichment()

## Knowledge Gaps
- **5 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.

## Suggested Questions
_Questions this graph is uniquely positioned to answer:_

- **Why does `ChatWindow` connect `chat_window` to `app`?**
  _High betweenness centrality (0.124) - this node is a cross-community bridge._
- **Why does `ClaudeWorker` connect `chat_window` to `claude_worker`?**
  _High betweenness centrality (0.105) - this node is a cross-community bridge._
- **Why does `_make_embedding_fn()` connect `build_index` to `Any`?**
  _High betweenness centrality (0.039) - this node is a cross-community bridge._
- **Are the 3 inferred relationships involving `ChatWindow` (e.g. with `FPTApplication` and `PayloadFetcher`) actually correct?**
  _`ChatWindow` has 3 INFERRED edges - model-reasoned connections that need verification._
- **Are the 3 inferred relationships involving `get_sg()` (e.g. with `fpt_launch_app_impl()` and `_project_id_for_entity()`) actually correct?**
  _`get_sg()` has 3 INFERRED edges - model-reasoned connections that need verification._
- **What connects `FPT MCP Server — Flow Production Tracking (ShotGrid) integration for Claude Desk`, `_session_stats.py ================= Per-session reset machinery + F0 telemetry f`, `Return a freshly initialised `_stats` dict.      Kept in sync with the module-le` to the rest of the system?**
  _226 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `chat_window` be split into smaller, more focused modules?**
  _Cohesion score 0.05454545454545454 - nodes in this community are weakly interconnected._