Python planning library · Compile & execute · AGPL-3.0

Plan once,
execute deterministically.

ltpmcp implements LTP (Lean Task Protocol): one LLM call compiles a goal into a structured plan, then a pure-Python runtime executes it step-by-step — variables, conditionals, FOREACH loops, parallel groups, ON_FAIL handling, and mid-plan RE-PLAN. Use it as a library, or run its CLI and MCP server (3 tools).

agent_plan.py
from ltpmcp import LTPCompiler, LTPRuntime

# You supply two async callbacks:
#   llm_fn(messages) -> str
#   tool_executor(tool_name, args, namespace) -> dict

# 1. Compile a goal into a plan (1 LLM call) -> LTPPlan | None
compiler = LTPCompiler(llm_fn=my_llm)
plan = await compiler.compile("What is the weather in Ibiza?")

# 2. Execute the plan deterministically
runtime = LTPRuntime()
result = await runtime.execute(
    plan,
    tool_executor=my_tools,
    llm_fn=my_llm,
)
print(result["response"])
Deterministic runtimeConditionals & loops
Library · CLI · MCP server
Plan DSL
1-call compile
FOREACH & parallel
ON_FAIL / RE-PLAN
Provable plans
Python 3.11+

Separate planning
from execution

Single-call compilation

Convert a natural-language goal into a structured execution plan with one LLM call, using a compact Micro-CLI syntax.

LTPCompilerMicro-CLI

Deterministic runtime

A pure-Python engine executes the plan step-by-step with explicit $variable passing — no LLM in the control loop.

LTPRuntime$variables

Conditionals & FOREACH

?IF conditions are evaluated in Python (==, !=, >, <, contains, NOT_EMPTY, IS_EMPTY). ?FOREACH iterates over list variables.

?IF?FOREACH

ON_FAIL handling

Per-step resilience: @RETRY(N) with backoff, GOTO a fallback step, or TERMINATE with a message.

RETRYGOTOTERMINATE

RE-PLAN & parallel

Recompile mid-execution when results invalidate the approach. Run steps in the same parallel_group concurrently.

RE-PLAN@PARALLEL

Validate & visualize

validate_plan flags undefined vars, unreachable steps, circular GOTOs and duplicate IDs. plan_to_mermaid renders a flowchart.

validate_planplan_to_mermaid

Provable plans

Because the whole plan is compiled before anything runs, you can statically verify it against a policy with verify_plan(plan, PlanPolicy(...)) — and refuse it before step 1. Checks tool allow/deny lists, a step budget, runtime escape hatches (RE-PLAN / sub-agents), a no-egress-after-sensitive-read data-flow rule, and secret/path argument patterns. Returns a verdict with the exact violations; it never executes anything.

verify_planPlanPolicyrefuse-before-run

Import it.
Compile and run.

1

Install

One pip install. Core deps: pydantic, structlog, click, mcp.

pip install mcpaisuite-ltpmcp
2

Compile

Turn a goal into a plan in one LLM call. Returns an LTPPlan, or None on failure.

plan = await LTPCompiler( llm_fn=my_llm ).compile("…")
3

Execute

Run the plan deterministically; your tool_executor handles each @TOOL.

res = await LTPRuntime().execute( plan, my_tools, my_llm )
4

Inspect

Validate before running, or render the plan as a Mermaid diagram.

validate_plan(plan) plan_to_mermaid(plan)

A small DSL for
structured tasks

ConstructDescription
?IFCondition?IF ($var op value) THEN …, evaluated in Python (==, !=, >, <, >=, <=, contains, NOT_EMPTY, IS_EMPTY)
?FOREACHIteration?FOREACH ($item IN $list) THEN …, collects results into the output variable
@PARALLELParallel — steps sharing a parallel_group run concurrently via asyncio
ON_FAILError handling@RETRY(N), GOTO Sn, or TERMINATE ("msg") on step failure
RE-PLANMid-plan pivot — recompile with collected-variable context when results invalidate the plan (capped by max_replans, default 3)
:typeType casting> $var:int casts output to int, float, list, bool, or json
$var.fieldDot notation — traverse JSON fields without an extra LLM call

Host / shell instructions are also available in plans: @HOST_EXEC, @HOST_FILE_READ, @HOST_FILE_LIST, @SHELL_EXEC. Every @TOOL is routed to the tool_executor callback you provide — ltpmcp never runs tools itself.

Give your agent
a plan it can trust.

Read the docs View on PyPI