This document provides a high-level introduction to tutti, explaining its purpose, architecture philosophy, and system design. For installation instructions, see Installation. For detailed architecture documentation, see Architecture. For practical usage examples, see Quick Start Tutorial.
Tutti is a native process orchestration tool designed for local development workflows. It manages multiple interdependent services on a developer's machine without containerization. The system reads service definitions from a TOML configuration file, resolves dependencies using topological sorting, spawns processes in correct order, and aggregates logs from all services into a single stream.
The project is structured as a Rust workspace containing six crates that work together to provide process orchestration, inter-process communication, and configuration management.
Sources: README.md1-16 docs/motivation.md1-9
Tutti orchestrates local services by managing their lifecycle, dependencies, and output. A developer defines services in a tutti.toml file, specifying the command to run, working directory, environment variables, dependencies on other services, and restart policies. The tutti-cli command starts all services in dependency order and streams their logs to the terminal.
The system consists of two primary executables:
tutti-cli: The command-line interface that users interact withtutti-daemon: A background process that manages service lifecycleWhen a user runs tutti-cli run -f tutti.toml, the CLI parses the configuration, spawns or connects to a daemon, and instructs it to start the services. The daemon uses the tutti-core supervisor to manage process spawning, monitoring, and termination. All communication between CLI and daemon occurs over Unix domain sockets using length-delimited JSON messages.
Sources: README.md16-43 Cargo.lock694-706
Tutti manages native OS processes directly rather than using containers. Each service defined in tutti.toml becomes a child process spawned by the UnixProcessManager implementation in tutti-core. This approach avoids the overhead of containerization while providing dependency ordering and log aggregation.
Sources: docs/motivation.md1-9
The system uses a persistent daemon process (tutti-daemon) that remains running across multiple CLI invocations. This design allows:
The daemon creates a Unix domain socket at a well-known path for IPC communication. The socket path is determined at runtime based on the project configuration.
Sources: Cargo.lock734-743
All components use tokio as the async runtime (version 1.48.0). The Supervisor in tutti-core runs a background task that processes commands concurrently while managing service state transitions. Process output streams are handled asynchronously using tokio-stream and tokio-util.
Sources: Cargo.lock546-595
Communication between CLI and daemon uses a strongly-typed protocol defined in tutti-transport. Messages are serialized as JSON and framed using tokio_util::codec::LengthDelimitedCodec. The TuttiApi enum in tutti-types defines all possible operations (Up, Down, Ping, Shutdown, Subscribe) ensuring compile-time correctness.
Sources: Cargo.lock746-757
| Aspect | Tutti | Docker Compose |
|---|---|---|
| Target Use Case | Local development only | Development and production |
| Process Model | Native OS processes | Containerized processes |
| Build Requirements | None (runs existing executables) | Docker image builds required |
| Startup Speed | Immediate (no build step) | Slower (image pulls/builds) |
| Resource Usage | Minimal overhead | Higher (container runtime) |
| Configuration Format | TOML (tutti.toml) | YAML (docker-compose.yml) |
| Dependency Resolution | Topological sort of deps field | depends_on with health checks |
| Platform | Linux/macOS (Unix sockets) | Cross-platform |
| Production Ready | No | Yes |
Tutti is optimized for rapid local iteration where services are already runnable on the host machine. It eliminates Docker's rebuild cycle, which is particularly slow on macOS. For production deployments, Docker Compose remains the appropriate choice.
Sources: README.md44-46 docs/motivation.md1-9
The following diagram maps the runtime architecture to specific code entities in the workspace:
This diagram shows how the abstract system layers map to concrete types and functions in the codebase. The tutti-cli binary parses commands using the Command enum, connects to the daemon via IpcClient, and sends TuttiApi messages. The daemon accepts connections through IpcServer and delegates orchestration to the Supervisor struct, which runs supervisor_background_task() to manage service lifecycle through UnixProcessManager.
Sources: Cargo.lock694-764 crates/tutti-core/src/error.rs1-19
The workspace is organized into six crates with clear dependency boundaries:
| Crate | Version | Key Components | External Dependencies |
|---|---|---|---|
tutti-cli | 0.1.5 | main.rs, Command enum, Logger struct | clap (4.5.58), colored (3.1.1), tokio (1.48.0) |
tutti-daemon | 0.1.5 | spawn_daemon(), daemon lifecycle management | tokio (1.48.0), libc (0.2.182), futures-util (0.3.31) |
tutti-core | 0.1.5 | Supervisor, ProcessManager trait, UnixProcessManager, Error enum | tokio (1.48.0), tokio-stream (0.1.18), async-trait (0.1.89) |
tutti-transport | 0.1.5 | IpcClient, IpcServer, TuttiMessage, TuttiApi handling | tokio (1.48.0), tokio-util (0.7.18), serde_json (1.0.149) |
tutti-config | 0.1.5 | parse_file(), RawProject, TOML validation | toml (1.0.1), serde (1.0.228), thiserror (2.0.18) |
tutti-types | 0.1.5 | Project, Service, TuttiApi, ProjectId, RunningService | serde (1.0.228) only |
The dependency structure ensures tutti-types has no dependencies on other tutti crates, making it the foundation for all other components. The middle layer (tutti-core, tutti-transport, tutti-config) has no interdependencies. The tutti-daemon crate provides the daemon spawning logic consumed by tutti-cli.
Sources: Cargo.lock694-764
A service is defined by:
cmd: Array of command and arguments (required)deps: Array of service names this service depends on (optional)env: Map of environment variable names to values (optional)cwd: Working directory path (optional)restart: Restart policy - "never", "always", or "on-failure" (optional)Sources: README.md84-111
Services are started in dependency order using topological sorting. The algorithm is implemented in tutti-core and ensures:
The dependency graph is constructed from the deps field of each Service struct in the Project. The topological sort produces a startup order that respects all dependency edges. If a cycle is detected, the system returns Error::CircularDependencyDetected defined at crates/tutti-core/src/error.rs17
The following diagram shows the dependency resolution flow:
Sources: crates/tutti-core/src/error.rs1-19
All service output (stdout and stderr) is captured by the process manager and streamed to the CLI through the daemon. The CLI prefixes each line with the service name using colored output from the colored crate (version 3.1.1).
Sources: Cargo.lock137-143 README.md76-80
Each service transitions through states managed by the Supervisor struct in tutti-core. The state machine is represented by the ServiceState enum:
The Supervisor maintains a map of ProjectId to RunningProject, where each RunningProject contains a map of service names to their current state. The daemon persists across CLI sessions, maintaining service state even when the CLI disconnects. State transitions trigger SupervisorEvent emissions that are sent to connected IPC clients.
Sources: crates/tutti-core/src/error.rs1-19 Cargo.lock719-731
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.