Palo
Palo is a local process manager for multi-service development environments.
It gives you a Docker Compose-like control plane without containers: define your
services in palo.yml, start them from one terminal dashboard, watch logs and
telemetry, restart on file changes, coordinate dependencies, and operate the
stack from a TUI or an optional MCP server.
Palo is built for source-first workflows where services run directly from your local checkout with your normal toolchains.

Features
- Declarative
palo.ymlservice configuration. - Generic process support for any command or executable.
- Rust project discovery with
palo init --type rust. - Dependency-aware startup and shutdown.
- Managed process lifecycle: start, stop, restart, crash handling, and shutdown.
- Build and check pipelines before service startup.
- Lifecycle hooks for build, start, and stop phases.
- HTTP health checks and command-based readiness checks.
- File watching with include, exclude, ignore paths, regex ignores, and debounce.
- Restart policies:
manual,mcp,never,change,crash, andalways. - Per-service environment variables and working directories.
- Live stdout/stderr capture in the terminal UI.
- Runtime telemetry for CPU, memory, uptime, open ports, and platform-supported disk/network counters.
- File logging for Palo runtime logs and managed application logs.
- Optional MCP control server for tool/agent integrations.
- Structured internal logging with
tracing.
Status
Palo is early software. The repository already contains the core runtime, configuration loader, Rust discovery, TUI, tests, examples, and MCP integration, but the public package may not be published yet. Install from a checkout today; use the crates.io command after the package is released.
Install
From Source
The repository root is a Cargo workspace, so install the binary crate from
palo/.
From crates.io
Quick Start
Generate a configuration for a Rust workspace:
Or create a commented template for any project:
Run with a custom config path:
CLI
palo init [--type rust|generic] [--overwrite]
palo new --template [--overwrite]
palo run [--config path]
palo init generates palo.yml from the current workspace. When --type is
omitted, Palo detects Rust projects by looking for Cargo.toml; otherwise it
falls back to generic mode. Existing configs are not overwritten unless
--overwrite is provided.
palo new --template writes a larger commented palo.yml template that shows
the available configuration fields.
palo run loads palo.yml, starts services with autostart: true, opens the
TUI, captures logs, and stops managed services before exit.
TUI Controls
| Key | Action |
|---|---|
j / Down |
Select next service |
k / Up |
Select previous service |
Tab / Right / l |
Move focus forward |
Shift+Tab / Left / h |
Move focus backward |
s |
Start selected service |
x |
Stop selected service |
r |
Restart selected service |
S |
Start all services |
X |
Stop all services |
R |
Restart all services |
: |
Open command mode |
q / Ctrl+C |
Quit |
Command mode accepts:
start
stop
restart
start all
stop all
restart all
quit
Mouse selection is supported in the service list.
Minimal Configuration
services:
api:
command:
By default, services use:
type: genericautostart: trueworking_dir: .restart.on: manual- in-memory log retention of
500lines
Generic Example
palo:
settings:
log_retention: 500
telemetry_refresh: 1s
logs:
enabled: true
directory: .palo/logs
palo: true
apps: true
services:
web:
type: generic
autostart: true
command:
working_dir: web
env:
NODE_ENV: development
PORT: "3000"
healthcheck:
url: http://127.0.0.1:3000/health
interval: 2s
timeout: 1s
retries: 30
restart:
on: change
watch:
paths:
- web
include:
- "src/**"
- "package.json"
exclude:
- "node_modules/**"
ignore_paths:
- web/.next
debounce: 500ms
worker:
type: generic
autostart: false
command:
working_dir: .
restart:
on: crash
max_crash_retries: 3
backoff: 1s
Rust Workspace Example
palo:
settings:
log_retention: 500
logs:
enabled: true
directory: .palo/logs
palo: true
apps: true
services:
api:
type: rust
autostart: true
target: debug
executable:
working_dir: .
env:
RUST_LOG: info
build:
check:
cmd:
healthcheck:
http:
url: http://127.0.0.1:8080/health
method: GET
expected_status: 200..399
initial_delay: 1s
interval: 5s
timeout: 2s
retries: 30
restart:
on: change
debounce: 2500ms
watch:
paths:
- .
include:
- "src/**/*.rs"
- "Cargo.toml"
exclude:
- "target/**"
ignore_paths:
- ".palo"
palo init --type rust discovers workspace members, runnable binary targets,
Cargo check/build commands, debug executable paths, and useful watch paths. If a
package has multiple binaries, set package.default-run in Cargo.toml or edit
the generated service manually.
Full Template
Use the built-in template when starting from scratch:
It writes a commented palo.yml with examples for:
- global settings
- file logging
- MCP settings
- Rust and generic services
- health checks
- legacy command readiness
- dependencies
- restart policies
- watch rules
- hooks
Configuration Reference
Global Settings
palo:
settings:
font_size: 14
log_retention: 500
telemetry_refresh: 1s
logs:
enabled: true
directory: .palo/logs
palo: true
apps: true
font_size is an optional UI hint for clients that support it.
log_retention sets the default number of in-memory log lines retained per
service.
telemetry_refresh is accepted as an optional refresh hint. Durations can be
human-readable strings such as 500ms, 1s, or 2m. Integer duration values
are interpreted as milliseconds.
logs can be either a boolean or an object. When enabled, Palo writes each run
under .palo/logs by default and can capture Palo runtime logs and application
stdout/stderr separately.
Services
services:
api:
type: rust
autostart: true
target: debug
command:
working_dir: .
Each service must define exactly one of command or executable.
command and executable accept either a shell-like string:
command: "cargo run --package api"
or an argument array:
command:
Argument arrays are recommended because they avoid shell quoting surprises.
Supported service types:
genericrust
Supported targets:
debugrelease
Environment
services:
api:
command:
env:
RUST_LOG: info
API_BIND: 127.0.0.1:8080
Environment variables are applied to run commands, build commands, readiness checks, and hooks for the service.
Build Pipeline
services:
api:
command:
build:
check:
cmd:
When a service starts, Palo can run:
hooks.pre_buildbuild.checkbuild.cmdhooks.post_build- the service command
hooks.post_start
Health Checks
services:
api:
command:
healthcheck:
http:
url: http://127.0.0.1:8080/health
method: GET
expected_status: 200..399
initial_delay: 1s
interval: 1s
timeout: 2s
retries: 30
Short form is also supported:
healthcheck:
url: http://127.0.0.1:8080/health
expected_status can be a single code such as 200 or a range such as
200..399.
Command Readiness
services:
worker:
command:
readiness:
command:
initial_delay: 500ms
interval: 1s
timeout: 2s
retries: 10
readiness is a command-based readiness check. Do not configure both
readiness and healthcheck on the same service.
Dependencies
Short form:
services:
api:
command:
depends_on:
db:
command:
Detailed form:
services:
api:
command:
depends_on:
db:
condition: ready
restart: true
required: true
timeout: 60s
Dependency conditions:
startedrunningready
Palo validates missing required dependencies, duplicate dependencies, self dependencies, and dependency cycles before runtime starts.
Restart Policies
restart:
on: manual
Supported policies:
| Policy | Behavior |
|---|---|
manual |
Restart only from the UI or command surface |
mcp |
Intended for MCP-controlled services; does not enable watching by default |
never |
Never restart automatically |
change |
Restart on matching file changes |
crash |
Restart after unexpected process exits |
always |
Restart whenever the process exits |
change accepts debounce:
restart:
on: change
debounce: 500ms
crash accepts max_crash_retries and backoff:
restart:
on: crash
max_crash_retries: 3
backoff: 1s
always accepts backoff.
File Watching
watch:
enabled: true
paths:
- .
include:
- "src/**/*.rs"
- "Cargo.toml"
exclude:
- "target/**"
ignore_paths:
- ".palo"
ignore_regex:
- "(^|/)generated/"
debounce: 500ms
For restart.on: change, watching is enabled by default and the default watch
path is the service working_dir. For other restart policies, watching is off
unless watch.enabled: true is set.
Hooks
hooks:
pre_build:
-
post_build:
-
pre_start:
-
post_start:
-
pre_stop:
-
post_stop:
-
Hook phases:
pre_buildpost_buildpre_startpost_startpre_stoppost_stop
Hooks inherit the service environment and working directory.
MCP Server
Palo can expose an MCP server for local tool and agent integrations.
palo:
mcp:
enabled: true
host: 127.0.0.1
port: 9464
path: /mcp
allowed_hosts:
allowed_origins:
stateful: true
json_response: false
log_retention: 512
When enabled, palo run starts the server next to the TUI. Available MCP tools
include:
runtime_statuslist_servicesget_servicelist_processesstart_servicestop_servicerestart_servicecheck_servicebuild_servicestart_all_servicesstop_all_servicesrestart_all_servicescheck_all_servicesbuild_all_servicesshow_logs
Keep MCP bound to localhost unless you have a deliberate reason to expose it.
Logs and Telemetry
Palo keeps recent logs in memory for the TUI and can also write logs to disk. The default file log directory is:
.palo/logs
The TUI shows:
- service lifecycle state
- service health
- recent stdout/stderr
- restart reasons
- last exit code
- last error
- PID
- CPU usage
- memory usage
- uptime
- open ports
- disk and network counters when available
Network telemetry is built per platform: macOS samples process traffic with
nettop, Linux reads process network namespace counters, and Windows or other
unsupported targets report it as unavailable rather than mixing in host-wide
traffic.
Internal runtime events use tracing, so you can adjust verbosity with
RUST_LOG:
RUST_LOG=debug,palo=debug,palo_core=debug,palo_projects=debug,palo_tui=info
Workspace Layout
palo-core/ Core config, domain model, execution, orchestration, events, watch, telemetry
palo/ CLI binary, runtime wiring, logging, MCP server
palo-projects/ Project discovery adapters, including Rust workspace discovery
palo-tui/ Ratatui dashboard and terminal event handling
examples/ Example palo.yml files
Development
Prerequisites:
- Rust toolchain with edition 2024 support.
- Cargo.
- Platform tools needed by the services you want Palo to run.
Clone and test:
Run the CLI from the workspace:
Run a specific test package:
Check formatting and linting before submitting changes:
Releasing
Releases are created by the GitHub Actions release workflow. The workflow runs only when a version tag is pushed, and the tag must match the workspace package version exactly.
Before releasing, update the workspace version in Cargo.toml and any internal
workspace dependency versions in member manifests, then validate the release
locally:
Create and push the matching version tag:
Replace 0.5.1 with the new version. On a successful tag build, GitHub Actions
builds release binaries, publishes the crates to crates.io in dependency order,
and creates the GitHub release with packaged assets.
The repository must have a crates.io token configured as either
CARGO_REGISTRY_TOKEN or CRATES_IO_TOKEN in GitHub Actions secrets. The
workflow also supports manual dispatch with an existing tag.
Examples
Example configs live in examples/:
examples/palo.generic.ymlexamples/palo.rust.ymlexamples/palo.mcp.yml
Copy one into a project as palo.yml and adjust service commands, ports, paths,
and environment variables.
License
MIT. See LICENSE.