{"id":32710204,"url":"https://github.com/czottmann/interfazzle","last_synced_at":"2025-11-04T07:02:46.092Z","repository":{"id":321208606,"uuid":"1084912221","full_name":"czottmann/interfazzle","owner":"czottmann","description":"A Swift CLI tool for building simple Markdown docs for a package's public interface from its symbol graphs. LLMs love that stuff, too!","archived":false,"fork":false,"pushed_at":"2025-10-30T09:33:17.000Z","size":197,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-30T11:38:08.488Z","etag":null,"topics":["agents","documentation","documentation-tool","llm","llm-agents","markdown","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/czottmann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-28T10:35:14.000Z","updated_at":"2025-10-30T09:32:39.000Z","dependencies_parsed_at":"2025-10-29T14:07:57.881Z","dependency_job_id":"2019dc29-7a08-49b2-a498-ba3b8eeb04a0","html_url":"https://github.com/czottmann/interfazzle","commit_stats":null,"previous_names":["czottmann/swift-interfizzle","czottmann/swift-interfazzle","czottmann/interfazzle"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/czottmann/interfazzle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czottmann%2Finterfazzle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czottmann%2Finterfazzle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czottmann%2Finterfazzle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czottmann%2Finterfazzle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czottmann","download_url":"https://codeload.github.com/czottmann/interfazzle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czottmann%2Finterfazzle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":282592352,"owners_count":26694864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-04T02:00:05.887Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","documentation","documentation-tool","llm","llm-agents","markdown","swift"],"created_at":"2025-11-02T05:00:48.347Z","updated_at":"2025-11-04T07:02:46.086Z","avatar_url":"https://github.com/czottmann.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Interfazzle\n\nA wee **Swift CLI tool** that builds **Markdown documentation for a package's public interface** from Swift symbol graphs.\n\nIts aimed at package maintainers.\n\nFirst and foremost, I built this for myself – it scratches my own itches! But it feels kinda useful, even more so now that many of us work with LLMs, and they need to read docs, too. To home in on _that_, I grilled various LLMs—okay, just Claude Code—about how they work with documentation files, having them explain in detail what doc structure is useful to them. I combined what I've learned there with what I (a certified human!) look for in docs, and here we are.\n\nAlso, DocC and its dynamic-page nonsense is the Liquid Glass of documentation. There, I said it.\n\n## Overview\n\nInterfazzle handles the complete documentation generation pipeline:\n\n1. **Validation**: Verifies Package.swift exists in the current directory\n2. **Symbol Graph Generation**: Uses Swift's built-in compiler to generate symbol graph JSON files\n3. **Markdown Conversion**: Converts symbol graphs to interface-style Markdown documentation\n\nThis approach replaces the old `sourcedocs` tool, which failed for me when the package includes dependencies with pre-built binaries.\n\n## Demo\n\nSee [Demo](Demo/) folder for a dummy example package containing sources (in [Demo/Sources/](Demo/Sources/)) and generated documentation (in [Demo/docs/](Demo/docs/)).\n\n## Usage\n\n### Quick Start\n\nGenerate all documentation from your Swift package root:\n\n```bash\ninterfazzle generate\n# or if not installed:\nswift run interfazzle generate\n```\n\n## Requirements\n\n- macOS with Swift 6 (tested on Swift 6.0+)\n- Must be run from a directory containing `Package.swift`\n\n## Commands\n\nInterfazzle provides three main commands:\n\n### `generate` - Generate Documentation\n\nGenerate complete documentation (build + convert) in `./docs/` (default):\n\n```bash\ninterfazzle generate [options]\n```\n\nThis will:\n\n1. Verify `Package.swift` exists in the current directory\n2. Parse `Package.swift` using `swift package describe --type json` to:\n   - Extract module names (your public API)\n   - Discover target source paths for README integration\n3. Build the project and generate symbol graphs in `.build/symbol-graphs/`\n4. Convert symbol graphs to Markdown files in `docs/` with:\n   - Interface-style code blocks showing the public API\n   - `README.md` content from module source folders (if present)\n   - Intelligently adjusted heading levels for proper hierarchy\n   - Automatic filtering to package modules only (excludes dependencies and re-exports)\n\n### `build` - Build Symbol Graphs Only\n\nBuild symbol graphs without generating documentation:\n\n```bash\ninterfazzle build [options]\n```\n\n### `validate` - Validate Package\n\nVerify Package.swift exists in current directory:\n\n```bash\ninterfazzle validate\n```\n\n## Options\n\n### Global Flags\n\nAvailable for `generate` and `build` commands:\n\n- `-v, --verbose`: Show full `swift build` output (default: suppressed unless error)\n- `--be-lenient`: On build failure, attempt to continue with existing symbol graphs instead of failing\n- `-h, --help`: Show command-specific help\n\n### Generate Command Flags\n\nAdditional flags for `generate`:\n\n- `--generate-only`: Skip build phase, use existing symbol graphs (useful for quick regeneration)\n- `--include-reexported`: Include symbols from re-exported modules (e.g., from `@_exported import`)\n- `--symbol-graphs-dir \u003cdir\u003e`: Directory for symbol graphs (default: `.build/symbol-graphs`)\n- `--output-dir \u003cdir\u003e`: Output directory for documentation (default: `docs`)\n- `--modules \u003clist\u003e`: Comma-separated list of modules to document (default: all public products)\n\n### Build Command Flags\n\nFlags for `build`:\n\n- `--symbol-graphs-dir \u003cdir\u003e`: Directory for symbol graphs (default: `.build/symbol-graphs`)\n\n**Note**: By default, only modules listed in Package.swift's products (your public API) are documented. Dependency modules are automatically excluded.\n\n## Examples\n\n```bash\n# Show all available commands\ninterfazzle --help\n\n# Show help for a specific command\ninterfazzle generate --help\n\n# Basic documentation generation\ninterfazzle generate\n\n# Skip build, regenerate docs from existing symbol graphs (fast)\ninterfazzle generate --generate-only\n\n# Show verbose build output for debugging\ninterfazzle generate --verbose\n\n# Continue with existing symbol graphs if build fails\ninterfazzle generate --be-lenient\n\n# Include re-exported symbols (e.g., from @_exported import)\ninterfazzle generate --include-reexported\n\n# Document specific modules only\ninterfazzle generate --modules \"ModuleF,ModuleC,ModuleK,ModuleN,ModuleZ,ModuleS\"\n\n# Use custom directories\ninterfazzle generate --symbol-graphs-dir .build/symbols --output-dir output-docs\n\n# Combine flags\ninterfazzle generate --verbose --be-lenient\ninterfazzle generate --include-reexported --verbose\n\n# Custom directories with specific modules\ninterfazzle generate --symbol-graphs-dir custom-graphs --output-dir custom-docs --modules \"MyModule\"\n\n# Just build symbol graphs without generating docs\ninterfazzle build --verbose\n\n# Build to custom directory\ninterfazzle build --symbol-graphs-dir custom-graphs\n\n# Validate package before other operations\ninterfazzle validate\n```\n\n## Output Format\n\nEach module generates a single Markdown file with interface-style code blocks showing the complete public API in Swift syntax, similar to how Xcode shows generated interfaces.\n\n- H2 heading with module name\n- Optional README content (with adjusted heading levels)\n- Table of Contents listing all top-level types\n- H3 heading: \"Public interface\"\n- Separate code blocks for each top-level construct with H4 headings\n- Documentation comments as triple-slash syntax above each symbol\n\n### Structure\n\n- **H2**: Module name (`## Module \\`ModuleName\\``)\n- **Optional**: README content from module source folder (e.g., `Sources/ModuleName/README.md`)\n  - Headings automatically adjusted so the highest level becomes H3\n  - Maintains relative hierarchy of all headings\n- **Table of Contents**: Markdown table listing all top-level types with their kind (class, struct, enum, etc.)\n- **H3**: \"Public interface\" heading\n- **H4 + Code blocks**: Each top-level construct (class, struct, enum, protocol, extension, globals) gets:\n  - Its own H4 heading with type label and name (e.g., `#### class ExampleClass`)\n  - A separate Swift code fence containing its complete interface\n  - Nested types rendered within parent declarations\n  - Documentation comments as triple-slash (`///`) comments above declarations\n  - Symbols grouped by type: Protocols → Structs → Classes → Enums → Extensions → Macros → Functions\n\n### README Integration\n\nIf a module folder contains a `README.md` file, its content is automatically included after the module heading. The script:\n\n1. Removes duplicate module name headings (e.g., `# ModuleName`)\n2. Adjusts heading levels intelligently:\n   - Finds the highest heading level in the README (e.g., `##` = level 2)\n   - Shifts it to H3 to fit under the module's H2\n   - Applies the same shift to all other headings to maintain hierarchy\n3. Example: README with `##` and `###` → becomes `###` and `####` in output\n\n## Installation\n\n### Install from Source\n\n```bash\ngit clone https://github.com/czottmann/interfazzle.git\ncd interfazzle\nswift build -c release\ncp .build/release/interfazzle /usr/local/bin/\n```\n\n### Build Locally\n\n```bash\nswift build\n# Use with: swift run interfazzle\n```\n\n### Mise tasks\n\nThis project uses [mise-en-place's tasks](https://mise.jdx.dev/tasks/) for convenience. Run `mise tasks` to see what's available.\n\n## Architecture\n\nSince v1.0, Interfazzle is a proper Swift package with modular architecture:\n\n### Package Structure\n\n- **`Interfazzle`** - Core library module with all documentation generation logic\n  - `Models/` - Data structures (Config, SymbolGraph, PackageDescription)\n  - `Core/` - Core logic (PackageValidator, SymbolGraphBuilder, ModuleExtractor, PackageInfoLoader, PackageInfoProvider)\n  - `Generation/` - Documentation generation (DocumentationGenerator, SymbolSorter, DeclarationFormatter, MarkdownFormatter)\n\n- **`InterfazzleCLI`** - Executable module with SwiftCLI-based command-line interface\n  - `Commands/` - Command implementations (GenerateCommand, BuildCommand, ValidateCommand)\n  - Uses [SwiftCLI](https://github.com/jakeheis/SwiftCLI) for argument parsing and help generation\n\n### Features\n\n- **Validation**: Checks for Package.swift in current directory\n- **Orchestration**: Builds symbol graphs and generates documentation in one command\n- **Filtering**: Automatically filters to public product modules (excludes dependencies and re-exports)\n- **Multiple Commands**: Separate commands for generate, build, and validate\n- **Customization**: Optional custom directories and module filtering\n- **README Integration**: Automatically includes README.md from module source folders\n- **Heading Adjustment**: Intelligently adjusts README heading levels to maintain hierarchy\n- **Interface-style Output**: Generates code blocks like Xcode's generated interfaces\n- **Symbol Grouping**: Organizes by type (protocols → structs → classes → enums → extensions)\n- **Nested Types**: Handles nested types with proper indentation\n- **Protocol Consolidation**: Shows all protocol conformances in main class declarations\n- **Doc Comments**: Renders documentation comments as triple-slash (`///`) syntax\n- **Error Handling**: Clear error messages with appropriate exit codes\n\n### Exit Codes\n\n- `0`: Success\n- `1`: Validation error (e.g., Package.swift not found)\n- `2`: Build error (when not using `--be-lenient`)\n- `3`: Documentation generation error\n\n## How It Works\n\n### Symbol Graphs\n\nSwift's compiler can emit \"symbol graphs\" - JSON files containing all public API information:\n\n- Types (classes, structs, enums, protocols)\n- Properties and methods\n- Documentation comments\n- Declaration signatures\n- Relationships between symbols\n\n### Conversion Process\n\nThe `DocumentationGenerator` module's Markdown generation phase:\n\n1. **Reads** symbol graph JSON files from `.build/symbol-graphs/`\n2. **Filters** to public product modules by default (excludes dependencies)\n3. **Filters** to public API symbols (`public` and `open` access levels, excludes internal/private/synthesized)\n4. **Groups** symbols by:\n   - Type (protocols, structs, classes, enums, extensions)\n   - Nesting (properties, methods, etc. under parent types)\n5. **Generates** one Markdown file per module with all content consolidated:\n   - `ModuleName.md` containing all symbols for that module\n   - Interface-style code blocks showing the complete public API\n   - Optional README content with intelligently adjusted heading levels\n\n## Why Not SourceDocs?\n\n[SourceDocs](https://github.com/eneko/SourceDocs) failed me on some projects:\n\n1. It uses SourceKit, which crashes when dependencies include pre-built binaries\n2. Symbol graphs are compiler-generated, so they handle all valid Swift packages\n3. Symbol graphs are the official way Apple recommends for documentation tooling\n\nThe above conclusions might be wrong, I'm still a noob in a lot of regards when it comes to Swift.\n\n### Differences from SourceDocs Output\n\nThe generated documentation differs from SourceDocs in structure and format:\n\n1. **Interface-style code blocks**: Shows complete Swift interface in code blocks (like Xcode's generated interfaces) instead of individual sections per symbol\n2. **Consolidated files**: One `ModuleName.md` file per module instead of folder-per-module with multiple files\n3. **Structured headings**: Module name (H2), optional README content, Table of Contents, \"Public interface\" (H3), and H4 for each top-level construct\n4. **README integration**: Automatically includes README.md from module source folders with intelligent heading adjustment\n5. **Protocol consolidation**: Shows all protocol conformances (including from extensions) in the main class declaration\n6. **Nested type rendering**: Nested types appear within their parent declarations, maintaining proper Swift syntax\n\nThe interface-style format is more compact, easier to read, and better reflects how developers actually view APIs in Xcode.\n\nIf you prefer one documentation file for your entire project: `cat docs/**.md \u003e documentation.md` 😉\n\n## Future Improvements\n\nPotential enhancements:\n\n- [ ] Generate cross-reference links between types\n- [ ] Add availability information (iOS 16+, macOS 13+, etc.) to declarations\n- [ ] Support for Linux and other platforms\n\n## Troubleshooting\n\n### \"Cannot read symbol graphs directory\"\n\nRun `interfazzle generate` without `--generate-only` to build symbol graphs first, or use the build command:\n\n```bash\ninterfazzle build\n```\n\nOr manually build them:\n\n```bash\nswift build -Xswiftc -emit-symbol-graph -Xswiftc -emit-symbol-graph-dir -Xswiftc .build/symbol-graphs\n```\n\n### \"Package.swift not found in current directory\"\n\nAll commands must be run from the root of a Swift package (where Package.swift is located). Use `interfazzle validate` to check.\n\n### Missing symbols in output\n\nOnly public API symbols (`public` and `open` access levels) are documented. Internal/private/fileprivate symbols are intentionally excluded.\n\n### README not being included\n\nThe script looks for `README.md` in the target's source path as defined in `Package.swift`. If your README isn't being included:\n\n1. Verify the file is named exactly `README.md` (case-sensitive)\n2. Check it's in the module's source directory (e.g., `Sources/ModuleName/README.md`)\n3. Verify the target path in Package.swift matches where the README is located\n\n### Formatting issues\n\nThe script uses Swift's declaration fragments directly. If formatting looks odd, check the symbol graph JSON to see what the compiler emits.\n\n### Build errors blocking documentation generation\n\nUse `--be-lenient` to generate docs from existing symbol graphs even if the build fails:\n\n```bash\ninterfazzle generate --be-lenient\n```\n\n### Dependency modules appearing in output\n\nThis shouldn't happen with the current version. Interfazzle automatically filters to only public product modules. If you see dependency docs being generated, please report it as a bug.\n\n### Regenerating docs quickly after edits\n\nUse `--generate-only` to skip the build phase and regenerate docs from existing symbol graphs:\n\n```bash\ninterfazzle generate --generate-only\n```\n\nThis is much faster when you've only changed documentation comments or README files.\n\n### Re-exported symbols missing from output\n\nBy default, Interfazzle filters out symbols from re-exported modules (e.g., from `@_exported import`) to keep documentation focused on your package's own API. If you need to include these symbols:\n\n```bash\ninterfazzle generate --include-reexported\n```\n\nThis will include symbols from frameworks like OSLog that are re-exported using `@_exported import`.\n\n## Author\n\nCarlo Zottmann, \u003ccarlo@zottmann.dev\u003e, https://c.zottmann.dev, https://github.com/czottmann\n\n\u003e ### 💡 Did you know?\n\u003e\n\u003e I make Shortcuts-related macOS \u0026 iOS productivity apps like [Actions For Obsidian](https://actions.work/actions-for-obsidian), [Browser Actions](https://actions.work/browser-actions) (which adds Shortcuts support for several major browsers), and [BarCuts](https://actions.work/barcuts) (a surprisingly useful contextual Shortcuts launcher). Check them out!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczottmann%2Finterfazzle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczottmann%2Finterfazzle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczottmann%2Finterfazzle/lists"}