A modern Swift 6 framework for working with Final Cut Pro's FCPXML with full concurrency support, SwiftTimecode integration, and XLKit integration.
OpenFCPXMLKit provides a type-safe API for parsing, creating, and manipulating FCPXML with async/await, SwiftTimecode, and Excel/PDF reporting. Targets macOS 26+ and iOS 26+ (Foundation XML on macOS; AEXML on iOS).
Tests: 1169 listed in swift test list — 1161 in OpenFCPXMLKitTests + 8 optional ExcelReportTest (all Swift Testing) — across 60 sample .fcpxml files. Private local investigation inbox: Tests/Submitted FCPXML/ (gitignored; never commit private FCPXML).
OpenFCPXMLKit is currently in an experimental stage. It covers most core FCPXML attributes and parameters and provides a solid foundation for parsing, creation, and manipulation, with room for future expansion and additional feature coverage.
This codebase is developed using AI agents.
Important
OpenFCPXMLKit is highly experimental and has not yet been extensively tested in production environments, real-world workflows, or application integration. Report generation, in particular, remains at a very early and experimental stage. This library serves as a modernised foundation for AI-assisted development and experimentation with FCPXML processing capabilities.
Caution
The codebase's API is still evolving and may change without notice between versions. Please consult the documentation for API usage. Use with caution in any workflow you rely on.
Note
This project is shared as is and is not under active or regular development.
- Core Features
- Requirements
- Installation
- Before CLI Usage
- CLI Usage
- API Documentation
- FCPXML Version Support
- Modularity & Safety
- Architecture Overview
- Utilised By
- Credits
- License
- Reporting Bugs
- Contribution
- Legacy
- Read / create / modify
.fcpxmland.fcpxmldbundles (FCPXMLFileLoader, sync & async) - FCPXML 1.5–1.14 DTDs; semantic + DTD validation (full DTD on macOS; structural on iOS)
- Version convert with automatic element stripping for the target DTD
- Cut detection (edit points, transitions, gaps); typed element filtering (
FCPXMLElementType)
- SwiftTimecode:
CMTime,Timecode, FCPXML time strings FCPXMLTimecode(arithmetic, frame alignment, conversion)- Frame rates: 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 fps
- Resources, events, clips, projects, transitions, multicam
- Adjustments (crop, corners, transform, volume, panner, EQ, 360, stereo 3D, …)
- Filters, captions/titles (
TextStyle), smart collections, keyword folders - Keyframe animation, Live Drawing (1.11+), HiddenClipMarker / heroEye / mediaReps (1.13+)
- Build and export
Timeline/TimelineFormat(presets, empty projects) - Ripple insert, auto lane, clip queries, secondary storylines
- Markers, keywords, ratings, custom metadata, timestamps
FinalCutPro.FCPXML.Authoringvalue graph (no live XML ownership)- Encode/decode limited subset; omit-on-write via
VersionAvailability/VersionFeatureGate - Spine: asset-clip, gap, title, transition, video/audio, caption, sync/ref/mc-clip, audition
- Resources: format, asset, effect, media (compound + multicam)
- See Manual 08 — Detached Authoring
- Extraction presets (Captions, Markers, Roles, Titles, Effects, FrameData)
- Media extract / copy; MIME detection; asset validation; silence; duration; parallel I/O
- Mid-layer between Extraction and Reporting:
TimelineProjector→MediaUsageWindow - Channels, lanes,
timeMap/ conform retiming, multicam / ref-clip / audition unfold RetimingSegmentcompose/clip;TimelineOccupancyIndexoverlap;.trackAnalysisoptions preset- Reports project once per timeline; Markers / Keywords / Titles / Transitions / Effects are Projection-first (Extraction fallback)
- See Manual 12 — Timeline Projection
- Primary-timeline still-image shots → PNG dataset + CSV or Notion JSON (
ShotExtractor/extractShots/planShotsdry-run) - Rejects primary-spine video, titles / generators / Motion templates, and audio; connected lanes ignored; reused stills get distinct Shot IDs (
{scene}-001…) - Notion JSON (
--extract-format notion) follows the csv2notion-neo JSON import convention - CLI:
--extract-shots --scene-number …(optional--dry-run,--extract-format,--icon) - See Manual 21 — Shot Extraction
- Build once with
buildReport(options:), then export.xlsx(XLKit) and/or.pdf(CoreGraphics) - Sheets: Role Inventory, Markers, Keywords, Titles, Transitions, Non-Std Effects & Templates, Effects, Speed Change, Summary, Media Summary
- Role inventory: 26 fixed columns (Duplicate Frames, Codecs, Ingest Date, Frame Size / Audio Config, …) + per-role Total: footers
- Empty enabled sheets keep headers + status rows (No Markers Found, No Missing Media, …) via
ReportEmptySectionStatus
- Filters: roles, columns (incl. Row), disabled clips, project name, timecode format, copyright label
- Markers: default omits out-of-bounds starts;
--include-markers-outside-clip-boundariesadds them + Hidden column - Excel:
--protect-sheets/protectSheetsapplies worksheet edit locks (not encryption; PDF unaffected) - CLI:
--report,--report-full,--report-non-standard-effects,--create-pdf,--media-resolution,--timecode-format,--protect-sheets, … - See Manual 20 — Reporting
OpenFCPXMLKit-CLI: check / convert / validate / media-copy / extract-shots / create-project / report- Single portable binary with embedded DTDs — CLI README
- Protocol-oriented + dependency injection; sync and async APIs
- Layer stack:
XML → Parsing → Model → Extraction → Projection → Reporting(plus parallelShotExtraction/from Projection) - Swift 6 strict concurrency; cross-platform OFKXML (Foundation / AEXML)
- See ARCHITECTURE.md and GUARDRAILS.md
- macOS 26.0+ or iOS 26.0+ (CLI is macOS-only; library supports both)
- Xcode 26.0+
- Swift 6.3+ (strict concurrency compliant; protocols and public types are
Sendablewhere appropriate;@unchecked Sendableonly where required for Foundation/ObjC interop)
Add OpenFCPXMLKit to your project in Xcode:
- File → Add Package Dependencies
- Enter the repository URL:
https://github.com/TheAcharya/OpenFCPXMLKit - Select the version you want to use
- Click Add Package
Or add it to your Package.swift:
// swift-tools-version: 6.3
// Add OpenFCPXMLKit as a dependency and link it to your target.
import PackageDescription
let package = Package(
name: "MyPackage",
platforms: [
.macOS(.v26),
.iOS(.v26)
],
dependencies: [
.package(url: "https://github.com/TheAcharya/OpenFCPXMLKit", from: "3.3.3")
],
targets: [
.target(
name: "MyTarget",
dependencies: ["OpenFCPXMLKit"]
)
]
)First, ensure your system is configured to allow the tool to run:
Privacy & Security Settings
Navigate to the Privacy & Security settings and set your preference to App Store and identified developers.
Download the latest release of the CLI universal binary here.
Extract the OpenFCPXMLKit-CLI-portable-x.x.x.zip file from the release.
Using Homebrew
$ brew install TheAcharya/homebrew-tap/OpenFCPXMLKit-CLI$ brew uninstall --cask OpenFCPXMLKit-CLIUpon completion, find the installed binary OpenFCPXMLKit-CLI located within /usr/local/bin. Since this is a standard directory part of the environment search path, it will allow running OpenFCPXMLKit-CLI from any directory like a standard command.
Download the latest release of the CLI installer package here.
Use the OpenFCPXMLKit-CLI-<version>.pkg installer to install the command-line binary into your system. Upon completion, find the installed binary OpenFCPXMLKit-CLI located within /usr/local/bin. Since this is a standard directory part of the environment search path, it will allow running OpenFCPXMLKit-CLI from any directory like a standard command.
To uninstall, run this terminal command. It will require your account password.
sudo rm /usr/local/bin/OpenFCPXMLKit-CLIVERSION=3.3.3 # replace this with the git tag of the version you need
git clone https://github.com/TheAcharya/OpenFCPXMLKit.git
cd OpenFCPXMLKit
git checkout "tags/$VERSION"
swift build -c releaseOnce the build has finished, the OpenFCPXMLKit-CLI executable will be located at .build/release/.
$ OpenFCPXMLKit-CLI --help
OVERVIEW: Experimental tool to read, validate and generate Excel/PDF reports from Final Cut Pro FCPXML/FCPXMLD.
https://github.com/TheAcharya/OpenFCPXMLKit
USAGE: [<options>] [<fcpxml-path>] [<output-dir>]
ARGUMENTS:
<fcpxml-path> Input FCPXML file / FCPXMLD bundle; or output directory when using --create-project.
<output-dir> Output directory (for --convert-version, --media-copy, etc.).
GENERAL:
--check-version Check and print FCPXML document version.
--convert-version <version>
Convert FCPXML to the given version (e.g. 1.10, 1.14) and write to output-dir.
--extension-type <extension-type>
Output format for --convert-version: fcpxmld (bundle) or fcpxml (single file). Default:
fcpxmld when converting. For target versions 1.5–1.9, .fcpxml is used regardless. (values:
fcpxml, fcpxmld)
--validate Perform robust check and validation of FCPXML/FCPXMLD (semantic + DTD).
TIMELINE:
--create-project Create a new empty FCPXML project (requires --width, --height, --rate, and <output-dir>
positional).
--width <width> Project width in pixels (used with --create-project).
--height <height> Project height in pixels (used with --create-project).
--rate <rate> Frame rate (e.g. 24, 25, 29.97) (used with --create-project).
--project-version <project-version>
FCPXML version for the new project (e.g. 1.10, 1.14). Default: 1.14. (used with
--create-project).
EXTRACTION:
--media-copy Scan FCPXML/FCPXMLD and copy all referenced media files to output-dir.
SHOT EXTRACTION:
--extract-shots Extract primary-timeline still-image shots to PNG + CSV/JSON. Rejects primary-spine video,
titles/generators/Motion templates, and audio clips.
--dry-run Validate the timeline and report shot count without writing PNGs or manifests. Requires
--extract-shots. Suitable for GUI preflight. output-dir is optional.
--extract-format <extract-format>
Shot Extraction manifest format: csv | notion (JSON). Requires --extract-shots.
--scene-number <scene-number>
Scene number for Shot ID / Scene Number columns (required with --extract-shots).
--folder-format <folder-format>
Shot Extraction folder naming: short | medium | long (default: medium). Requires
--extract-shots.
--result-file-path <result-file-path>
Optional JSON result file path for Shot Extraction (also written on --dry-run). Requires
--extract-shots.
--extract-project <extract-project>
Optional project / timeline name filter for Shot Extraction. Requires --extract-shots.
--icon <icon> Optional emoji (or any text) for the Icon Image column on every shot row. Requires
--extract-shots.
REPORT:
--report Build an Excel report workbook from FCPXML (role inventory only; use --report-full for all
sheets).
--report-full Include every optional report sheet (with --report). Default --report exports role inventory
only.
--report-markers Include the Markers sheet (with --report).
--report-keywords Include the Keywords sheet (with --report).
--report-titles-generators
Include the Titles & Generators sheet (with --report).
--report-transitions Include the Transitions sheet (with --report).
--report-non-standard-effects
Include the Non-Std Effects & Templates sheet (with --report).
--report-effects Include the Video & Audio Effects sheet (with --report).
--report-speed-change-effects
Include the Speed Change Effects sheet (with --report).
--report-summary Include the Summary sheet (project metrics and role-duration totals; with --report).
--report-media-summary Include the Media Summary sheet (missing media file paths; with --report).
--create-pdf Also write a PDF report alongside the Excel workbook (with --report). Includes the same
workbook sections, column exclusions, and timecode formatting when present.
--report-project <report-project>
Timeline name filter: matches a <project> name or a standalone compound-clip / ref-clip name
when the document has more than one reportable timeline.
--label-copyright <label-copyright>
Optional copyright / attribution line for Excel and PDF reports (with --report). Excel:
cover sheet cell A2 below the Created-by brand row. PDF: same subtitle style below
Created-by on the cover, and centred in the running footer (same footer font/size as the
Created-by branding).
--exclude-role <exclude-role>
Exclude a role or subrole from role inventory (repeatable). Excluding a main role also
excludes its subroles.
--exclude-disabled-clips
Omit disabled clips (enabled="0") from all report sections (with --report).
--include-markers-outside-clip-boundaries
Include markers whose start is outside the host clip’s media range (hidden in FCP
timeline/Tags) and add a Hidden column (✓/✗) on the Markers sheet (with --report /
--report-markers). Default omits those markers and does not show Hidden.
--protect-sheets Protect every sheet in the Excel workbook against casual edits (with --report). Applies to
the cover sheet and all content sheets. This is an edit lock, not file-open encryption —
Excel can still open the file, and anyone can turn protection off. PDF export is unaffected
(use Preview’s Encrypt to password-protect a PDF).
--exclude-column <exclude-column>
Exclude a report column from every applicable Excel/PDF sheet (repeatable; with --report).
Case-insensitive names include Row / Row Numbers (all tabular sheets + PDF Row injection),
Role Subrole, Clip Name, Frame Rate, Reel, Metadata (role inventory dynamic metadata keys),
and other shared column headers. Columns are removed wherever the sheet uses a matching
header.
--timecode-format <timecode-format>
Timeline time display format for Excel and PDF report cells (with --report). Values:
HH:MM:SS:FF, Frames, Feet+Frames, HH:MM:SS. Default when omitted: HH:MM:SS:FF (SMPTE with
frames; semicolon before frames for drop-frame).
--media-resolution <media-resolution>
How report building treats timeline projection failures (with --report). Values: fail-soft,
fail-loud. Default when omitted: fail-soft (continue with empty projection windows).
fail-loud aborts with an error. Missing files on disk still appear on Media Summary.
--media-summary-distinguish-proxy
On Media Summary, emit separate Missing Original and Missing Proxy columns instead of a
single Missing Media column (with --report / --report-media-summary).
LOG:
--log <log> Log file path.
--log-level <log-level> Log level. (values: trace, debug, info, notice, warning, error, critical; default: info)
(default: info)
--quiet Disable log.
OPTIONS:
--version Show the version.
-h, --help Show help information.
Complete manual, usage guide, and examples are in the Documentation folder:
- Manual Index — Full chapter list and navigation (start here)
- Documentation hub — Manual overview
- Coverage — Detailed FCPXML coverage matrices (typed Model, Authoring, Extraction, Projection, Reporting)
- CLI — Flags, examples, building and extending
- ARCHITECTURE.md — Layer stack, codebase map, Mermaid diagrams
- GUARDRAILS.md — Must / must-not constraints for contributors and agents
- Tests/README.md — Test suite layout (1169 listed; all Swift Testing)
- AGENT.md — AI agent / contributor briefing
OpenFCPXMLKit supports FCPXML versions 1.5 through 1.14. All DTDs for these versions are included. You can validate a document against any version's schema (e.g. document.validateFCPXMLAgainst(version: "1.14")).
- Parsing: Any well-formed FCPXML document parses successfully; the full XML tree is available via the protocol-based XML layer (
OFKXMLDocument/OFKXMLElement— Foundation-backed on macOS, AEXML-backed on iOS). - Typed element types: Every element from the FCPXML DTDs (1.5–1.14) is represented in
FCPXMLElementType, so you can identify and filter by any element (e.g.locator,import-options,live-drawing,filter-video, alladjust-*, smart-collection match rules, etc.). Structural types like multicam vs compoundmediaare inferred from the first child. - Typed attributes and helpers: The framework also provides typed properties and helpers for a subset of elements (e.g.
fcpxDuration,fcpxOffset, event/project/clip APIs). Other elements are fully accessible viaelement.name,element.attribute(forName:), and the sharedgetElementAttribute/setElementAttributehelpers.
- Protocol-oriented and dependency-injected: core behaviour (parsing, timecode, document ops, error handling) is behind protocols with default implementations you can replace. Inject when creating FCPXMLService or FCPXMLUtility or when using modular extension overloads.
- Extension APIs that can't take a parameter use a single shared instance (FCPXMLUtility.defaultForExtensions) for consistency and concurrency safety; use overloads with a
using:parameter for custom services. - Built with Swift 6 and strict concurrency; Sendable where possible, no unsafe code. Key dependencies: SwiftTimecode, SwiftExtensions 3.0+, SwiftSemanticVersion, swift-log, AEXML (iOS XML backend), XLKit (Excel report export), swift-textfile (Shot Extraction CSV), CoreGraphics / ImageIO (PDF report export; PNG shot images), and swift-argument-parser (CLI only). Minimum versions are defined in
Package.swift.
- Protocols define parsing, timecode conversion, document operations, error handling, MIME type detection, asset validation, silence detection, asset duration measurement, and parallel file I/O; each has a default implementation you can swap. FCPXMLService (and FCPXMLUtility) composes these and exposes sync and async APIs. ModularUtilities provides createService, processFCPXML, validateDocument, convertTimecodes, and similar helpers.
- FCPXMLFileLoader handles .fcpxml and .fcpxmld (including bundle Info.fcpxml). FCPXMLValidator and FCPXMLDTDValidator handle structural and schema validation (full DTD on macOS; FCPXMLStructuralValidator on iOS when DTD is unavailable); DTDs for 1.5–1.14 are bundled.
- A cross-platform XML layer (
Sources/OpenFCPXMLKit/XML/) provides protocol types (OFKXMLNode, OFKXMLElement, OFKXMLDocument, OFKXMLFactory) with Foundation and AEXML backends. Extensions on CMTime and the XML protocol types offer convenience APIs; use modular overloads with an explicit dependency to inject your own. Error types are explicit (FCPXMLError, FCPXMLLoadError, export and validation errors); you can inject a custom error handler. - The engine is layered bottom-up —
XML → Parsing → Model → Extraction → Projection → Reporting— so the CLI, extraction presets, timeline tools, and reports share one foundation. Authoring is a parallel detached create path (not in the Reporting stack). Projection emits playableMediaUsageWindows; Reporting (Excel via XLKit, PDF via CoreGraphics) maps Projection + Extraction facts into sheets and owns presentation only. See ARCHITECTURE.md for the full codebase map and layer boundaries, and GUARDRAILS.md for hard must / must-not constraints on those layers.
See AGENT.md for a detailed breakdown for AI agents and contributors, and GUARDRAILS.md for hard must / must-not constraints.
Created by Vigneswaran Rajkumar
Icon Design by Bor Jen Goh
Licensed under the MIT license. See LICENSE for details.
For bug reports, feature requests and suggestions you can create a new issue to discuss.
Pull requests are accepted on a best effort basis. Contributions must not break existing functionality: all current features, behaviours and logic should remain fully functional and unchanged. Response times may be slow given the project's limited maintenance schedule.
OpenFCPXMLKit is developed using AI agents as part of an ongoing exploration of AI-assisted development workflows. Contributions from developers interested in this approach are welcome via pull request.
This repository was formerly known as Pipeline Neo.


