Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Control Plane Reference

gRPC Service Definition

The control plane is exposed as a gRPC service defined in schemabound-proto.

service ControlPlaneService {
  rpc SubmitPlan    (SubmitPlanRequest)         returns (SubmitPlanResponse);
  rpc GetPlanStatus (GetPlanStatusRequest)      returns (GetPlanStatusResponse);
  rpc ExecuteStep   (ExecuteStepRequest)        returns (ExecuteStepResponse);
  rpc CancelPlan    (CancelPlanRequest)         returns (CancelPlanResponse);
  rpc StreamPlanEvents (StreamPlanEventsRequest) returns (stream PlanEvent);
}

Submit a Plan

message SubmitPlanRequest {
  string session_id   = 1;
  string name         = 2;
  string description  = 3;
  repeated PlanStepDef steps = 4;
}

message PlanStepDef {
  string step_id              = 1;
  string name                 = 2;
  string tool_name            = 3;
  string intent               = 4;
  string query_template       = 5;
  repeated string depends_on         = 6;
  repeated string schema_table_hints = 7;
}

A successful response returns a plan_id. All subsequent calls reference this identifier.

Execute a Step

message ExecuteStepRequest {
  string plan_id = 1;
  string step_id = 2;
}

message ExecuteStepResponse {
  bool              success           = 1;
  StepStatus        step_result       = 2;
  LlmContextUpdate  llm_context_update = 3;
  string            error_message     = 4;
}

The llm_context_update field is the value to pass back to the LLM before it chooses the next step.

Stream Plan Events

message StreamPlanEventsRequest {
  string plan_id = 1;
}

message PlanEvent {
  string plan_id    = 1;
  string event_type = 2;
  string payload_json = 3;
  string timestamp  = 4;
}

Event types include PlanCreated, PlanStepExecuted, PlanCompleted, and PlanFailed.

REST API Endpoints

Create a Plan

POST /api/plans
Content-Type: application/json

Request body

{
  "session_id": "sess-abc123",
  "name": "Customer order lookup",
  "description": "Find customer then retrieve their orders",
  "steps": [
    {
      "id": "lookup_customer",
      "name": "Look up customer by email",
      "tool_name": "query_customers",
      "intent": "read_select",
      "query_template": "SELECT id FROM customers WHERE email = 'alice@example.com'",
      "depends_on": [],
      "schema_table_hints": ["customers"]
    },
    {
      "id": "get_orders",
      "name": "Get orders for customer",
      "tool_name": "query_orders",
      "intent": "read_select",
      "query_template": "SELECT * FROM orders WHERE customer_id = {{step.lookup_customer.output}}",
      "depends_on": ["lookup_customer"],
      "schema_table_hints": ["orders"]
    }
  ]
}

Response

{
  "data": {
    "plan_id": "plan-8f1c2b3d",
    "status": "pending"
  }
}

Get Plan Status

GET /api/plans/:plan_id

Response

{
  "data": {
    "plan_id": "plan-8f1c2b3d",
    "status": "running",
    "steps": [
      { "step_id": "lookup_customer", "status": "completed" },
      { "step_id": "get_orders",      "status": "pending"   }
    ]
  }
}

Execute a Step

POST /api/plans/:plan_id/steps/:step_id/execute

Response

{
  "data": {
    "step_result": {
      "step_id": "lookup_customer",
      "status": "completed",
      "row_count": 1,
      "executed_at": "2026-04-20T14:00:00Z"
    },
    "llm_context_update": {
      "plan_id": "plan-8f1c2b3d",
      "step_id": "lookup_customer",
      "tool_output_json": "{\"id\": 42}",
      "schema_additions": [],
      "augmentation_hints": []
    }
  }
}

Cancel a Plan

DELETE /api/plans/:plan_id

OSS Trait Contract

The WorkflowOrchestrator trait in schemabound-public defines the full public interface. Any implementation — including custom ones — must satisfy:

#![allow(unused)]
fn main() {
#[async_trait]
pub trait WorkflowOrchestrator: Send + Sync {
    async fn create_plan(
        &self,
        session_id: &str,
        definition: PlanDefinition,
    ) -> Result<PlanRecord, String>;

    async fn get_plan(
        &self,
        plan_id: &str,
    ) -> Result<Option<PlanRecord>, String>;

    async fn execute_step(
        &self,
        plan_id: &str,
        step_id: &str,
        ctx: &QueryRuntimeContext,
    ) -> Result<(StepResult, LlmContextUpdate), String>;

    async fn cancel_plan(
        &self,
        plan_id: &str,
    ) -> Result<(), String>;
}
}

NoOpWorkflowOrchestrator is the default in OSS builds. It satisfies the trait boundary and returns an explicit error on any write operation, making the absence of a backing store visible rather than silent.