CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-embabel-agent--embabel-agent-api

Fluent DSL and Kotlin DSL for building autonomous agents with planning capabilities on the JVM, featuring annotation-based and programmatic configuration for agentic flows with Spring Boot integration

Overview
Eval results
Files

platform-management.mddocs/

Platform and Process Management

The platform and process management APIs provide the core infrastructure for running and managing agent processes. The AgentPlatform acts as the execution environment for agents, while AgentProcess represents individual running instances with their own lifecycle, state, and control mechanisms.

Capabilities

AgentPlatform Interface

The AgentPlatform is the central execution environment for agents. It manages agent deployment, process creation, and lifecycle operations.

import com.embabel.agent.core.AgentPlatform
import com.embabel.agent.core.Agent
import com.embabel.agent.core.AgentProcess
import com.embabel.agent.core.ProcessOptions
import com.embabel.agent.api.common.PlatformServices
import com.embabel.agent.spi.ToolGroupResolver
import java.util.concurrent.CompletableFuture

interface AgentPlatform : AgentScope {
    /** Core services provided by the platform */
    val platformServices: PlatformServices

    /** Resolver for tool groups */
    val toolGroupResolver: ToolGroupResolver

    /** Find an agent process by ID (running processes only) */
    fun getAgentProcess(id: String): AgentProcess?

    /** Kill an agent process by ID, returns the killed process or null */
    fun killAgentProcess(id: String): AgentProcess?

    /** Get all deployed agents */
    fun agents(): List<Agent>

    /** Deploy an agent to the platform */
    fun deploy(agent: Agent): AgentPlatform

    /** Deploy an agent scope to the platform */
    fun deploy(agentScope: AgentScope): AgentPlatform

    /** Run an agent with the given options and bindings */
    fun runAgentFrom(
        agent: Agent,
        processOptions: ProcessOptions = ProcessOptions(),
        bindings: Map<String, Any>
    ): AgentProcess

    /** Create an agent process without starting it (status: NOT_STARTED) */
    fun createAgentProcess(
        agent: Agent,
        processOptions: ProcessOptions,
        bindings: Map<String, Any>
    ): AgentProcess

    /** Create an agent process and bind objects to the blackboard */
    fun createAgentProcessFrom(
        agent: Agent,
        processOptions: ProcessOptions,
        vararg objectsToAdd: Any
    ): AgentProcess

    /** Run an agent process in the background asynchronously */
    fun start(agentProcess: AgentProcess): CompletableFuture<AgentProcess>

    /** Create a child process from a parent agent process */
    fun createChildProcess(
        agent: Agent,
        parentAgentProcess: AgentProcess
    ): AgentProcess

    /** All domain types from deployed agents */
    override val domainTypes: Collection<DomainType>

    /** All actions from deployed agents */
    override val actions: List<Action>

    /** All goals from deployed agents */
    override val goals: Set<Goal>

    /** All conditions from deployed agents */
    override val conditions: Set<Condition>
}

Basic Usage:

@Action(description = "Run data processing agent")
fun processData(
    dataSource: DataSource,
    platform: AgentPlatform,
    context: ActionContext
): ProcessingResult {
    // Create process with custom options
    val process = platform.createAgentProcessFrom(
        agent = dataProcessingAgent,
        processOptions = ProcessOptions()
            .withBudget(Budget(cost = 1.0, actions = 30))
            .withVerbosity(Verbosity().showPlanning()),
        dataSource,
        context.blackboard()
    )

    // Run the process
    val completedProcess = process.run()

    // Extract result
    return completedProcess.resultOfType<ProcessingResult>()
}

Asynchronous Execution:

@Action(description = "Start analysis in background")
fun startBackgroundAnalysis(
    data: Dataset,
    platform: AgentPlatform
): String {
    val process = platform.createAgentProcess(
        agent = analysisAgent,
        processOptions = ProcessOptions(),
        bindings = mapOf("dataset" to data)
    )

    // Start async and return immediately
    val future = platform.start(process)

    // Can monitor later
    future.thenAccept { completed ->
        println("Analysis completed: ${completed.id}")
    }

    return "Started analysis process: ${process.id}"
}

AgentProcess Interface

Represents a running instance of an agent with its own state, lifecycle, and execution control.

import com.embabel.agent.core.AgentProcess
import com.embabel.agent.core.AgentProcessStatusCode
import com.embabel.agent.core.Agent
import com.embabel.agent.core.Blackboard
import com.embabel.agent.core.ProcessOptions
import com.embabel.agent.core.ProcessContext
import com.embabel.agent.core.LlmInvocation
import com.embabel.agent.api.event.ProcessKilledEvent
import com.embabel.plan.Planner
import com.embabel.plan.WorldState
import java.time.Duration
import java.time.Instant

interface AgentProcess : Blackboard, Timestamped, Timed,
    OperationStatus<AgentProcessStatusCode>, LlmInvocationHistory {

    /** Unique identifier for this process */
    val id: String

    /** The agent this process is running */
    val agent: Agent

    /** Current status of the process */
    override val status: AgentProcessStatusCode

    /** The blackboard for this process */
    val blackboard: Blackboard

    /** Options the process was started with */
    val processOptions: ProcessOptions

    /** The planner used by this process */
    val planner: Planner<*, *, *>

    /** History of actions taken by this process */
    val history: List<ActionInvocation>

    /** Goal of this process (may be null for utility processes) */
    val goal: com.embabel.plan.Goal?

    /** ID of the parent AgentProcess, if any */
    val parentId: String?

    /** Last world state used to plan the next action */
    val lastWorldState: WorldState?

    /** When the process started */
    override val timestamp: Instant

    /** How long the process has been running */
    override val runningTime: Duration

    /** Is the process finished (completed, failed, killed, or terminated)? */
    val finished: Boolean

    /** Failure information if the process failed */
    val failureInfo: Any?

    /** Process context */
    val processContext: ProcessContext

    /** Run the process as far as possible */
    fun run(): AgentProcess

    /** Perform the next step only (single action) */
    fun tick(): AgentProcess

    /** Kill this process and return kill event if successful */
    fun kill(): ProcessKilledEvent?

    /** Pause the process (implementation-specific) */
    fun pause()

    /** Resume a paused process (implementation-specific) */
    fun resume()

    /** Return a serializable status report */
    fun statusReport(): AgentProcessStatusReport

    /** Get the result of a specific type (process must be completed) */
    fun <O> resultOfType(outputClass: Class<O>): O

    /** Get a variable value from the blackboard */
    fun getValue(variable: String, type: String): Any?

    /** Record an LLM invocation for tracking */
    fun recordLlmInvocation(llmInvocation: LlmInvocation)

    companion object {
        /** Get the current agent process for this thread (only during tool calls) */
        @JvmStatic
        fun get(): AgentProcess?
    }
}

/** Convenience extension function for reified type result extraction */
inline fun <reified O> AgentProcess.resultOfType(): O

Basic Process Execution:

@Action(description = "Execute validation process")
fun validateDocument(
    document: Document,
    platform: AgentPlatform
): ValidationReport {
    // Create process
    val process = platform.createAgentProcess(
        agent = validationAgent,
        processOptions = ProcessOptions(),
        bindings = mapOf("document" to document)
    )

    // Run synchronously
    val completed = process.run()

    // Check status and extract result
    return when (completed.status) {
        AgentProcessStatusCode.COMPLETED ->
            completed.resultOfType<ValidationReport>()
        AgentProcessStatusCode.FAILED ->
            throw ProcessException("Validation failed: ${completed.failureInfo}")
        else ->
            throw ProcessException("Unexpected status: ${completed.status}")
    }
}

Step-by-Step Execution:

@Action(description = "Monitor process execution step-by-step")
fun monitoredExecution(
    task: Task,
    platform: AgentPlatform
): ExecutionTrace {
    val process = platform.createAgentProcess(
        agent = taskAgent,
        processOptions = ProcessOptions().withVerbosity(Verbosity().debug()),
        bindings = mapOf("task" to task)
    )

    val trace = mutableListOf<String>()

    // Execute step by step
    while (!process.finished) {
        process.tick()

        // Log each action
        if (process.history.isNotEmpty()) {
            val lastAction = process.history.last()
            trace.add("Action: ${lastAction.actionName} (${lastAction.runningTime.toMillis()}ms)")
        }

        // Check status
        trace.add("Status: ${process.status}")
    }

    return ExecutionTrace(
        processId = process.id,
        steps = trace,
        finalStatus = process.status
    )
}

Thread-Local Access:

@Tool(description = "Get current process information")
fun getCurrentProcessInfo(): ProcessInfo {
    val process = AgentProcess.get()
        ?: throw IllegalStateException("No agent process in current thread")

    return ProcessInfo(
        id = process.id,
        agentName = process.agent.name,
        status = process.status.name,
        actionsExecuted = process.history.size,
        runningTime = process.runningTime
    )
}

AgentProcessStatusCode Enum

Status codes for agent process lifecycle.

enum class AgentProcessStatusCode {
    /** The process has not started yet */
    NOT_STARTED,

    /** The process is running without any known problems */
    RUNNING,

    /** The process has completed successfully */
    COMPLETED,

    /** Game over. The process has failed */
    FAILED,

    /** The process has been killed by an early termination policy */
    TERMINATED,

    /** The process has been killed by the user or platform, from outside */
    KILLED,

    /** The process cannot formulate a plan to progress (may be temporary) */
    STUCK,

    /** The process is waiting for user input or another external event */
    WAITING,

    /** The process has paused due to scheduling policy */
    PAUSED
}

Status Checking:

@Action(description = "Check process health")
fun checkProcessHealth(processId: String, platform: AgentPlatform): HealthStatus {
    val process = platform.getAgentProcess(processId)
        ?: return HealthStatus.NOT_FOUND

    return when (process.status) {
        AgentProcessStatusCode.RUNNING -> HealthStatus.HEALTHY
        AgentProcessStatusCode.WAITING, AgentProcessStatusCode.PAUSED -> HealthStatus.IDLE
        AgentProcessStatusCode.STUCK -> HealthStatus.DEGRADED
        AgentProcessStatusCode.COMPLETED -> HealthStatus.COMPLETED
        else -> HealthStatus.FAILED
    }
}

ProcessOptions Data Class

Configuration for agent process execution.

import com.embabel.agent.core.ProcessOptions
import com.embabel.agent.core.Verbosity
import com.embabel.agent.core.Budget
import com.embabel.agent.core.ProcessControl
import com.embabel.agent.core.Identities
import com.embabel.agent.core.ContextId
import com.embabel.agent.core.Blackboard
import com.embabel.agent.api.channel.OutputChannel
import com.embabel.agent.api.event.AgenticEventListener
import com.embabel.agent.api.common.PlannerType

data class ProcessOptions(
    /** Context ID for connecting to external resources and persistence */
    val contextId: ContextId? = null,

    /** User identities associated with this process */
    val identities: Identities = Identities(),

    /** Existing blackboard to use (will be modified during execution) */
    val blackboard: Blackboard? = null,

    /** Verbosity settings for logging */
    val verbosity: Verbosity = Verbosity(),

    /** Budget constraints for the process */
    val budget: Budget = Budget(),

    /** Process control settings (defaults based on budget) */
    val processControl: ProcessControl = ProcessControl(
        toolDelay = Delay.NONE,
        operationDelay = Delay.NONE,
        earlyTerminationPolicy = budget.earlyTerminationPolicy()
    ),

    /** Whether to prune the agent to only relevant actions */
    val prune: Boolean = false,

    /** Additional event listeners for this process */
    val listeners: List<AgenticEventListener> = emptyList(),

    /** Custom output channel for process output */
    val outputChannel: OutputChannel = DevNullOutputChannel,

    /** Type of planner to use (default: GOAP) */
    val plannerType: PlannerType = PlannerType.GOAP
) {
    /** Get context ID as string (Java interop) */
    fun getContextIdString(): String?

    /** Wither methods for fluent configuration */
    fun withContextId(contextId: ContextId?): ProcessOptions
    fun withContextId(contextId: String?): ProcessOptions
    fun withIdentities(identities: Identities): ProcessOptions
    fun withBlackboard(blackboard: Blackboard?): ProcessOptions
    fun withVerbosity(verbosity: Verbosity): ProcessOptions
    fun withBudget(budget: Budget): ProcessOptions
    fun withProcessControl(processControl: ProcessControl): ProcessOptions
    fun withAdditionalEarlyTerminationPolicy(policy: EarlyTerminationPolicy): ProcessOptions
    fun withPrune(prune: Boolean): ProcessOptions
    fun withListeners(listeners: List<AgenticEventListener>): ProcessOptions
    fun withListener(listener: AgenticEventListener): ProcessOptions
    fun withOutputChannel(outputChannel: OutputChannel): ProcessOptions
    fun withPlannerType(plannerType: PlannerType): ProcessOptions

    companion object {
        @JvmField
        val DEFAULT = ProcessOptions()
    }
}

Configuration Examples:

// Minimal configuration
val basicOptions = ProcessOptions()

// Custom verbosity
val verboseOptions = ProcessOptions()
    .withVerbosity(
        Verbosity()
            .showPrompts()
            .showLlmResponses()
            .showPlanning()
    )

// Budget constraints
val budgetedOptions = ProcessOptions()
    .withBudget(
        Budget()
            .withCost(0.5)
            .withActions(20)
            .withTokens(50000)
    )

// Custom termination policy
val customOptions = ProcessOptions()
    .withAdditionalEarlyTerminationPolicy(
        EarlyTerminationPolicy.ON_STUCK
    )

// With event listener
val monitoredOptions = ProcessOptions()
    .withListener(object : AgenticEventListener {
        override fun onEvent(event: AgenticEvent) {
            println("Event: ${event.javaClass.simpleName}")
        }
    })

// Complex configuration
val fullOptions = ProcessOptions()
    .withContextId("session-123")
    .withIdentities(Identities(forUser = currentUser))
    .withBudget(Budget(cost = 1.0, actions = 50))
    .withVerbosity(Verbosity().showPlanning())
    .withPlannerType(PlannerType.GOAP)
    .withPrune(true)

Verbosity Configuration

Controls logging and debugging output detail.

data class Verbosity(
    val showPrompts: Boolean = false,
    val showLlmResponses: Boolean = false,
    val debug: Boolean = false,
    val showPlanning: Boolean = false
) : LlmVerbosity {
    /** Derived property: show long plans if any verbosity is enabled */
    val showLongPlans: Boolean

    /** Wither methods for fluent configuration */
    fun withShowPrompts(showPrompts: Boolean): Verbosity
    fun showPrompts(): Verbosity
    fun withShowLlmResponses(showLlmResponses: Boolean): Verbosity
    fun showLlmResponses(): Verbosity
    fun withDebug(debug: Boolean): Verbosity
    fun debug(): Verbosity
    fun withShowPlanning(showPlanning: Boolean): Verbosity
    fun showPlanning(): Verbosity

    companion object {
        @JvmField
        val DEFAULT = Verbosity()
    }
}

Verbosity Examples:

// Show all details
val maxVerbosity = Verbosity()
    .showPrompts()
    .showLlmResponses()
    .showPlanning()
    .debug()

// Just planning
val planningOnly = Verbosity().showPlanning()

// Debug mode
val debugMode = Verbosity().debug()

// Production mode (default)
val production = Verbosity.DEFAULT

Budget Configuration

Define cost and resource limits for agent processes.

data class Budget(
    /** Maximum cost in USD */
    val cost: Double = DEFAULT_COST_LIMIT,

    /** Maximum number of actions before termination */
    val actions: Int = DEFAULT_ACTION_LIMIT,

    /** Maximum number of tokens before termination */
    val tokens: Int = DEFAULT_TOKEN_LIMIT
) {
    /** Convert budget to early termination policy */
    fun earlyTerminationPolicy(): EarlyTerminationPolicy

    /** Wither methods for fluent configuration */
    fun withCost(cost: Double): Budget
    fun withActions(actions: Int): Budget
    fun withTokens(tokens: Int): Budget

    companion object {
        const val DEFAULT_COST_LIMIT = 2.0
        const val DEFAULT_ACTION_LIMIT = 50
        const val DEFAULT_TOKEN_LIMIT = 1000000

        @JvmField
        val DEFAULT = Budget()
    }
}

Budget Examples:

// Conservative budget
val conservative = Budget()
    .withCost(0.25)
    .withActions(10)

// Standard budget
val standard = Budget.DEFAULT

// Generous budget
val generous = Budget()
    .withCost(5.0)
    .withActions(100)
    .withTokens(2000000)

// Cost-focused
val costFocused = Budget()
    .withCost(1.0)
    .withActions(Int.MAX_VALUE)

// Action-limited
val actionLimited = Budget()
    .withCost(Double.MAX_VALUE)
    .withActions(25)

Identities Configuration

User identity information for process execution.

data class Identities(
    /** User for whom the process is running */
    val forUser: User? = null,

    /** User under which the process is running */
    val runAs: User? = null
) {
    /** Wither methods for fluent configuration */
    fun withForUser(forUser: User?): Identities
    fun withRunAs(runAs: User?): Identities

    companion object {
        @JvmField
        val DEFAULT = Identities()
    }
}

Identity Examples:

// Run on behalf of user
val userIdentities = Identities()
    .withForUser(currentUser)

// Run as service account
val serviceIdentities = Identities()
    .withRunAs(serviceAccount)

// Both identities
val fullIdentities = Identities(
    forUser = requestingUser,
    runAs = executionUser
)

Delay Enum

Control timing between operations.

enum class Delay {
    /** No delay */
    NONE,

    /** Medium delay between operations */
    MEDIUM,

    /** Long delay between operations */
    LONG
}

ProcessControl Configuration

Fine-grained control over process execution behavior.

data class ProcessControl(
    /** Delay between tool invocations */
    val toolDelay: Delay = Delay.NONE,

    /** Delay between operations */
    val operationDelay: Delay = Delay.NONE,

    /** Policy for early termination */
    val earlyTerminationPolicy: EarlyTerminationPolicy =
        EarlyTerminationPolicy.maxActions(100)
) {
    /** Wither methods for fluent configuration */
    fun withToolDelay(toolDelay: Delay): ProcessControl
    fun withOperationDelay(operationDelay: Delay): ProcessControl
    fun withEarlyTerminationPolicy(policy: EarlyTerminationPolicy): ProcessControl
    fun withAdditionalEarlyTerminationPolicy(policy: EarlyTerminationPolicy): ProcessControl
}

ProcessControl Examples:

// Rate-limited execution
val rateLimited = ProcessControl()
    .withToolDelay(Delay.MEDIUM)
    .withOperationDelay(Delay.MEDIUM)

// Custom termination
val customTermination = ProcessControl()
    .withEarlyTerminationPolicy(
        EarlyTerminationPolicy.firstOf(
            EarlyTerminationPolicy.maxActions(30),
            EarlyTerminationPolicy.hardBudgetLimit(1.0),
            EarlyTerminationPolicy.ON_STUCK
        )
    )

// Add termination policy
val enhanced = ProcessControl()
    .withAdditionalEarlyTerminationPolicy(
        EarlyTerminationPolicy.maxTokens(100000)
    )

EarlyTerminationPolicy Interface

Define custom termination conditions for agent processes.

import com.embabel.agent.core.EarlyTerminationPolicy
import com.embabel.agent.core.EarlyTermination

interface EarlyTerminationPolicy {
    /** Name of this policy (defaults to class name) */
    val name: String

    /** Check if the process should be terminated early */
    fun shouldTerminate(agentProcess: AgentProcess): EarlyTermination?

    companion object {
        /** Terminate when process becomes stuck */
        @JvmStatic
        val ON_STUCK: EarlyTerminationPolicy

        /** Terminate after maximum number of actions */
        @JvmStatic
        fun maxActions(maxActions: Int): EarlyTerminationPolicy

        /** Terminate after maximum tokens consumed */
        @JvmStatic
        fun maxTokens(maxTokens: Int): EarlyTerminationPolicy

        /** Combine multiple policies (first match wins) */
        @JvmStatic
        fun firstOf(vararg policies: EarlyTerminationPolicy): EarlyTerminationPolicy

        /** Hard budget limit (last resort to prevent runaway costs) */
        @JvmStatic
        fun hardBudgetLimit(budget: Double): EarlyTerminationPolicy
    }
}

data class EarlyTermination(
    val agentProcess: AgentProcess,
    val error: Boolean,
    val reason: String,
    val policy: EarlyTerminationPolicy
)

Custom Termination Policy:

class TimeBasedTerminationPolicy(
    private val maxDuration: Duration
) : EarlyTerminationPolicy {
    override val name = "TimeLimit"

    override fun shouldTerminate(agentProcess: AgentProcess): EarlyTermination? {
        return if (agentProcess.runningTime > maxDuration) {
            EarlyTermination(
                agentProcess = agentProcess,
                error = true,
                reason = "Process exceeded time limit of ${maxDuration.toMinutes()} minutes",
                policy = this
            )
        } else null
    }
}

// Use custom policy
val options = ProcessOptions()
    .withProcessControl(
        ProcessControl()
            .withEarlyTerminationPolicy(
                TimeBasedTerminationPolicy(Duration.ofMinutes(5))
            )
    )

Supporting Types

/** History element for action invocations */
data class ActionInvocation(
    val actionName: String,
    val timestamp: Instant,
    val runningTime: Duration
)

/** Serializable status report for agent processes */
data class AgentProcessStatusReport(
    val id: String,
    val status: AgentProcessStatusCode,
    val timestamp: Instant,
    val runningTime: Duration
)

/** Context ID for process persistence and resource connection */
@JvmInline
value class ContextId(val value: String)

interface Timestamped {
    val timestamp: Instant
}

interface Timed {
    val runningTime: Duration
}

interface OperationStatus<S> : Timed where S : Enum<S> {
    val status: S
}

Complete Example

import com.embabel.agent.core.*
import com.embabel.agent.api.annotation.Action
import java.time.Duration

@Action(description = "Execute complex data pipeline with monitoring")
fun executeDataPipeline(
    pipeline: DataPipeline,
    platform: AgentPlatform,
    context: ActionContext
): PipelineResult {
    // Configure process with comprehensive options
    val options = ProcessOptions()
        .withContextId("pipeline-${pipeline.id}")
        .withIdentities(Identities(forUser = context.user()))
        .withBudget(
            Budget()
                .withCost(2.0)
                .withActions(75)
                .withTokens(500000)
        )
        .withVerbosity(
            Verbosity()
                .showPlanning()
                .withDebug(pipeline.debugMode)
        )
        .withProcessControl(
            ProcessControl()
                .withToolDelay(Delay.NONE)
                .withAdditionalEarlyTerminationPolicy(
                    EarlyTerminationPolicy.ON_STUCK
                )
        )
        .withListener(object : AgenticEventListener {
            override fun onEvent(event: AgenticEvent) {
                when (event) {
                    is ActionCompletedEvent ->
                        context.log("Action completed: ${event.actionName}")
                    is EarlyTermination ->
                        context.log("Early termination: ${event.reason}")
                }
            }
        })

    // Create and run process
    val process = platform.createAgentProcess(
        agent = pipelineAgent,
        processOptions = options,
        bindings = mapOf(
            "pipeline" to pipeline,
            "config" to pipeline.config
        )
    )

    // Execute with monitoring
    val result = when {
        pipeline.async -> {
            // Run asynchronously
            val future = platform.start(process)
            PipelineResult.Async(processId = process.id, future = future)
        }
        pipeline.stepByStep -> {
            // Execute step-by-step with monitoring
            val steps = mutableListOf<StepResult>()
            while (!process.finished) {
                process.tick()
                if (process.history.isNotEmpty()) {
                    steps.add(StepResult(
                        action = process.history.last().actionName,
                        status = process.status
                    ))
                }
            }
            PipelineResult.Stepped(steps = steps, process = process)
        }
        else -> {
            // Synchronous execution
            val completed = process.run()
            PipelineResult.Completed(process = completed)
        }
    }

    // Handle completion
    return when (result) {
        is PipelineResult.Completed -> {
            when (result.process.status) {
                AgentProcessStatusCode.COMPLETED ->
                    result.process.resultOfType<PipelineResult>()
                AgentProcessStatusCode.FAILED ->
                    throw PipelineException("Pipeline failed", result.process.failureInfo)
                AgentProcessStatusCode.TERMINATED ->
                    throw BudgetExceededException("Pipeline terminated: budget exceeded")
                else ->
                    throw PipelineException("Unexpected status: ${result.process.status}")
            }
        }
        else -> result
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-embabel-agent--embabel-agent-api@0.3.0

docs

actions-goals.md

agent-definition.md

builtin-tools.md

chat.md

conditions.md

events.md

human-in-the-loop.md

index.md

invocation.md

io-binding.md

llm-interaction.md

models.md

planning-workflows.md

platform-management.md

runtime-context.md

state-management.md

streaming.md

subagents.md

tools.md

type-system.md

typed-operations.md

validation.md

tile.json