Palm is a lightweight, Python-first orchestration engine built on a clean Behavior Tree foundation. It coordinates interactive wizards, data pipelines, andβover timeβcompute-heavy workloads with explicit contracts, durable state, and human-first tooling.
Current release: 0.67.0 β capacity closed Β· VISION-0.62 Β· vitality VISION-0.61 Β· map PALM.md Β· CHANGELOG.md Β· ARCHITECTURE.md Β· docs/MCP.md
Palm is pre-1.0 and experimental. APIs, packages, and behaviors may break between minors. There is no LTS, no stability guarantee, and no promise of backward compatibility until a future 1.0 decision by JosΓ© Gabriel Gruber.
Use Palm to explore, dogfood, and build. Pin versions deliberately. Read STATUS.md, docs/VERSIONING.md, and MIGRATION notes when you upgrade. Structure and honesty matter more than comfort paths while the organism is still growing.
0.65 closed (outbox proof) β VISION-0.65 Β· ADR-034 Accepted. Prior VISION-0.64 closed. Seed law VISION-ASSEMBLY. No open minor.
Website: palmengine.org β website/ Β· build just website-build β website/dist (Cloudflare assets dir).
Palm is published on PyPI as palmengine. After install, you import palm and run the palm CLI β same names as in source development.
| What | Name |
|---|---|
| PyPI package | palmengine |
pip install |
pip install palmengine[cli] |
| Python import | import palm |
| CLI command | palm |
# End users β CLI + REPL
pip install palmengine[cli]
palm version --full
palm doctor
# Library only (no Rich / REPL)
pip install palmengine
# From source (contributors)
git clone https://github.com/JGabrielGruber/palmengine.git && cd palmengine
uv sync --group dev --extra cli
uv pip install -e ".[cli]"| Extra | What |
|---|---|
[cli] |
CLI + REPL |
[mcp] |
FastMCP (palm-mcp) |
[test] |
test deps |
[dev] |
contributor |
[all] |
cli + test subset (not every extra) |
[postgres] / [mongodb] |
empty; name reserved |
Palm aims to be simple at the core and powerful at the edges:
- Human-first β interactive wizards, Assist, MCP, backtracking, resume after interruption
- Truth-seeking β durable instances, one start path, one continue path, named debt
- Extensible β patterns, providers, storages, runners register at the edge; core stays pure
- Alive as a system β boot, planes, supervisor, vitality, capacity (in-process multi-claimer)
- Two axes of scale β vertical home and meaning; horizontal place registry (bodies across hosts)
- Horizon path β assembly β tunnels β Grove
- Fit for living work β datasets, training flows, TinyML and model bodies as places under one genome
Behavior Trees are the control-flow foundation for business. Organism topology (assembly, home, places) is a different care β do not confuse the two. Org/realm speech means recursive support, not a second product. Cross-cutting concerns belong in system seats and thin surfaces β not buried in step JSON.
Read next: docs/PALM.md (Β§8 scale) Β· STATUS.md Β· docs/vision/ Β· PHILOSOPHY.md
| Area | Capabilities |
|---|---|
| Resources | ResourceDefinition, ResourceEngine.invoke(), ResourceLeaf, ResourceCatalog; wizard step_kind: resource |
palm provider |
Palm calling Palm β local submit_flow / invoke_resource or remote HTTP; recursion guardrails |
| ApplicationHost | Top-level orchestrator β role profiles (all_in_one, master, worker, server), startup recovery |
| CQRS | Command/query buses; host projections (instance_index, job_status_board, resource_invocations); wizard projection registered by WizardApp |
| Reliability | Transactional outbox, compensation handlers (including resource undo). Webhook organ does not POST |
| Core | Behavior tree, orchestration, context, storage, resource, event, auth, TransformEngine |
| State | DictStateSchema, scoped state, schema-aware snapshots (__palm:meta) |
| Transforms | 22 built-in rules β field shaping, JSONPath, dates, conditionals, serialization, enrich_resource |
| Patterns | PatternApp manifests + bindings//flow/ layout; Wizard, parallel, pipeline, dag (installed); etl intention-only β see docs/PATTERN-APPS.md Β· docs/STUBS.md |
| Persistence | Filesystem backend, InstanceManager, durable resume across restarts |
| Runtimes | EmbeddedRuntime, DaemonRuntime, ServerRuntime (HTTP), CLI + REPL (host-backed) |
| Palm Explorer | SSR hub at /explorer β flows, jobs, instances, wizard workspace (HTMX + collection editor), resources; / redirects here |
| Flow REST (0.16) | Continue: /v1/api/flows/{flow_id}/instance/{instance_id}/β¦ Β· create: POST β¦/flows/{flow_id}/create Β· Explorer: /explorer/instances/<instance_id> |
| Definitions REST (0.16) | /v1/api/definitions/β¦ β catalog reads + CRUD writes |
| Definition revisions (0.24) | Append-only flow revisions, flow_revision pin, impact query, instance migrate β MIGRATION-0.24.md |
| Design Service (0.25+) | Propose β impact β commit Β· one-shot palm_design_publish_* / palm_assist(params={body}) β VISION-0.25.md |
| Local resources (0.28β0.29) | kv / file / tiered backends; coconut-npc cross-session profile |
| MCP (0.16β0.31) | palm-mcp Β· palm_assist meta-tool Β· PALM_MCP_SURFACE=assist slim catalog Β· palm://agent/card progressive docs β docs/MCP.md Β· VISION-0.31.md |
| Dashboard | palm status β projection-backed Rich overview; --full, -r live refresh |
| DX | Rich examples, palm doctor, REPL resource * / assist *, just quality recipes |
flowchart LR
User[Developer / operator] --> CLI[CLI / REPL]
CLI --> Host[ApplicationHost]
Host --> CQRS[Command + Query buses]
Host --> RT[Runtime main]
CQRS --> Proj[Projections]
RT --> CM[common + patterns]
CM --> BT[Behavior Tree]
Recommended entrypoint: ApplicationHost wraps PalmKernel (infrastructure) and wires CQRS, projections, outbox, and compensation. The CLI uses it automatically via create_cli_host().
pip install palmengine[cli]
palm # interactive REPL (default)
palm repl # same as bare palm
palm status # live projection dashboard (command, not default)
palm doctor # full health report
palm version --full # version + registered plugins
palm flow start onboard # recommended β works for all patterns
# shortcut: palm start onboardFrom source: uv sync --group dev --extra cli && uv pip install -e ".[cli]" then the same palm commands.
Library quick start (ApplicationHost):
from palm.app import ApplicationHost, DeploymentProfile
with ApplicationHost(profile=DeploymentProfile.all_in_one()) as host:
job = host.submit_flow("onboard")
rows = host.list_instance_views(include_terminal=False)
print(job.status.value, len(rows))Demo script: uv run python examples/full_demo.py (host + resume across restart).
Coding agents (Cursor, Grok, Claude) can operate Palm wizards headlessly via MCP β no curl, no JSON blobs.
uv sync --extra mcp
PALM_MCP_IN_PROCESS=1 uv run --extra mcp palm-mcp # local default β no REST server
# Remote: just palm-server + PALM_MCP_IN_PROCESS=0Connect your IDE to the palm-mcp stdio server (pip install "palmengine[mcp]"). Read the Agent development guide for workflows, conventions, and the full tool list.
Operator loop: definitions β create session β inspect β input β wait on children β resume.
Key conventions: use session_id for flow sessions; pass plain input strings (yes, choice slugs, text); read palm://agent/guide (docs/mcp.txt) and palm://agent/skill at session start. Portable skill: docs/skills/palm/.
Docker (host server + Explorer):
just docker-up # build + start on :8080, ./data + ./logs volumes
open http://localhost:8080/explorer
just docker-logs # noisy logs β by designFull stack guide: docs/DOCKER.md β volumes, HTTP MCP against the container, env vars, troubleshooting.
Server + Palm Explorer (local Python):
# Start HTTP server (default port 8080)
python -c "from palm.runtimes.server import ServerRuntime, run_server; run_server(ServerRuntime())"
# Open the living hub β flows, jobs, instances, schemas
open http://localhost:8080/explorer # or just http://localhost:8080/ (redirects)REST reference: GET /v1/docs Β· OpenAPI: GET /v1/openapi.json Β· Health: GET /health
The instance detail page is a live wizard workspace β progress bar, prompt card, answers, timeline, and backtrack. Collection steps get a rich multi-item editor (add / edit / remove) with HTMX partial updates.
# 1. Start server
python -c "from palm.runtimes.server import ServerRuntime, run_server; run_server(ServerRuntime())"
# 2. Submit todo-builder (collection demo)
curl -s -X POST http://localhost:8080/v1/api/flows/todo-builder/create \
-H 'Content-Type: application/json' \
-d '{"flow_name": "todo-builder"}'
# β copy session_id from JSON
# 3. Open workspace
open http://localhost:8080/explorer/instances/<session_id>Use Add New on the collection overview, fill fields, edit or remove items, then Continue to summary. Full guide: EXPLORER-WIZARD.md.
Try the new examples:
palm flow start schema-onboard # layered state schemas + scopes
palm flow start todo-builder # dynamic todo list (collection step)
palm flow start parallel-demo # parallel wizard branches
palm flow start transform-example # wizard transform steps
palm flow start transform-shaping # pipeline calculate / lookup / conditional
palm flow start transform-formats # json_load β csv_dump ETL-style pipelineDeclarative data shaping via registered rules β usable in pipelines, wizard steps (step_kind: transform), or TransformLeaf nodes.
from palm.common.transforms import TransformExecutor, autoload
autoload()
executor = TransformExecutor()
result = executor.apply(
"string_format",
"ada",
template="Hello, {value}!",
case="title",
)
# β "Hello, Ada!"# Wizard step (in flow options.steps)
step_kind: transform
source_key: name
target_key: greeting
rule: string_format
options:
template: "Hello, {value}!"
case: titleRun palm doctor for the full rule catalog with descriptions. Extend with register_transform("my_rule", MyRule) at bootstrap.
CLI persistence: the CLI bootstraps ApplicationHost (all_in_one profile). By default it uses in-memory storage (fast, non-durable). Set durable storage via flags or environment:
# Recommended for local work β persists instances under ./data/
export PALM_STORAGE_BACKEND=filesystem
export PALM_DATA_DIR=./data
# Or per invocation:
palm --storage-backend filesystem --data-dir ./data flow start onboardpalm doctor and REPL startup show whether state will survive restarts.
Instance commands (list, status, snapshots) read through the host query bus and projections. Writes (flow start, input, resume) go through the command bus. Short ids from instance list work with prefix matching.
Global CLI flags (override env only when explicitly passed):
| Flag | Env | Purpose |
|---|---|---|
-b / --storage-backend |
PALM_STORAGE_BACKEND |
Storage backend (memory, filesystem, β¦) |
-d / --data-dir |
PALM_DATA_DIR |
Data directory for durable backends |
--config |
β | Optional .env-style config file |
-S / --enable-state-snapshot |
PALM_ENABLE_STATE_SNAPSHOT |
Capture state snapshot history |
--max-loaded-instances |
PALM_MAX_LOADED_INSTANCES |
InstanceManager LRU size |
--max-concurrent-active |
PALM_MAX_CONCURRENT_ACTIVE |
Active instance cap |
--scheduler |
PALM_DEFAULT_SCHEDULER |
inline or queued |
--format |
β | table (default) or json for scripting |
Settings precedence: PALM_* environment β --config file β CLI flags.
palm instance list # active (non-terminal) instances
palm instance list --all --format json # all instances, JSON for scripts
palm instance list --status WAITING_FOR_INPUT --flow quick
palm instance prune --dry-run # preview terminal instance cleanup
palm --format json instance status <id> # machine-readable statusThe REPL uses smart tab-completion for commands, flow/process names, and instance ids
(active by default; --all includes terminal instances).
Process instances snapshot orchestrated workβwizard answers, step, statusβand persist through storage so sessions survive restarts.
palm flow start onboard
palm input Ada
palm instance list # note instance id
# Later, or in a new terminal:
palm instance resume <instance_id>
palm input ada@example.com
# β¦ continue through summary and commitShared StorageEngine across runtime lifetimes is required for cross-process resume (see DEVELOPMENT.md).
Durable filesystem storage (recommended for local dev and single-node deploys):
export PALM_STORAGE_BACKEND=filesystem
export PALM_DATA_DIR=./data # optional; defaults to ./data
palm flow start onboard
palm input Ada
# Restart the CLI β instances and definitions persist under ./data/
palm instance resume <instance_id>Palm can record point-in-time blackboard captures at selected job status transitionsβuseful for audit trails, debugging wizard flows, and future time-travel replay. Snapshots are stored on each ProcessInstance as a bounded ring buffer (state_snapshots[]). The feature is off by default.
Enable via environment:
export PALM_ENABLE_STATE_SNAPSHOT=true
export PALM_SNAPSHOT_ON_STATUS='["WAITING_FOR_INPUT","SUCCEEDED","FAILED"]'
export PALM_MAX_SNAPSHOTS_PER_INSTANCE=10
palm flow start onboard
palm input Ada
palm instance snapshots <instance_id> # inspect captured historyEnable in code:
from palm.app import ApplicationHost, DeploymentProfile, PalmSettings
settings = PalmSettings(
enable_state_snapshot=True,
snapshot_on_status=["WAITING_FOR_INPUT", "SUCCEEDED"],
max_snapshots_per_instance=5,
)
with ApplicationHost(settings, profile=DeploymentProfile.all_in_one()) as host:
job = host.submit_flow("onboard")
snapshots = host.list_instance_snapshots(job.metadata["instance_id"])Resume still uses the latest state_snapshot field (maintained by InstancePersistenceHook). Historical entries are for inspectionβnot replay yet. See ARCHITECTURE.md for middleware design and trade-offs.
Definitions under examples/definitions/ auto-register at CLI startup.
| Example | Command | Highlights |
|---|---|---|
| Onboarding | flow start onboard |
Validation, summary + commit |
| Schema wizard | flow start schema-onboard |
Flow + per-step schemas, scoped resume |
| Todo builder | flow start todo-builder |
Collection step, dynamic lists, schemas |
| Parallel demo | flow start parallel-demo |
Concurrent branches, merge, branch scopes |
| Data ingestion | flow start ingest-wizard |
Resource action step, ETL companion flow |
| Approval | flow start approval |
Multi-field validation, commit handler |
| Quick demo | flow start quick |
Minimal wizard for resume experiments |
palm process list
palm process submit data-ingestion
palm doctor # shows flows with state schemasDetails: examples/README.md
When ServerRuntime is running, Palm Explorer is the browser-first control surface for operators and integrators:
| Path | Purpose |
|---|---|
/explorer |
Overview β registered flows, active jobs, instance counts |
/explorer/flows |
Flow catalog with Start this flow actions |
/explorer/flows/submit |
Schema-driven flow submission (registered or test wizard) |
/explorer/jobs |
Job board with wizard input forms |
/explorer/instances |
Durable process instance browser |
/explorer/schemas |
State schema introspection |
Legacy /wiki/* and /docs redirect to /explorer. Implementation: palm/runtimes/server/surfaces/ssr/explorer/.
| Command | Description |
|---|---|
palm / palm repl |
Interactive REPL (host-backed; default) |
palm status |
Live dashboard β instances, wizards, jobs, host events (command, not default) |
palm status --full |
Detailed dashboard (active rows, traces) |
palm status -r |
Live refresh every 2s (Ctrl+C to stop) |
palm doctor |
Full health report: plugins, persistence, definitions |
palm version --full |
Version, Python, registered patterns/providers/storages |
palm process list | submit |
Definition catalog and process submit |
palm instance list |
Instances via CQRS projection |
palm instance resume <id> |
Resume a persisted instance |
palm instance snapshots <id> |
State snapshot history (when enabled) |
palm flow start <flow> |
Start any flow β recommended |
palm start <flow> |
Shortcut for flow start |
resource * / assist * |
REPL-only β palm repl then resource list / describe / invoke |
palm input / palm back |
Drive or rewind an active flow |
palm host all-in-one |
Run ApplicationHost (blocking, signals) |
palm host master | worker | server |
Role-based deployment |
Run palm --help for the full list.
src/palm/
βββ app/ # ApplicationHost, PalmKernel (infra), settings, host roles
βββ core/ # Pure engines (BT, orchestration, context, storage, β¦)
βββ common/ # CQRS, outbox, compensation, hooks, persistence, managers
βββ instances/ # ProcessInstance + StateSnapshot models
βββ definitions/ # FlowDefinition, ProcessDefinition
βββ patterns/ # wizard, dag, etl (extensible)
βββ providers/ # rest, graphql, postgres (extensible)
βββ storages/ # memory, filesystem, postgres, mongodb (extensible)
βββ runtimes/ # Embedded/Daemon/Server, CLI (host-backed)
examples/ # definitions/ + full_demo.py (ApplicationHost)
SCOPE.md # vision, scope, roadmap
ARCHITECTURE.md # layers, ApplicationHost, CQRS, reliability
docs/migrations/ # upgrade guides (MIGRATION-0.X.md)
docs/releases/ # point-release checklists (RELEASE-0.X.Y.md)
archive/ # legacy + experimental (not imported)
- Define once, reference everywhere β register
ResourceDefinitionin the repository; useresource_refin wizards,ResourceLeafin behavior trees, andenrich_resourcein transforms. - Prefer declarative params β bind with
{{ state.key }}; promote wizard answers before resource steps (promote_binding_keys()). - Compose with the
palmprovider β delegate sub-flows locally or viaremote_url; rely on built-in depth/cycle guardrails. - Observe
resource.*events β completed/failed payloads include correlation (invoke_depth,invoke_chain,parent_job_id). - Cache reads, not writes β keep
resource_cache_definitionson; enableresource_cache_resultsonly for idempotentfetchactions. - Discover before invoke β
palm doctor, REPLresource list/describe, and Explorer/explorer/resourcesshow actions and schemas.
palm resource list
palm resource describe fetch-customer
palm resource invoke fetch-customer customer_id=42Full guide: docs/vision/closed/VISION-0.12.md Β· MIGRATION-0.12.md
High-level direction (not all shipped yet). Full detail in SCOPE.md.
| Theme | Direction |
|---|---|
| Runtimes | WebSocket Assist channel + Portal backend (VISION-0.32), persistent plan registry, richer server auth |
| Middleware | Runtime-level auth/observability; optional BT guard nodes for step policy |
| Compute | KernelLeaf GPU nodes, resident kernels, dataset staging (Parquet β context β kernel β artifact) |
| Observability | Structured events, long-running job management |
GPU batch prototypes live in archive/experimental/gpubatches/ as early R&Dβnot part of the supported API until promoted.
---
title: CPU vs GPU Execution Time
---
xychart
title "CPU vs GPU Batch Processing Time"
x-axis "Batch Size" ["32K", "65K", "131K", "262K"]
y-axis "Time (seconds)" 0 --> 60
line "CPU" [8.28, 14.37, 28.64, 57.14]
line "GPU" [0.026, 0.051, 0.100, 0.200]
| Document | Contents |
|---|---|
| SCOPE.md | Purpose, horizon, experimental honesty (not a frozen old roadmap) |
| docs/vision/closed/VISION-0.64.md | Closed β first capability work_drain |
| docs/vision/VISION-ASSEMBLY.md | Seed essay β roles Β· ports Β· citizenship |
| PHILOSOPHY.md | Spirit β grown, not built; glory and shackles |
| ARCHITECTURE.md | Layers, BT control flow, middleware model, engines |
| DEVELOPMENT.md | Setup, tests, adding patterns/backends |
| AGENTS.md | Rules for contributors and AI agents |
just dev # setup
just check # lint + types + tests
just palm-doctor # CLI health
just demo-full # end-to-end scriptπ΄ Palm grows where the sun meets the sea.
Orchestration should balance structure with flexibilityβautomation with mindful human participation. Palm keeps the core small and truthful, puts people first in interactive flows, and grows capability through registries and nodes rather than monolithic middleware.
Two habits keep that promise honest as Palm grows:
- Register downward. Shared state lives in the low layers; capabilities register into it from above β a new pattern, provider, or storage is a new module that registers itself, never an edit to the core. Extension is addition, not surgery.
- Coherence is a fitness function. Palm's layering and import graph aren't just conventions β they're checked (
guard_core,guard_deferred, wired intojust ci) and only ever ratchet tighter. The architecture defends its own shape, which is what lets it be refactored fearlessly.
For the spirit beneath the surface β what Palm is, not just what it does β see PHILOSOPHY.md.
- 0.11.x β 0.12 Compositional Power β see MIGRATION-0.12.md for wizard
step_kind: resourceand removedactionsteps - 0.9.x β 0.10 architecture β see MIGRATION-0.10.md for
ApplicationHost, CQRS, and removedbootstrap_cli/cli/pkgpaths - 0.5.x β 0.6.0 β see MIGRATION-0.6.md for removed aliases (
ExecutionBackend,EmbeddedMode, etc.) - 0.3.x legacy β code under
archive/is reference-only; never import fromarchive/in new work
MIT