Point it at a folder. Get a diagram back. No annotations, no project files, no build step — just your source code, parsed for real and drawn as a UML class diagram. Works across Swift, Kotlin, Java, TypeScript/JavaScript, Dart, Python, C, and C++, all in one picture. Explore it in the native macOS app, or wire the acai CLI into your build and docs.
☝️ The macOS app exploring the bundled Examples/ClassDiagram sample.
You've inherited a codebase. Or you're onboarding onto one. Or you just want to remember how the thing you wrote six months ago fits together. Açaí reads your source the way a compiler's front end would — it actually parses it, it doesn't grep for keywords — and builds one unified model of your types and how they relate. Then it draws the picture: the boxes, the members, and the inheritance / composition / dependency arrows between them.
It runs on a folder. Got a polyglot repo with Swift up front and a C core underneath? Point Açaí at the root and every language lands in the same diagram. Nothing to annotate, no build to run first.
git clone https://github.com/pauljohanneskraft/Acai.git
cd Acai
./Scripts/app_create.sh && ./Scripts/app_install.sh
open -a AcaiThen: add a project, point a codebase at any folder of source, and let it index. Open a class diagram, drag the boxes where you want them, fold members away, group by folder or namespace, dial in an access level — the diagram updates live. Happy with the layout? Hit Export Image and you get a PNG exactly as you arranged it.
./Scripts/cli_create.sh && ./Scripts/cli_install.sh
# Render any codebase straight to a PNG (macOS):
acai image --source ~/path/to/your/project --output project.png
# …or emit DOT and render it anywhere Graphviz runs:
acai diagram --source ~/path/to/your/project --output project.dot
dot -Tpng project.dot -o project.png # brew install graphvizNo config file required for either path.
Point Açaí at the whole repo and every language lands in one diagram, neatly grouped — here the bundled sample's Swift and Kotlin sides, side by side:
Zoom in on one side for full member detail. Access levels show as + / -, and the three UML relationships are all here: inheritance (hollow triangle), composition (filled diamond), and dependency (dashed arrow).
Prefer the shape over the detail? Hide members for an architecture-at-a-glance overview:
Generated diagrams are the fast path, but the app also ships a freeform editor. Drag types, actors, use cases, packages, and notes from the catalog onto an infinite canvas and wire them up by hand — or take a generated diagram and keep editing from there. Sequence, state-machine, and call-graph elements are all in the box.
- 🌍 Multi-language out of the box — one tool for polyglot repos, not six.
- ⚡️ Zero configuration — point it at a directory and go.
- 🎨 Tweak what you see — filter members, methods, and access levels; group by file or namespace; pick a theme; drag the layout into shape.
- 🖼 Export to PNG or DOT — a pixel-perfect image of your on-screen layout, or standard Graphviz you can render anywhere.
- 🤖 Automatable — a first-class CLI for CI, docs pipelines, and pre-commit hooks.
- 🧩 A library underneath — the whole engine is a set of SwiftPM modules you can build on.
No tool is magic, and this one is no exception. Worth knowing up front:
- PNG rendering is macOS-only. Both the app's Export Image and the
acai imagecommand render through SwiftUI'sImageRenderer, which needs a window-server session. On Linux, emit DOT withacai diagramand render it with Graphviz (dot -Tpng) — that path runs everywhere. - It's static analysis. Açaí reads source text; it does not run your build, resolve your package graph, or execute anything. Relationships are inferred from what the code says, not from a compiler's resolved symbol table.
- Plain JavaScript is thin. With no type annotations to read, a JS-only diagram shows little beyond inheritance. TypeScript gives you the full picture; for a JS example see
Examples/StateDiagram. - C is modeled with
structs. C has no classes, so its domain shows up as structs plus composition, and method-receiver analysis maps free functions back to the type they mutate by pointer. Faithful, but it reads differently from the OO languages.
The per-language nuances are documented in detail — and proven with checked-in exports — in Examples/README.md.
| Language | Parser |
|---|---|
| Swift | SwiftSyntax |
| Kotlin | Tree-sitter |
| Java | Tree-sitter |
| TypeScript / JavaScript | Tree-sitter |
| Dart | Tree-sitter |
| Python | Tree-sitter |
| C | Tree-sitter |
| C++ | Tree-sitter |
Mix and match — Açaí produces one unified model across all of them. (C and C++ share the .h header extension; Açaí routes each header to the right grammar by its contents.)
Run acai --help (or acai <command> --help) for the full menu. The essentials:
acai analyze --source ./MyProject --output model.json # Parse code → JSON model
acai store myproj ./MyProject # Analyze and stash it under a name
acai list # Show stored analyses
acai metrics --from myproj # Counts, coupling, OO metrics as JSON
# DOT / Graphviz output:
acai diagram --from myproj --theme dark --group-by namespace --output app.dot
acai diagram --source ./MyProject --language kotlin --language java
# PNG output, rendered natively (macOS):
acai image --source ./MyProject --grouping directory --output app.pngTwo ways to get an image, with deliberately different options:
acai diagram |
acai image |
|
|---|---|---|
| Output | DOT/Graphviz text | PNG |
| Grouping | --group-by file|namespace|none |
--grouping none|directory|product |
| Members | --show-members / --no-show-members |
--hide-members, --min-access <level> |
| Styling | --theme default|dark, --direction TB|LR|BT|RL, --config <yaml> |
--scale <factor> |
| Runs on | every platform | macOS only |
Both accept --from <stored-name-or-json> or --source <dir> (with optional repeated --language), and both can draw sequence, state, package, and call-graph diagrams via their respective flags. Pair --config myconfig.yaml with diagram to lock options down for repeatable output.
Açaí renders images two ways, for two jobs:
- In the app — "Export Image." Renders the diagram exactly as you've arranged it: your manual node positions, your resizes, your visibility settings. WYSIWYG, straight to a PNG.
- On the CLI —
acai image. Headless and scriptable, perfect for CI and docs. It runs the same SwiftUI layout and views as the app, so the output matches.
acai image --source ./MyProject --grouping directory --min-access public --scale 2 --output api.pngmacOS only. Both paths render through SwiftUI's
ImageRenderer, which needs a window-server session. On Linux, emit DOT withacai diagramand render it with Graphviz (dot -Tpng).
The class diagrams in this README were produced by acai image from the samples in Examples/ — see Examples/README.md for the exact commands, plus DOT/PNG exports of every diagram type in all supported languages.
Açaí is a layered Swift package — one module per concern, so you can pull in only what you need:
Source files
│ per-language parsers (SwiftSyntax / Tree-sitter)
▼
AcaiSwift · AcaiJVM (Java/Kotlin) · AcaiJS · AcaiDart · AcaiPython · AcaiCFamily (C/C++)
│ one unified model
▼
AcaiCore ──► AcaiLibrary (AnalysisService: discovery + dispatch)
│ │
│ ├──► AcaiDiagram → DOT / Graphviz / Mermaid
│ └──► AcaiRender → PNG (SwiftUI ImageRenderer + Sugiyama layout)
▼
AcaiCLI (acai) · AcaiApp (Acai.app) · AcaiMCP (acai-mcp)
AcaiCore— the data model (CodeArtifact,TypeDeclaration,Relationship, …) and theCodeParserprotocol. The vocabulary everything else speaks.- Per-language parsers —
AcaiSwiftuses SwiftSyntax;AcaiJVM(Java + Kotlin),AcaiJS,AcaiDart,AcaiPython, andAcaiCFamily(C + C++) use Tree-sitter (shared helpers live inAcaiTreeSitter). Each plugin is self-contained — its parser, its language config, its build-system detector. AcaiLibrary— the composition root.AnalysisServiceholds the parser registry and dispatches by language; importing this one module gives you everything.AcaiDiagram— turns the model into DOT/Graphviz and Mermaid.AcaiRender— the diagram views, a Sugiyama hierarchical layout engine, and PNG rendering. Shared by the app and theacai imagecommand (Apple platforms only).AcaiMCP— a third entry point overAcaiLibrary(alongside the CLI and app): an in-process Model Context Protocol server (acai-mcp) that exposes the read-only analysis engine as tools an AI agent can call directly. Shipped with the bundledcode-qualityClaude Code plugin under.claude/plugins/, which pairs the server with theauditmethodology skill.
Full module-by-module documentation lives at pauljohanneskraft.github.io/Acai.
Everything the CLI and app are built on is a reusable library. Add Açaí as a dependency:
// Package.swift
dependencies: [
.package(url: "https://github.com/pauljohanneskraft/Acai.git", branch: "main"),
],
targets: [
.target(
name: "MyTool",
dependencies: [
.product(name: "AcaiLibrary", package: "Acai"), // analysis + all parsers
// or cherry-pick: .product(name: "AcaiCore", package: "Acai"),
// .product(name: "AcaiSwift", package: "Acai"),
]
),
]Then analyze a directory and walk the model:
import AcaiCore
import AcaiLibrary
let artifact = try AnalysisService.standard.analyzeProject(
at: URL(filePath: "/path/to/project"),
allowedLanguages: [.swift, .kotlin] // empty = every supported language
)
for type in artifact.types {
print(type.kind, type.qualifiedName)
}
for relationship in artifact.relationships {
print(relationship.source, "→", relationship.target, "(\(relationship.kind))")
}From there, AcaiDiagram's DOTGenerator produces Graphviz, and on Apple platforms AcaiRender's DiagramImageRenderer produces a PNG.
Available products: AcaiCore, AcaiTreeSitter, AcaiSwift, AcaiJVM (Java + Kotlin), AcaiJS, AcaiDart, AcaiPython, AcaiCFamily (C + C++), AcaiDiagram, AcaiLibrary, and (Apple platforms only) AcaiRender.
Full API documentation for every module lives at pauljohanneskraft.github.io/Acai — start with the Getting Started guide. To build the docs locally, run ./Scripts/docs_generate.sh and serve the output.
- Swift 6 toolchain.
- macOS 15+ for the app and for
acai image(native PNG rendering needs a window-server session). - Libraries and the rest of the CLI run on broader Apple platforms (iOS 16+, tvOS 16+, watchOS 9+, visionOS 1+) and on Linux.
- Graphviz (optional) — only to render DOT into images:
brew install graphviz.
swift build # Build everything
swift test --parallel # Run the test suiteCreate and install the binaries with the helper scripts (these build -c release --arch arm64 and assemble the .app bundle):
./Scripts/cli_create.sh # Produces `acai`
./Scripts/cli_install.sh # Installs it on your PATH
./Scripts/cli_uninstall.sh # Removes it
./Scripts/app_create.sh # Produces Acai.app
./Scripts/app_install.sh # Installs to /Applications/Acai.app
./Scripts/app_uninstall.sh # Removes itIssues and pull requests are welcome. Adding a language is the most common contribution — the existing Tree-sitter parsers under Sources/AcaiDart, Sources/AcaiPython, Sources/AcaiCFamily, and friends are a good template (a CodeParser conformance plus an AnalysisService registration). CI enforces swiftlint lint --strict and swift test --parallel on macOS and Linux.
MIT © Paul Johannes Kraft





