Background
Tuist lets users describe an Xcode project by writing a Project.swift manifest in plain Swift, then evaluates that manifest at CLI invocation time — without the user having to compile and run a full app themselves. SwiftPM does the same thing with Package.swift.
We should investigate whether SyntaxKit could expose an analogous flow: the user writes a Swift file that uses the SyntaxKit DSL, and a CLI compiles + executes it to emit generated Swift source. This would let people drive code generation declaratively from a checked-in .swift file without setting up an executable target per generator.
Goals of this research
- Understand exactly how Tuist (and, as a comparison point, SwiftPM) compiles and executes a user manifest.
- Identify which pieces of that pipeline are reusable for a SyntaxKit-driven codegen CLI.
- Surface the risks and open questions before we commit to a design.
Phase 1 — How Tuist does it
Source: tuist/tuist, primarily the ProjectDescription target and the manifest-loading subsystem.
Questions to answer (with file/line citations into the Tuist repo):
- Compilation pipeline. What exact
swiftc invocation compiles Project.swift? Flags, framework search paths, linker args, output type (dylib vs. executable)?
- Execution model. Does Tuist (a) load a compiled dylib and call a known symbol, (b) run a compiled executable that dumps a description on stdout, or (c) something else? (SwiftPM uses (b) — confirm whether Tuist matches.)
- Bridging format. What's the wire format between the manifest process and the host tool?
ProjectDescription types are Codable — is JSON the boundary?
- Helpers / shared code. How does
ProjectDescriptionHelpers/ get compiled and made importable from the manifest?
- Caching. Does Tuist hash the manifest +
ProjectDescription version and skip recompilation? Where is the cache?
- Failure modes. What happens when the manifest crashes, has a syntax error, or hangs?
Phase 2 — Map the pattern onto SyntaxKit
With Phase 1 in hand, sketch the equivalent for a SyntaxKit CLI:
- Manifest shape. What does the user write? A top-level expression returning a
Group of CodeBlocks? An @main struct?
- What crosses the process boundary. SyntaxKit's output is generated Swift source, not a graph of
Codable types. Two viable options:
- Manifest executable prints generated Swift to stdout directly (simplest).
- Manifest exports a
Codable IR; host renders via SwiftSyntax (matches Tuist more closely, but duplicates rendering).
- Linking SyntaxKit into the manifest. The manifest needs
import SyntaxKit. Compare (a) shipping a precompiled SyntaxKit binary next to the CLI and passing -F/-I/-L, vs. (b) generating a throwaway SwiftPM package per run.
- Helpers directory. Mirror Tuist's
ProjectDescriptionHelpers so users can factor out reusable codegen.
Phase 3 — Open risks to probe early
- SwiftSyntax link cost. SwiftSyntax is large; compiling a manifest that transitively links it could be slow. Measure on a hello-world manifest before committing.
- macOS-only vs. Linux. Tuist is mac-focused. The SyntaxKit CLI should at least not paint itself into a macOS corner.
- Toolchain resolution. How does Tuist locate
swiftc (xcrun --find vs. explicit toolchain paths)?
Deliverables
- Phase 1 write-up: how Tuist's manifest pipeline works, with citations.
- Design sketch: compile command, execution model, IR boundary (or lack of one), helpers layout, caching strategy.
- Smallest possible proof-of-concept steps (enumerated, not yet implemented), e.g. "compile a manifest that imports SyntaxKit and prints a
Hello.swift to stdout."
Out of scope (for this issue)
- Implementation of the CLI itself — this issue is research only.
- Choosing a CLI name or product surface.
Background
Tuist lets users describe an Xcode project by writing a
Project.swiftmanifest in plain Swift, then evaluates that manifest at CLI invocation time — without the user having to compile and run a full app themselves. SwiftPM does the same thing withPackage.swift.We should investigate whether SyntaxKit could expose an analogous flow: the user writes a Swift file that uses the SyntaxKit DSL, and a CLI compiles + executes it to emit generated Swift source. This would let people drive code generation declaratively from a checked-in
.swiftfile without setting up an executable target per generator.Goals of this research
Phase 1 — How Tuist does it
Source: tuist/tuist, primarily the
ProjectDescriptiontarget and the manifest-loading subsystem.Questions to answer (with file/line citations into the Tuist repo):
swiftcinvocation compilesProject.swift? Flags, framework search paths, linker args, output type (dylib vs. executable)?ProjectDescriptiontypes areCodable— is JSON the boundary?ProjectDescriptionHelpers/get compiled and made importable from the manifest?ProjectDescriptionversion and skip recompilation? Where is the cache?Phase 2 — Map the pattern onto SyntaxKit
With Phase 1 in hand, sketch the equivalent for a SyntaxKit CLI:
GroupofCodeBlocks? An@mainstruct?Codabletypes. Two viable options:CodableIR; host renders via SwiftSyntax (matches Tuist more closely, but duplicates rendering).import SyntaxKit. Compare (a) shipping a precompiled SyntaxKit binary next to the CLI and passing-F/-I/-L, vs. (b) generating a throwaway SwiftPM package per run.ProjectDescriptionHelpersso users can factor out reusable codegen.Phase 3 — Open risks to probe early
swiftc(xcrun --findvs. explicit toolchain paths)?Deliverables
Hello.swiftto stdout."Out of scope (for this issue)