Skip to main content
The Plan backend gives the LLM one meta-tool: execute_plan(steps). The LLM submits a JSON plan:a list of steps that execute sequentially, with later steps able to reference earlier results.

Setup

from concierge import Concierge, Config, ProviderType

app = Concierge(
    "my-server",
    config=Config(provider_type=ProviderType.PLAN),
)

How It Works

One LLM turn executes multiple tools in sequence. The LLM plans upfront, Concierge executes deterministically.

What the LLM Sends

{
  "steps": [
    {
      "id": "backup",
      "tool": "create_backup",
      "args": {"database": "prod"}
    },
    {
      "id": "validate",
      "tool": "validate_backup",
      "args": {
        "backup_id": {
          "output_by_reference": {"backup": ["backup_id"]}
        }
      }
    }
  ]
}
The output_by_reference resolves to the output of a previous step. Here, {"backup": ["backup_id"]} means: take the backup step’s result, then get ["backup_id"] from it.

Data Passing with Sharable

Only parameters annotated with Sharable() can receive referenced data:
from typing import Annotated
from concierge.core.sharable import Sharable

@app.tool()
def validate_backup(backup_id: Annotated[str, Sharable()]) -> dict:
    """Validate a backup by ID."""
    return {"valid": True, "backup_id": backup_id}
Only backward references are allowed:a step can only reference steps that come before it. No cycles, no self-references.

What the LLM Sees

A single tool:
[
  {
    "name": "execute_plan",
    "description": "Execute a sequential plan of tool calls.",
    "inputSchema": {
      "properties": {
        "steps": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {"type": "string"},
              "tool": {"type": "string"},
              "args": {"type": "object"}
            }
          }
        }
      }
    }
  }
]

When to Use

Use Plan when your workflow involves multiple steps with data dependencies:the output of one tool feeds into the next.
Good fit:
  • Multi-step workflows (backup → validate → migrate)
  • Data pipelines where steps depend on previous results
  • When you need deterministic, auditable execution
Bad fit:
  • Simple single-tool calls (Plain is simpler)
  • Conditional logic or loops (use Code)
  • Dynamic workflows where the next step depends on runtime decisions