# 01 — Arquitetura do Sistema (G-ART / fcp-mcp-server) > **Escopo:** Como o sistema é dividido em camadas e onde cada responsabilidade mora. > **Não cobre:** Detalhe módulo a módulo (→ 02) · ferramentas MCP (→ 03) · app (→ 08) > Referência canônica de como o sistema está dividido. Leia antes de qualquer > mudança de código. Se algo aqui divergir do código, **o código está certo e > este documento está velho** — corrija-o no mesmo commit. Última varredura: 2026-08-19 · 77 ferramentas MCP · 1.498 testes · versão `0.6.35` --- ## 1. Visão de cima (camadas) O sistema lê, analisa e reescreve **FCPXML** do Final Cut Pro. Ele opera *fora* do FCP: você exporta o XML, o programa processa como dados estruturados e devolve um XML para importar. Nada é patcheado, nenhuma API privada é usada. São **quatro camadas**, e o ponto importante é que existem **duas portas de entrada diferentes** para o mesmo motor: ``` ┌──────────────────────────┐ ┌──────────────────────────────┐ │ MacApp/ (SwiftUI) │ │ Cliente MCP (Claude) │ │ O app que o usuário usa │ │ Conversa, decide a edição │ └───────────┬──────────────┘ └───────────────┬──────────────┘ │ subprocesso + JSON-lines │ JSON-RPC (stdio) ▼ ▼ ┌──────────────────────────┐ ┌──────────────────────────────┐ │ admin/models_api.py │ │ server.py + server_tools/ │ │ + admin/api/ │ │ 77 tools, dispatch, schemas │ │ 37 comandos da ponte │ │ NÃO tem lógica de timeline │ └───────────┬──────────────┘ └───────────────┬──────────────┘ └───────────────┬────────────────────┘ ▼ ┌───────────────────────────────────┐ │ fcpxml/ — O ENGINE │ │ Núcleo puro Python, desacoplado. │ │ Não conhece MCP nem o app. │ │ É onde quase tudo mora. │ └───────────────────────────────────┘ ``` **A regra que sustenta tudo:** nem `server.py` nem `admin/api/` implementam lógica de timeline. Os dois validam entrada, chamam o engine e formatam a saída. Toda regra de negócio é testável sem MCP e sem app. **Por que duas portas.** O MCP existe para o julgamento editorial — qual tomada usar, onde dar zoom — que é conversa com uma IA. A ponte existe para o que o usuário faz sozinho no app — transcrever, configurar, processar. As duas caem no mesmo engine, então uma correção ali vale para as duas. --- ## 2. Regras transversais (valem em todo o código) | Conceito | Regra | |----------|-------| | **Tempo** | `TimeValue`, fração racional `"600/2400s"`. **Nunca float para tempo.** | | **Tempo de decisão** | Ações de voz usam sempre segundos da **mídia original**, nunca pós-corte. | | **I/O paths** | Sempre via `_validate_filepath` / `_validate_output_path` (sandbox). | | **Nome de saída** | Nunca sobrescrever o original: `generate_output_path()` gera `_suffix`. | | **Segurança XML** | Sempre `defusedxml` via `safe_xml.py`. Nunca `xml.etree` direto para ler. | | **Deps opcionais** | `librosa`/`ffmpeg`/`huggingface_hub` importados **lazy**, degradam com `None`. | | **Idioma** | Comunicação com o usuário em português. Código e comentários em inglês. | | **Validação** | `./Engine/run_after_fix.sh` **sempre** após cada correção. | | **App** | Alterou `MacApp/`? Compile e rode: `admin/run_app.command` (padrão de revisão; equivale a `./MacApp/build_app.sh --run`). | --- ## 3. Fluxo de um request ### Pela porta MCP (Claude decidindo a edição) ``` Cliente MCP ──JSON-RPC──► server.py │ TOOL_HANDLERS[nome] ▼ server_tools/.py │ _shared/: valida path, parseia projeto ▼ fcpxml/ (parser → writer → safe_xml) ▼ projeto_.fcpxml (original intocado) ``` ### Pela porta do app (usuário operando) ``` MacApp ──Process + argv JSON──► admin/models_api.py │ handlers[comando] ▼ admin/api/.py │ shared.emit() devolve JSON-lines ▼ fcpxml/ (ou chama um handler do server) ▼ arquivo gerado + caminho de volta ao app ``` A saída da ponte é **JSON-lines**: um documento JSON por linha, para que comandos longos transmitam progresso enquanto rodam. Toda escrita passa por `admin/api/shared.py::emit`, que serializa o acesso a stdout — dois comandos escrevendo ao mesmo tempo entrelaçariam documentos. --- ## 4. Dual-mode: XML + Live - **Modo XML (principal):** exporta FCPXML, processa como dados, reimporta. - **Modo Live (`fcpxml/live.py`):** *push* do FCPXML direto para o FCP em execução via Apple events oficiais (`Open Document`). Leitura de bibliotecas via AppleScript read-only. **Assimetria estrutural:** import é scriptable, mas a Apple não oferece export programático. Round-trips sempre voltam pelas ferramentas XML. --- ## 5. Onde está cada responsabilidade | Responsabilidade | Fica em | |------------------|---------| | Modelos de dados (tempo, clips, markers, QC, legendas) | `fcpxml/models/` | | Parse FCPXML → objetos | `fcpxml/parser.py` | | Edição e escrita de FCPXML | `fcpxml/writer/` | | Geração de timeline nova | `fcpxml/rough_cut.py` | | Comparação de timelines | `fcpxml/diff.py` | | Export cross-NLE (Resolve, FCP7) | `fcpxml/export.py` | | Silêncio e beats | `fcpxml/media_intel.py` | | Transcrição Whisper | `fcpxml/transcribe.py` | | Diarização (quem falou) | `fcpxml/diarize.py` | | Ênfase acústica | `fcpxml/emphasis.py`, `fcpxml/voice_features.py` | | Timeline de voz (o JSON que a IA lê) | `fcpxml/voice_timeline.py` | | Decisões de edição (cut/zoom/text/marker) | `fcpxml/voice_actions.py` | | Revisão de frases da etapa 5 | `fcpxml/phrase_review.py` | | Layout de legendas e métricas de fonte | `fcpxml/text_layout.py`, `font_metrics.py`, `collision.py` | | Gestão de modelos Whisper | `fcpxml/model_manager.py` | | Controle Live do FCP | `fcpxml/live.py` | | Segurança XML | `fcpxml/safe_xml.py` | | Validação contra DTDs da Apple | `fcpxml/dtd.py` | | Transporte MCP (77 tools) | `server.py` + `server_tools/` | | Ponte com o app (37 comandos) | `admin/models_api.py` + `admin/api/` | | Interface do usuário | `MacApp/Sources/` | --- ## 6. Mapa de dependências ``` MacApp/ ──► admin/models_api.py (subprocesso, por caminho) admin/api/ ──► fcpxml/* e, para algumas operações, server.py server.py ──► server_tools/* server_tools/* ──► server_tools/_shared/ ──► fcpxml/* fcpxml/writer/ ──► fcpxml/models/, safe_xml, dtd, text_layout, collision fcpxml/models/ ──► fcpxml/text_layout (só o pacote subtitles) fcpxml/__init__.py ──► reexporta a API pública ``` **A seta que não existe, e não deve existir:** `fcpxml/` nunca importa de `server_tools/`, de `admin/` ou de qualquer coisa que saiba o que é uma tool. Se você precisar disso, a lógica está no lugar errado. --- ## 7. Criando algo novo — por onde começar | Você quer… | Comece por | |-----------|-----------| | Uma **ferramenta MCP** nova | Função pura em `fcpxml/` + teste. O handler em `server_tools/` fica fino. | | Um **comando do app** novo | Mesmo caminho, e exponha em `admin/api/.py` + tabela em `models_api.py`. | | Uma **tela** nova | `MacApp/Sources/`, consumindo comandos que já existem na ponte. | | Uma **regra de edição** nova | `fcpxml/` sempre. Se você está escrevendo `if` sobre timeline fora de `fcpxml/`, pare. | O trabalho principal é **sempre** no engine. As camadas de cima são finas de propósito: é o que permite testar 1.498 casos sem abrir o app nem subir o MCP.