# Authoring Skills Source: https://docs.meshagent.com/agent_skills/authoring ## Skill anatomy Each skill lives in its own directory. The main entrypoint is `SKILL.md`. MeshAgent also accepts lowercase `skill.md`, but `SKILL.md` is the preferred name. ```text theme={null} my-skill/ ├── SKILL.md ├── references/ │ └── examples.md ├── scripts/ │ └── helper.sh └── assets/ └── template.md ``` * `SKILL.md`: required entrypoint. * `references/`: optional long-form background material. * `scripts/`: optional helper scripts the agent may run when the environment allows it. * `assets/`: optional templates, sample files, or other bundled content. Keep the directory name aligned with the skill's `name` field. That keeps validation and discovery predictable. Keep the root of the skill small. Put bulky supporting material in subdirectories and reference it from `SKILL.md` only when needed. Skills can absolutely include files beyond Markdown, including scripts, templates, structured data, images, and other resources the workflow depends on. ## Required `SKILL.md` structure At minimum, define: * `name`: stable skill identifier * `description`: what the skill does and when the agent should use it * Markdown body: the workflow and output expectations Example: ```md theme={null} --- name: creating-meshagent-examples description: Create beginner-friendly MeshAgent SDK tutorials and runnable examples. Use this when the user asks for a tutorial, walkthrough, getting-started guide, example project, sample code, or docs page for a MeshAgent feature. --- # Creating MeshAgent Examples Use this skill when the user wants a tutorial or runnable example for a MeshAgent feature. ## Goal Produce a beginner-friendly guide that explains one concept, shows setup, and includes a small working example. ## Process 1. Read the SDK source or docs that define the behavior. 2. Design the smallest useful example. 3. Validate the steps when possible. 4. Write the guide in a clear, CLI-first format. ## Output - Start with a short explanation of what the feature is and when to use it. - Include setup steps, a minimal example, and how to run it. - Save the draft to a markdown file. - Include the final file path in the response. ``` This example is still intentionally small, but it is closer to best practice because the description is more trigger-oriented and the output expectations are more explicit. ## Writing good descriptions The `description` field is the main trigger surface, so make it specific. Good descriptions: * say what the skill does * say when the agent should use it * mention recognizable user intents or task categories Weak descriptions are vague: * "Helps with docs" * "A useful writing skill" Better descriptions are explicit: * "Review content against brand voice and messaging guidelines. Use when the user asks for brand review, tone alignment, messaging consistency, or editorial feedback." ## Authoring guidelines When writing a skill: * Keep workflows explicit and step-by-step. * Tell the agent what to inspect before acting. * Name the tools or files it is expected to use when that matters. * Define the desired output shape. * Prefer short sections over dense paragraphs. Avoid: * dumping large reference manuals directly into `SKILL.md` * hiding critical trigger logic only in the body * assuming tools exist without saying which ones are needed * mixing unrelated workflows into one skill ## Organizing support material Use subdirectories intentionally: * Put background reading in `references/`. * Put templates or reusable output skeletons in `assets/`. * Put executable helpers in `scripts/` only when running code is genuinely part of the workflow. Reference those files from `SKILL.md` with clear instructions such as: * "Read `references/terminology.md` when the user asks for product naming help." * "Use `assets/report_template.md` for the final report format." This keeps the top-level skill understandable while still allowing deep, domain-specific guidance. ## Linking to external resources It is also fine for a skill to point to external documentation, specifications, or source material when that is the right source of truth. Use external links carefully: * Link to stable sources when possible. * Say when the agent should consult the link. * Do not make the whole workflow depend on a vague "go read this website" instruction. For example: * "If the task involves OpenAPI validation, consult the official OpenAPI spec before generating the final schema." * "If the user asks about a provider-specific API, check the provider's latest docs before calling the tool." ## Compatibility guidance If you want the skill to stay portable across agent runtimes: * keep the core behavior in standard `SKILL.md` frontmatter and Markdown * avoid product-specific assumptions unless they are essential * treat runtime-specific tools as optional environment details In other words: write the common skill first, then layer MeshAgent-specific tooling guidance where it helps. ## Where to go next * [Skills Overview](./overview): understand how skills fit with rules, prompts, and tools. * [Bundle Private Skills with a Custom Service](./packaging_and_deploying): ship skills inside a custom MeshAgent service. # Skills Overview Source: https://docs.meshagent.com/agent_skills/overview Skills are reusable task instructions that agents can consult when they are relevant. A skill tells the agent how to approach a class of work. Tools give the agent the capabilities to actually do that work. MeshAgent supports the open [Agent Skills](https://agentskills.io/home) format. You can load one skill, a folder of skills, or a repo of skills into an agent with `--skill-dir` in the CLI or `skill_dirs` in the SDKs that expose it. ## What a skill is A skill is a directory that contains instructions and optional supporting files: ```text theme={null} my-skill/ ├── SKILL.md ├── references/ │ └── examples.md └── scripts/ └── helper.sh ``` The main entrypoint is `SKILL.md`. MeshAgent also accepts lowercase `skill.md`. The file starts with YAML frontmatter such as: * `name` * `description` Then the Markdown body explains the workflow, what to inspect, which tools to use, and what output to produce. ## Skills vs rules and tools These pieces work together, but they do different jobs: * **Rules** shape the agent's ongoing behavior. * **User prompts** describe the current request. * **Skills** give the agent reusable workflows for specific kinds of work. * **Tools** give the agent callable capabilities such as storage, shell access, web search, or room APIs. The practical distinction is simple: * Tools do work. * Skills explain how to do work. ## Load skills into an agent You can point `--skill-dir` at either: * one skill directory * a parent directory that contains multiple skill directories This example creates one skill under `./skills` and then loads the parent folder: ```bash bash theme={null} mkdir -p ./skills/release-summary cat > ./skills/release-summary/SKILL.md <<'EOF' --- name: release-summary description: Summarize release notes, changelogs, or shipped features into a concise update for humans. Use this when the user asks for a release summary, changelog rewrite, product update, or announcement draft. --- # Release Summary ## Goal Turn raw release notes or a changelog into a short, clear summary. ## Process 1. Read the source material carefully. 2. Group related changes together. 3. Highlight user-facing impact, not just implementation details. 4. Keep the output concise and easy to skim. EOF meshagent setup meshagent process join \ --room quickstart \ --agent-name assistant \ --channel chat \ --storage \ --skill-dir ./skills \ --rule "You are a helpful assistant." ``` After the agent starts, ask it for a release summary. The model can inspect the available skill and decide to use it for that task. ## Auto-detecting skills from a folder When `--skill-dir` points at a parent folder, MeshAgent auto-detects the immediate child directories that contain `SKILL.md` or `skill.md`. That means this works: ```text theme={null} ./skills/ ├── release-summary/ │ └── SKILL.md └── brand-review/ └── SKILL.md ``` And this CLI command loads both: ```bash bash theme={null} meshagent process join \ --room quickstart \ --agent-name assistant \ --channel chat \ --skill-dir ./skills ``` Use repeated `--skill-dir` flags when you want to combine multiple roots. ## Pull skills from GitHub MeshAgent does not need a special GitHub-specific skill loader. It reads skills from local directories. That means there are two practical patterns: * tell an agent with shell access to clone or pull a public skills repo into room storage * configure a custom service with `--skill-dir` pointing at the room-backed skills folder This is especially relevant for the built-in room assistant. The shipped assistant template already includes shell access, storage access, and mounts room files at `/data`, so you can tell it to create skills in the room or pull a public skills repo into the room for you. If the repo is private, the agent needs a token or other credentials that let it authenticate with GitHub. One important distinction: the built-in assistant template does not currently start with `--skill-dir`. That means cloned skill files are not automatically loaded through MeshAgent's formal skills runtime just because they exist in the room. The assistant can still fetch them, inspect them, and use them as files. To have a service auto-load them as skills, the agent or service needs to be configured with `--skill-dir` pointed at that folder. Because MeshAgent reads configured skill directories from disk when it builds the agent's rules, skills added to a configured room-backed path can be picked up on later turns. ## When to use skills Use skills when you want to: * package a repeatable workflow once and reuse it across many turns or rooms * keep long task playbooks out of inline `--rule` strings * teach an agent how to choose tools, inspect files, and structure its output * ship domain-specific guidance with a deployed service ## When not to use skills Do not use skills as a replacement for: * **tools**, when the agent needs a new capability * **rules**, when the instruction should apply on every turn * **schemas**, when the system needs strict structured input or output If the task needs new abilities, add tools first. If the task needs better reusable judgment about how to use those abilities, add a skill. ## Where to go next * [Authoring Skills](./authoring): write `SKILL.md` files and organize supporting resources. * [Bundle Private Skills with a Custom Service](./packaging_and_deploying): ship a fixed or private set of skills with a service. * [How Tools and Toolkits Work](../agents/tools/tools_and_toolkits): understand the capabilities that skills often rely on. # Bundle Private Skills with a Custom Service Source: https://docs.meshagent.com/agent_skills/packaging_and_deploying For most skills workflows, you do not need this page. The default path is to keep skills in the room and let agents create, edit, or pull them there. If you are using the built-in assistant, it already has shell and storage access, so it can fetch public skill repos or create skills in room storage for you. This page covers the more controlled path: bundle a fixed or private set of skills into a custom service and start that service with `--skill-dir`. For the full service YAML reference, see [Service YAML](../services/deployment/deploy_services#service-configuration-field-reference). ## When this pattern makes sense Use this pattern when: * the skills are private and you do not want to pull them from a public repo at runtime * you want a versioned, reproducible skill set baked into a service * you want a custom agent or service to auto-load skills through `--skill-dir` * you want a room to start with a seeded set of skills before anyone edits them If you just want an agent to fetch or write skills into the room and use them as files, keep them in room storage instead. ## End-to-end example: bundle a skills repo for a process agent This example assumes you already have a repo or folder of Agent Skills you want to ship. The `anthropic_skills` sample packages those skills into an image, mounts them at `/skills`, copies them into `/data/skills`, and starts a `meshagent process` agent with `--skill-dir /data/skills`. ### Step 1: Package your skills into an image Start with a skills repo that contains one or more skill directories, each with its own `SKILL.md`. In the existing sample, the skills come from the open [Anthropic skills repo](https://github.com/anthropics/skills). At runtime, the MeshAgent service expects those skills to be present in an image that can be mounted read-only into the container. Clone the skills repo: ```bash bash theme={null} git clone https://github.com/anthropics/skills.git cd skills ``` Create a scratch `Dockerfile` in the repo root: ```dockerfile theme={null} FROM scratch COPY skills/ /skills/ ``` Build and push the image: ```bash bash theme={null} docker buildx build . \ -t "//:" \ --platform linux/amd64 \ --push ``` **What the build arguments mean** * ``: Container registry host such as `docker.io`, `ghcr.io`, or `us-west1-docker.pkg.dev`. * ``: Your registry account or organization name. * ``: The repository name for the image. * ``: A version label such as `latest` or `2026-03-03`. * `docker buildx build .`: Builds from the current directory using Buildx. * `-t`: Tags the image with the full name. * `--platform linux/amd64`: Builds a Linux AMD64 image. * `--push`: Pushes the built image to the registry. **Docker Hub note** For Docker Hub you can omit the registry and use: ```bash bash theme={null} docker buildx build . \ -t "/:" \ --platform linux/amd64 \ --push ``` If you do not want to build your own image, you can keep using the prebuilt image already referenced by the sample: ```text theme={null} docker.io/tulamasterman/anthropic-skills:latest ``` ### Step 2: Create the MeshAgent service spec Use a `meshagent.yaml` file that mounts the skills image and starts a process agent that loads the copied skills. ```yaml Yaml theme={null} version: v1 kind: ServiceTemplate variables: [] metadata: name: claudeskills description: An agent that can assist you with questions, powered by Anthropic's Claude model annotations: meshagent.service.id: meshagent.claudeskills agents: - name: claudeskills annotations: meshagent.agent.type: ChatBot container: image: meshagent/cli:default command: /bin/bash /var/start.sh storage: room: - path: /data read_only: false images: - image: docker.io/tulamasterman/anthropic-skills:latest path: /skills read_only: true files: - path: /var/start.sh text: | #!/bin/bash set -e mkdir -p /data/skills skills_src="/skills" if [ -d /skills/skills ]; then skills_src="/skills/skills" fi if [ -d "$skills_src" ]; then cp -R -n "$skills_src"/* /data/skills/ 2>/dev/null || true fi exec /usr/bin/meshagent process join \ --model=claude-sonnet-4-6 \ --channel=chat \ --shell \ --shell-image=meshagent/shell-terminal:default \ --shell-tool-room-path=/:/data \ --script-tool \ --web-search \ --use-memory agents/claudeskills/memories \ --storage \ --storage-tool-room-path=/:/data \ -rr=agents/claudeskills/rules.md \ --skill-dir /data/skills \ --rule='You have customizable rules stored in agents/claudeskills/rules.md, you can use the read_file tool to read your rules. You can use the write_file tool to update the contents of the rules file or other text files. Use the read_file tool to read PDFs, examine images, or read files with a text/* mime type from attachments or files.' \ --rule='You are a MeshAgent agent. MeshAgent is an agent operating system. You can find out more at www.meshagent.com and docs.meshagent.com' \ --rule='The root of the filesystem that the user sees (the "Room" files) has been mounted in the /data folder. If the user is currently viewing a file, the file path is relative to /data. To write a file the user can see, you must write it inside /data and tell them the path, relative to the /data folder, not including the data folder' environment: - name: MESHAGENT_TOKEN token: identity: claudeskills role: agent ``` If you built your own image in Step 1, update the image mount in the service spec: * `container.storage.images.image: //:` ### Step 3: Understand what this service is doing The sample does four important things: * It mounts the room filesystem at `/data`. * It mounts the skills image at `/skills`. * It copies the skills into `/data/skills` on startup. * It starts `meshagent process join --skill-dir /data/skills` with the tools and rules the skills need in order to be useful. The auto-detection behavior matters here. `--skill-dir /data/skills` can point at the parent folder, and MeshAgent will load the immediate child skill folders inside it. You do not need to expand every skill into its own CLI flag. ### Step 4: Validate the service spec ```bash bash theme={null} meshagent service validate-template --file meshagent.yaml ``` This checks that the `ServiceTemplate` is structurally valid before deployment. ### Step 5: Deploy it to a room ```bash bash theme={null} meshagent service create-template --file meshagent.yaml --room quickstart ``` Because this sample is a `ServiceTemplate` with no required input variables, you can deploy it directly to a room. If you want the service to be available only in one room, keep the `--room` flag. If you later convert the sample to a plain `Service`, you can follow the normal room vs project deployment rules from the packaging docs. ### Step 6: Verify that the skills are available After deployment: 1. Open the room in MeshAgent Studio. 2. Start chatting with the deployed agent. 3. Give it a task that should trigger one of the packaged skills. 4. Check the agent logs if you need to confirm startup or skill discovery behavior. If the skills depend on shell access, storage, web search, or other tools, make sure those are enabled in the service command. Packaging the skill files alone is not enough. ## Why this pattern works well This approach works well when: * you already have a private or curated skill repo you want to reuse * you want multiple skills to ship together * you want the service to discover whatever skills are present in the mounted or copied skills folder * you want stable, versioned skill content in deployment It is especially useful when the skills repo is maintained separately from the MeshAgent service spec and should not be edited casually in each room. ## Room-managed skills vs image-baked skills There are two common operating modes: * **Room-managed skills**: easier to create, inspect, pull from GitHub, and edit inside the room. * **Image-baked skills**: versioned, reproducible, and better when you want a fixed private baseline. The Anthropic skills example uses both: * The mounted image acts as the default packaged source of truth. * On startup, the skills are copied into `/data/skills`, which lives in room storage. * Because the sample uses `cp -R -n`, files that already exist in room storage are not overwritten by later startups. In practice, that means you can seed a room with the skills from the image, then edit, pull, or customize the copied skill files in the room, and the agent will load the room-backed copies from `/data/skills`. This gives you a useful hybrid model: * ship a stable base set of skills in the image * let a specific room inspect or customize those skills after deployment * keep the agent pointed at the room-backed paths it actually uses at runtime ## Adapting this pattern to your own repo If your skills repo differs from the sample: * change the mounted image in `storage.images` * adjust the source path if your repo uses a different root layout * keep the copied files under a parent folder such as `/data/skills` * enable whatever tools the skills actually depend on If you only have one skill and a fixed layout, you can point `--skill-dir` directly at that one skill directory instead. ## See also * [Skills Overview](./overview): understand how skills differ from tools and rules. * [Deploy a built in Agent](../services/deployment/deploy_builtin_agent): deploy a process-backed agent from CLI flags. * [Service YAML](../services/deployment/deploy_services#service-configuration-field-reference): full service YAML field reference. # Anthropic Messages Adapter Source: https://docs.meshagent.com/agents/adapters/anthropic_messages_adapter The Anthropic Messages adapter is an `LLMAdapter` implementation for Anthropic's Messages API. It enables MeshAgent agents to use Claude models, handle tool calls, and stream responses while preserving MeshAgent toolkit behavior. ## Key features * **Model defaults:** Reads the model name from the constructor (`model=`) or the `ANTHROPIC_MODEL` environment variable. Override per call by passing `model` to `create_response()`. * **Max token defaults:** Reads `max_tokens` from the constructor or `ANTHROPIC_MAX_TOKENS`. * **Session context defaults:** Creates `AgentSessionContext(system_role=None)` so system/developer prompts come from the caller. * **Tool calling:** Converts the supplied toolkits into Anthropic `tools` definitions and executes `tool_use` requests. * **Tool result formatting:** Uses `AnthropicMessagesToolResponseAdapter` to return `tool_result` blocks back to the model. * **Streaming support:** Uses Anthropic's streaming API and emits events to `event_handler`. * **Structured output (best-effort):** When `output_schema` is provided, the adapter prompts for JSON and validates it (with retries). * **MCP connector support:** MCP toolkits inject `mcp_servers`, MCP toolset entries in `tools`, and required `betas` flags into the request. ## Constructor parameters ```python Python theme={null} AnthropicMessagesAdapter( model: str = "claude-3-5-sonnet-latest", max_tokens: int = 1024, client: Optional[Any] = None, message_options: Optional[dict] = None, provider: str = "anthropic", log_requests: bool = False, context_management: Literal["auto", "none"] = "auto", compaction_threshold: int = 150000, compaction_pause_after: bool = False, compaction_instructions: Optional[str] = None, base_url: Optional[str] = None, ) ``` * `model` - default model name; can be overridden per call. * `max_tokens` - cap on output tokens per response. * `client` - reuse an existing Anthropic client; otherwise the adapter builds one via `meshagent.anthropic.proxy.get_client`. * `base_url` - override the provider base URL used when the adapter creates its own client. Defaults to `ANTHROPIC_BASE_URL` when omitted. * `message_options` - extra parameters passed to `messages.create` (for example `temperature`, `top_p`, `tools`, `betas`). * `provider` - label emitted in telemetry and logs. * `log_requests` - when true, uses a logging HTTP client for debugging. * `context_management` - `auto` enables Anthropic beta context management compaction edits only for Claude model versions newer than `4.5` (for example `claude-sonnet-4-6`); `none` disables automatic compaction configuration. * `compaction_threshold` - input token threshold for triggering `compact_20260112` when `context_management="auto"` (minimum `50000`). * `compaction_pause_after` - when true, compaction can return a `compaction` block and pause before continuing. * `compaction_instructions` - optional summarization instructions passed to compaction. When `context_management="auto"` is enabled, the adapter uses Anthropic's `compact-2026-01-12` beta on `client.beta.messages.*` and injects a `compact_20260112` edit into the request's `context_management`. ## MCP connector support Anthropic's official MCP connector can be enabled by adding an MCP toolkit to your toolkits list. The adapter applies MCP middleware to the request, which injects `mcp_servers` and an MCP toolset into the top-level `tools` array (and ensures the required `betas` flag is present). ## Handling a turn When `create_response()` is called it: 1. **Bundles tools** - Converts toolkits into Anthropic tool definitions. 2. **Builds the request** - Converts the chat context into Anthropic blocks and constructs the request payload. 3. **Calls the model** - Sends the request (streaming if `event_handler` is provided). 4. **Handles tool calls** - Executes requested tools and formats `tool_result` blocks. 5. **Loops** - Continues until the model returns a final response. 6. **Returns result** - Returns text or validated JSON if `output_schema` was supplied. ## Related Topics * [Adapters Overview](./index): Understand LLMAdapters and ToolResponseAdapters * [MeshAgent LLM Proxy](../routing/llm_proxy): How requests are routed and metered inside rooms * [OpenAI Responses Adapter](./openai_responses_adapter): A detailed reference implementation * [Anthropic Tool Response Adapter](./anthropic_tool_response_adapter): How tool outputs are rendered back into the chat transcript * [Process Agents Overview](../process/overview): Shows where adapters are used in the recommended runtime # Anthropic Tool Response Adapter Source: https://docs.meshagent.com/agents/adapters/anthropic_tool_response_adapter `AnthropicMessagesToolResponseAdapter` is the default `ToolResponseAdapter` used whenever you pair an agent with the Anthropic Messages adapter. It converts tool outputs into Anthropic `tool_result` blocks and provides a plain-text fallback that hosts can display or log. ## Behavior summary * **Plain-text rendering:** `to_plain_text` generates concise strings for common response types (`LinkChunk`, `JsonChunk`, `TextChunk`, `FileChunk`, `EmptyChunk`). * **Chat context updates:** `create_messages` returns a user message containing a `tool_result` block so the model can consume tool output on the next turn. * **Attachment handling:** Images and PDFs are converted into Anthropic `image` or `document` blocks; unsupported image types fall back to text. * **Developer logging:** Emits events via `room.developer.log_nowait` to aid debugging when tools are called. ## Response handling | Response type | Plain text example | Notes | | ----------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `TextChunk` | The returned text | Included as a text block in the `tool_result`. | | `JsonChunk` | JSON string dump | Included as a text block in the `tool_result`. | | `FileChunk` | `filename.ext` | Images (`image/jpeg`, `image/png`, `image/gif`, `image/webp`) are embedded as Anthropic image blocks; PDFs become `document` blocks; other files fall back to text. | | `LinkChunk` | `{ "name": ..., "url": ... }` | Serialized to JSON and included as a text block. | | `EmptyChunk` | `"ok"` | Signals successful execution without additional data. | | `RawOutputsChunk` | n/a | Passed through directly as Anthropic message blocks, bypassing plain-text conversion. | ## Tool use requirements Anthropic requires tool results to include a `tool_use_id`. The adapter raises an error if the `tool_use` block is missing an `id`. ## Extending or replacing You can subclass `AnthropicMessagesToolResponseAdapter` to customize plain-text formatting or message content, provided the emitted messages still follow Anthropic's `tool_result` schema. Alternatively, supply your own adapter instance when constructing the agent. ## Where it is used * Automatically when you construct `AnthropicMessagesAdapter` without specifying a custom `tool_adapter`. * Any agent that wants to reuse the same Anthropic formatting logic can import and instantiate it directly. ## Related references * [Adapters Overview](./index): Understand LLMAdapters and ToolResponseAdapters * [Anthropic Messages Adapter](./anthropic_messages_adapter): Understand the LLM integration that uses this adapter. # Adapters Overview Source: https://docs.meshagent.com/agents/adapters/index Adapters connect MeshAgent to external LLMs and standardize how tool results flow back into conversations. These adapters are important for any MeshAgent agent that uses an LLM. * **LLM Adapters**: Talk to a model (from a provider like OpenAI, Anthropic, etc.), translate the session context into the provider’s request format, and stream the model’s responses back. * **Tool Response Adapters**: Convert tool outputs into messages that match what the provider and UI expect (e.g., text, JSON blobs, links, files). Most people start with the built-in OpenAI adapters, but you can implement your own to integrate additional LLM vendors, customise defaults, or change how tool responses are handled. ## `LLMAdapter` The `LLMAdapter` is the base class that standardizes how MeshAgent communicates with any language model provider (OpenAI, Anthropic, self-hosted, etc.). You pick or implement an adapter for your provider and can use it with any agent that accepts an `llm_adapter` parameter. ### Why LLM adapters exist Different LLM providers have different: * Request and response formats * Tool-calling protocols * Streaming APIs * System role conventions by models (e.g., some use "system", others use "developer") * Termination signals The adapter abstracts these differences so your agent logic remains provider-agnostic. ### Adapter responsibilities The `LLMAdapter` supplies the methods your implementation uses to run a full conversation turn. For a concrete reference, see the [OpenAI Responses Adapter](./openai_responses_adapter). * Input: Receive the current session context and the toolkits selected for this turn. * Call the model: Use the provider's API/SDK to send the messages; stream tokens/events back. * Handle tools: When the model requests a tool, execute it via the toolkit and capture the result (using a `ToolResponseAdapter` if provided). * Update Context: Add tool results back into the session context so the model can use it in the same turn or a later one (depending on the agent). * Optional compaction: When the context is too large for the model, compact it before sending the next request. * Output: Return the model’s final response for the turn (text or structured output). > Adapters append results to the in-memory session context for the turn. Whether that context is persisted across turns is agent-specific. Process-backed chat flows persist thread history across turns, while one-shot task-style flows can choose not to. ### What an `LLMAdapter` base class defines * `default_model()`: Return the model name (or identifier) the adapter should use when the caller does not override it. * `create_session()`: Creates a fresh `AgentSessionContext`. Implementations can use this to set provider and model specific roles (e.g., some models prefer a "developer" prompt vs a "system" prompt). * `context_window_size(model: str)`: Declare the model's context window size if known. * `needs_compaction(context)`: Decide if the current context should be compacted before the next request. * `compact(context, model?)`: Mutate the context to a smaller representation (provider-specific). * `get_input_tokens(...)`: Optional helper to estimate the token count for the current request. * `check_for_termination(context)`: Allows you to use the session context to decide whether the conversation should continue. Can be used to check end-of-turn events based on provider semantics. * `next(...)`: The core method: given the session context, room, toolkits for this turn, and an optional `ToolResponseAdapter`, call the underlying LLM, stream events (via `event_handler`), execute tool calls, inject tool results into the context, and return the final output. You can pass `output_schema` for structured responses, override `model`, and act `on_behalf_of` a participant. See [OpenAI Responses Adapter](./openai_responses_adapter) for a detailed implementation. * `validate(response, output_schema)`: Validate structured output using JSON Schema. ### Context compaction LLM adapters can optionally compact a session context before a new request when the context is too large for the model. The base class provides `needs_compaction()` and `compact()` as hooks; the default implementations do nothing. If your adapter supports compaction, check `needs_compaction()` early in `create_response()` and mutate the `AgentSessionContext` in-place (for example, by summarizing older messages or using a provider's compaction API). The built-in [OpenAI Responses Adapter](./openai_responses_adapter) performs this automatically. ### How agents use adapters (conversation turn flow) 1. The agent resolves toolkits for this turn 2. The agent calls `llm_adapter.create_response(...)` with the messages and toolkits 3. The adapter streams events, executes tool calls, and returns the final result ### Implementing your own LLM Adapter 1. **Subclass `LLMAdapter`.** Provide defaults for the model name and optionally a custom `create_session()`. 2. **Implement `create_response()`.** Use your provider’s SDK or API to send the session context, include tool definitions derived from the supplied toolkits, stream result, execute any tool calls, and append tool outputs back to the session context. 3. **Bundle native tools (optional).** If your provider works best with provider-native tools, expose them as ordinary `Toolkit` instances and let the caller include those toolkits for the turn. 4. **Be mindful of cancellation and telemetry.** Make appropriate operations async, apply appropriate timeouts/retries, and emit tracing data if you integrate with OpenTelemetry (the base adapters do). ## `ToolResponseAdapter` While `LLMAdapter` talks to the model, a `ToolResponseAdapter` decides how to surface tool outputs to the ongoing conversation and exposes a plain-text view when the host needs one. Every tool invocation returns a `Response` (`TextChunk`, `JsonChunk`, `FileChunk`, `LinkChunk`, `EmptyChunk`, `ErrorChunk`, `RawOutputsChunk`, etc.). The adapter translates that object into the concrete payloads that should be appended to the session context and, optionally, into a readable string. ### Core responsibilities * **Chat context updates:** Return message objects from `create_messages` that the LLM adapter will append to the conversation. The structure is provider-specific (for OpenAI Responses the payloads are `{"type": "function_call_output", ...}` objects rather than assistant-role messages). * **Plain-text representation:** Provide a best-effort human-readable string via `to_plain_text`. Callers decide if and where to display it. * **Attachment handling:** Convert `FileChunk`, `LinkChunk`, or other rich responses into whatever metadata the LLM provider expects (e.g., base64-encoded blobs or image inputs for OpenAI Responses). * **Passthrough outputs:** Some adapters support provider-native payloads (like `RawOutputsChunk`) for cases where you already have the final message objects. ### Base interface ```python Python theme={null} class ToolResponseAdapter(ABC): @abstractmethod async def to_plain_text(self, *, response: Response) -> str: ... @abstractmethod async def create_messages( self, *, context: AgentSessionContext, tool_call: Any, response: Response, ) -> list: ... ``` * `to_plain_text` – convert the response into a single string (used by loggers or providers that expect plain text). * `create_messages` – return the list of messages to append to the session context. ### When to customize * **Provider expectations:** Different APIs have their own schema for tool results. Implement a custom adapter when you need to emit non-default roles, event types, or headers. * **UI formatting:** If you want to display richer summaries (markdown tables, shortened JSON, etc.), override `to_plain_text` or wrap the adapter so the host displays exactly what users need. ### Usage in the chat loop During each tool call the LLM adapter: 1. Executes the requested tool via the toolkit. 2. Passes the tool’s `Response` object to the configured `ToolResponseAdapter`. 3. Appends the returned messages to the session context so the LLM can see the outcome. 4. Optionally uses `to_plain_text` if the hosting application wants to log or display a summary. Nothing is automatically pushed to the UI unless the caller does so. If you use the OpenAI Responses adapter and omit `tool_adapter`, it defaults to the OpenAI-focused implementation described next. ## Related Topics * [MeshAgent LLM Proxy](../routing/llm_proxy) * [OpenAI Responses Adapter](./openai_responses_adapter) * [OpenAI Tool Response Adapter](./openai_tool_response_adapter) * [Anthropic Messages Adapter](./anthropic_messages_adapter) * [Anthropic Tool Response Adapter](./anthropic_tool_response_adapter) # OpenAI Responses Adapter Source: https://docs.meshagent.com/agents/adapters/openai_responses_adapter The OpenAI Responses adapter is our reference `LLMAdapter` implementation. It enables MeshAgent agents to use the [OpenAI Responses API](https://platform.openai.com/docs/guides/responses), handling streaming, tool calls, and model-specific settings. ## Key features * **Model defaults:** Reads the model name from the constructor (`model=`) or the `OPENAI_MODEL` environment variable. Override per message by passing `model` in the chat payload. * **Session context defaults:** Creates `AgentSessionContext(system_role=None)` so system/developer prompts are driven by the caller or wrapper agent. * **Tool bundling:** Converts the supplied toolkits into OpenAI tool definitions (both standard JSON function tools and OpenAI-native tools like `computer_use_preview`, `web_search_preview`, `image_generation`). * **Streaming support:** Consumes the streaming response API, emitting events such as reasoning summaries, partial content, and tool call updates. * **Parallel tool calls:** Optionally enables OpenAI’s `parallel_tool_calls` setting (disabled automatically for models that do not support it). * **Structured output:** If `output_schema` is provided to `create_response()`, requests JSON schema output and validates the result. * **Automatic compaction:** Uses OpenAI Responses auto-compaction (`context_management`) by default. ## Constructor parameters ```python Python theme={null} OpenAIResponsesAdapter( model: str = "gpt-5.2", parallel_tool_calls: Optional[bool] = None, client: Optional[AsyncOpenAI] = None, response_options: Optional[dict] = None, reasoning_effort: Optional[str] = None, provider: str = "openai", log_requests: bool = False, max_output_tokens: Optional[int] = 32000, context_management: Literal["auto", "standalone", "none"] = "auto", compaction_threshold: int = 200000, base_url: Optional[str] = None, ) ``` * `model` – default model name; can be overridden per message. * `parallel_tool_calls` – request parallel tool execution when supported. * `client` – reuse an existing `AsyncOpenAI` client; otherwise the adapter creates one via `meshagent.openai.proxy.get_client`. * `base_url` – override the provider base URL used when the adapter creates its own client. Defaults to `OPENAI_BASE_URL` when omitted. * `response_options` – extra parameters passed to `responses.create`. * `reasoning_effort` – populates the Responses API `reasoning` options. * `provider` – label emitted in telemetry and logs. * `log_requests` – when true, logs HTTP requests for debugging. * `max_output_tokens` – cap output tokens per response; also used when deciding whether to compact the context. * `context_management` – controls compaction behavior: * `auto` attaches `context_management` to each request and lets Responses handle compaction. * `standalone` uses manual `responses.compact` preflight in the adapter. * `none` disables both auto and manual compaction. * `compaction_threshold` – threshold used for compaction (`compact_threshold` in Responses `context_management` entries and manual preflight trigger in `standalone` mode). ## Tool provider integration The adapter includes several OpenAI native tool wrappers. Agents can use them directly, or override them with agent-specific wrappers that add persistence and room-specific behavior. * **Image generation** – `ImageGenerationTool` * **Shell execution** – `ShellTool` * **MCP** – `MCPServer`, `MCPTool` * **Web search preview** – `WebSearchTool` * **File Search** - `FileSearchTool` * **Code Interpreter** - `CodeInterpreterTool` * **Reasoning** - `ReasoningTool` ## Handling a turn When `create_response()` is called it: 1. **Bundles tools** - Collects the tools from your toolkits and packages them for OpenAI's API 2. **Calls the model** - Sends messages and tools to OpenAI's API 3. **Handles responses** - Processes text, tool calls, or structured output 4. **Executes tools** - When the model requests tools, executes them and formats results 5. **Loops** - Continues calling the model with tool results until it produces a final answer 6. **Returns Result** - Gives you the final output (text or structured data) ## Context compaction `OpenAIResponsesAdapter` defaults to `context_management="auto"` and sends: `context_management=[{"type":"compaction","compact_threshold":200000}]` You can switch to: * `context_management="standalone"` to use manual `responses.compact` before a turn when usage crosses the threshold. * `context_management="none"` to disable compaction management. ## Related Topics * [Adapters Overview](./index): Understand LLMAdapters and ToolResponseAdapters * [MeshAgent LLM Proxy](../routing/llm_proxy): How requests are routed and metered inside rooms * [OpenAI Tool Response Adapter](./openai_tool_response_adapter): How tool outputs are rendered back into the chat transcript. * [Process Agents Overview](../process/overview): Shows where the adapter is invoked in the recommended overall agent flow. # OpenAI Tool Response Adapter Source: https://docs.meshagent.com/agents/adapters/openai_tool_response_adapter `OpenAIResponsesToolResponseAdapter` is the default `ToolResponseAdapter` used whenever you pair an agent with the OpenAI Responses adapter. It converts tool outputs into the payloads the OpenAI Responses API expects and exposes a plain-text summary that hosts can display or log. ## Behavior summary * **Plain-text rendering:** `to_plain_text` generates concise strings for common response types (`LinkChunk`, `JsonChunk`, `TextChunk`, `FileChunk`, `EmptyChunk`). Hosts decide whether to show or log that text. * **Chat context updates:** `create_messages` returns OpenAI Responses `function_call_output` objects so the model receives the tool result on the next turn. * **Developer logging:** Emits events via `room.developer.log_nowait` to aid debugging when tools are called. ## Response handling | Response type | Plain text example | Notes | | ----------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `TextChunk` | The returned text | Injected as-is into the chat transcript. | | `JsonChunk` | JSON string dump | Useful when the LLM expects structured output. | | `FileChunk` | `filename.ext` | Images become `input_image` payloads; PDFs use `input_file`; text/JSON are inlined; other formats return a "not supported" message. | | `LinkChunk` | `{ "name": ..., "url": ... }` | Links become JSON strings so the user can follow the URL. | | `EmptyChunk` | `"ok"` | Signals successful execution without additional data. | | `RawOutputsChunk` | n/a | Passed through directly as OpenAI Responses outputs, bypassing plain-text conversion. | ## Extending or replacing You can subclass `OpenAIResponsesToolResponseAdapter` to tweak the plain-text summary or adjust logging, provided the emitted messages continue to match the OpenAI Responses schema. Alternatively, supply your own adapter instance when constructing the agent. ## Where it is used * Automatically when you construct `OpenAIResponsesAdapter` without specifying a custom `tool_adapter`. * In the CLI chatbot and MeshAgent Studio when interacting with OpenAI models. * Any agent that wants to reuse the same formatting logic can import and instantiate it directly. ## Related references * [Adapters Overview](./index): Understand LLMAdapters and ToolResponseAdapters * [OpenAI Responses Adapter](./openai_responses_adapter): Understand the LLM integration that uses this adapter. # Agents Overview Source: https://docs.meshagent.com/agents/overview Understand how agents work in MeshAgent and where to start. Agents are room-connected participants that receive work, use tools and room capabilities, and produce results back into the room. [`meshagent process`](./process/overview) is the primary way to run agents in MeshAgent. An agent can stay available over time, accept work through multiple channels, and preserve thread continuity across conversations and jobs. ## How agents fit into MeshAgent * agents run in rooms and operate over the room's shared context * agents can use built-in tools, custom tools, skills, and room capabilities to do work * agents can be run locally for development or deployed as services so they are available in rooms when needed * agents can receive work through chat, queues, mail, toolkit calls, and other room-connected flows * agents run with an identity and a set of scoped permissions that define what they can access ## Core Capabilities MeshAgent agents are designed for work that needs continuity, steerability, and access to real runtime capabilities. Depending on how you configure them, an agent can: * stay available over long periods of time instead of running as a one-shot call * accept work through chat, queues, mail, and toolkit entry points * keep work separated by thread while preserving continuity where you want it * use built-in MeshAgent tools such as web search, storage, document authoring, shell, computer use, MCP, memory, and discovery features * use custom tools, custom toolkits, and skills * be steered with inline rules and room-backed rules files using `--rule` and `--room-rules` * use models from supported providers such as OpenAI and Anthropic through MeshAgent's routing and adapter surfaces * run with scoped identities and API grants so you can control what an agent is allowed to access ## The main mental model For most MeshAgent users, the important concepts are: * the **agent** is the running participant * the **channels** are how work reaches that agent * the **thread** is the continuity boundary for that work * the **tools, skills, and room infrastructure** are the capabilities the agent uses to act This lets one agent identity grow across several entry points without forcing you to build separate runtimes for chat, queue, mail, and toolkit usage. ## What agents are typically used for Common patterns include: * interactive chat agents for support, coding, research, or operations * background agents that consume queue work * mail-capable agents that turn inbound email into room work * toolkit-style agents that can be invoked by other agents * prebuilt agents you can add directly in MeshAgent Studio or Powerboards * custom agents you package and deploy yourself Some workflows combine several of those patterns in the same running agent. ## Identity, access, and scope When an agent is deployed, it runs with a participant identity and a set of room/API grants. That means you can decide whether the agent should be able to read storage, write to the dataset, run containers, or access other room capabilities. Deployment does not automatically grant every capability; the agent only gets the access you give it. Managed agent identities can also be created, connected, and granted room access through the REST API and SDKs. See the [REST API overview](../rest_api/overview) for the managed agent, agent grant, and agent-room grant endpoints. Managed agent identities can also be created, connected, and granted room access through the REST API and SDKs. See the [REST API overview](../rest_api/overview) for the managed agent, agent grant, and agent-room grant endpoints. ## Related parts of the docs * Start with [Process Agents](./process/overview) for the main runtime path. * Go to [Built-in MeshAgent Toolkits](./tools/built_in_toolkits), [Tools and Toolkits](./tools/tools_and_toolkits), and [Skills](../agent_skills/overview) to understand what agents can do and how you shape their behavior. * Go to [MeshAgent LLM Proxy](./routing/llm_proxy), [Use Codex and Claude with MeshAgent](./routing/use_codex_claude), [Local CLI Proxy](./routing/local_cli_proxy), and [LLM Adapters](./adapters/index) when you want MeshAgent to sit between agents or provider-compatible tools and the upstream model provider. * Go to [Queues and Scheduled Tasks](./queues_and_scheduled_tasks) for recurring and background work patterns. * Go to [Deploy & Manage](../services/deployment/deploy_services) when you are ready to package and deploy agents as services. * Go to [REST API](../rest_api/overview) when you need to create managed agents or manage their grants programmatically. ## Other agent surfaces [VoiceBot](./standard/voicebot) is the voice-focused runtime for real-time speech interactions. # Agent Turns Source: https://docs.meshagent.com/agents/process/agent_turns Understand how process-backed agents start, run, steer, and end turns across threads and channels. An **agent turn** is one unit of work handled by a process-backed agent. If a user sends one chat message, a queue consumer submits one job, or another participant invokes the agent as a toolkit, that input becomes a turn. Turns exist so MeshAgent can keep a few concerns separate: * the **room messaging fabric** that carries messages between participants * the **thread** that defines continuity and persistence * the **turn lifecycle** that tells clients what one active run is doing right now ## Why turns are separate from plain messages Plain room messages are good for discrete participant-to-participant communication. Process-backed agents need more than that. They need to: * accept work from several channels * assign that work to a specific thread * report that the work was accepted before it actually starts * stream progress while the turn is still running * allow steering or interruption of the active turn * mark the point where the turn started and ended That is why MeshAgent uses a turn protocol instead of treating every agent interaction as a plain chat message. ## Turn lifecycle At a high level, the flow looks like this: 1. A client sends `meshagent.agent.turn.start`. 2. The runtime replies with `meshagent.agent.turn.start.accepted`. 3. When execution actually begins, the runtime emits `meshagent.agent.turn.started`. 4. While the turn runs, the runtime can emit text deltas, tool call events, approval requests, and other live updates. 5. When the turn finishes or fails, the runtime emits `meshagent.agent.turn.ended`. The important distinction is: * `turn.start.accepted` means the runtime accepted the request * `turn.started` means that specific turn is now active * `turn.ended` means that active turn is finished ## Core turn messages | Message or event | What it means | | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `meshagent.agent.turn.start` | Start a new turn for a given thread path, carried on the process-message `thread_id` field, with typed input content. | | `meshagent.agent.turn.start.accepted` | The runtime accepted the request and tied it to the source message. | | `meshagent.agent.turn.started` | The turn is now active and has a `turn_id`. | | `meshagent.agent.turn.steer` | Add more input to the active turn without starting a separate turn. | | `meshagent.agent.turn.interrupt` | Interrupt the active turn. | | `meshagent.agent.turn.ended` | The turn completed or failed. | ## What a turn start carries A turn start request includes: * `thread_id`: the persisted thread path this work belongs to * `message_id`: the client-side message id for correlation * `content`: typed input items such as text or files * optional `model`: override the model for this turn * optional `instructions`: extra instructions for this turn * optional toolkit configuration * optional tool choice That allows one process-backed agent to accept work from different sources while still keeping continuity and per-turn behavior explicit. Queue and scheduled-task inputs use `path` for the same value. The process runtime carries that resolved thread path as `thread_id` after the queue item has been converted into a turn-start message. Example shape: ```json theme={null} { "type": "meshagent.agent.turn.start", "thread_id": "dataset://.threads/support/123", "message_id": "client-msg-1", "content": [ { "type": "text", "text": "Summarize the latest queue activity." } ] } ``` ## Steering and interruption Steering and interruption are part of the same turn model. Use steering when the turn should continue but needs more input. For example: * a user clarifies what they meant * a UI wants to append more instructions * a workflow injects follow-up context while the turn is still live Use interruption when the active turn should stop. For example: * the user cancelled the request * the UI is starting a different turn instead * a tool flow became irrelevant or stale These are control messages, not new conversations. They apply to the active `turn_id`. ## How turns relate to threads A thread can contain many turns over time. The thread gives the runtime a persisted continuity boundary. The turn gives the runtime a live execution boundary. That means: * **thread** answers "what history does this work belong to?" * **turn** answers "what active run is happening right now?" One process runtime can serve many threads. Each thread can have many turns. For the persistence model, see [Threads Overview](../threads_overview). ## How turns relate to messaging Turn messages are carried over the same room messaging fabric used by other participant messages, but they are not the same thing as the general-purpose Messaging API. Use the [Messaging API](../../room_api/messaging) when you want: * direct participant messages * broadcasts * attachments * participant discovery Use the turn protocol when you want: * process-backed agent execution * active-turn lifecycle updates * steering or interruption * thread-aware runtime control ## Related docs * [Process Agents](./overview) * [Process Agent Architecture](./architecture) * [Threads Overview](../threads_overview) * [Messaging API](../../room_api/messaging) # Process Agent Architecture Source: https://docs.meshagent.com/agents/process/architecture ## Overview This page is for engineers who want to understand how `meshagent process` maps to the implementation. At a high level, the runtime works like this: * channels convert outside inputs into process messages * a supervisor routes those process messages by their resolved thread path * a configured backend creates one process for each active thread * thread storage writes runtime events back into the persisted thread model This gives you one process-backed agent that can accept several channels without collapsing unrelated work into one shared live context. ## What `meshagent process` actually builds At the CLI level, `meshagent process` is a command group. In the current implementation, that command group reuses the chatbot command implementation and switches it into the `process` runtime mode. When you run `meshagent process`, the CLI builds: * one `SingleRoomAgent` * zero or one `ChatChannel` * zero or more `MailChannel` instances * zero or more `QueueChannel` instances * zero or more `ToolkitChannel` instances * one `AgentSupervisor` * one or more configured backends, such as `LLMBackend` or `CodexBackend` * one backend-created process per active thread * one `ThreadStorage` instance per persisted active thread That layering matters because `process` is not a single SDK class called "ProcessAgent". It is a runtime assembly of channels plus per-thread execution. ## Runtime flow ```mermaid theme={null} flowchart LR A["Channel receives input"] --> B["TurnStart or related message"] B --> C["AgentSupervisor"] C --> D["Backend process for thread A"] C --> E["Backend process for thread B"] D --> F["ThreadStorage"] E --> G["ThreadStorage"] F --> H["Thread events, tool calls, outputs"] G --> H ``` In practice: 1. a channel receives input from chat, mail, a queue, or a toolkit invocation 2. the channel emits process messages, including the resolved thread path on `thread_id` 3. the supervisor selects the configured backend for the thread 4. the backend finds or creates the process for that thread 5. the thread-scoped process runs the turn 6. thread storage records outputs, lifecycle state, tool activity, and status into the thread model ## Channel responsibilities A channel has one job: * receive input from some source * convert it into process messages * emit those messages into the supervisor That makes channels the extension point for new integrations. The built-in channel types are: * `ChatChannel` * `MailChannel` * `QueueChannel` * `ToolkitChannel` If you want to add another surface, such as Slack, the process model is to add another channel adapter that turns Slack events into process messages. ## What `AgentSupervisor` does `AgentSupervisor` is the router for the runtime. Its main responsibilities are to: * hold the active channels for the runtime * accept messages emitted by those channels * route those messages to the correct thread process * create a new process when a thread is seen for the first time * start and stop managed processes as the runtime lifecycle changes If you are looking for the place where work becomes thread-scoped, this is it. The supervisor is the boundary between "one long-running process-backed agent" and "per-thread execution". ## Channel roles The built-in channels each adapt a different source of input: * `ChatChannel`: bridges room messages and thread-oriented chat interfaces * `MailChannel`: turns inbound mail into turns and sends the resulting reply back through the mailbox flow * `QueueChannel`: listens on a room queue and turns queue payloads into agent turns * `ToolkitChannel`: exposes the agent as a callable toolkit so other participants can send a prompt and receive a reply ## What a backend process does The backend process is the thread-level execution loop for turns. Each instance handles one active thread at a time and is responsible for: * receiving routed messages for that thread * running the agent logic * managing turn lifecycle events * coordinating tool calls and approvals * emitting outputs back to the channels and thread storage This is why one process-backed agent can serve many channels and many threads without mixing unrelated thread state together. ## Backend implementations A backend decides what kind of thread process gets created after a channel delivers a turn. | Backend | Selected with | Thread process | What it does | | ------- | ------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------- | | LLM | `--model gpt-5.5` or another standard model | `LLMAgentProcess` | Runs the turn through MeshAgent's LLM adapters, including tool calls, streaming, and model/provider selection. | | Codex | `--backend codex` or `--model codex/...` | `CodexAgentProcess` | Runs the turn through Codex app-server while MeshAgent keeps the room participant, channels, routing, and thread storage. | Most application agents should use the LLM backend. Use the Codex backend when you want the same room participant, channel, routing, deployment, and thread-storage model, but you want Codex to execute the turns. ## Per-thread routing and queueing The supervisor routes by the process-message `thread_id` field, which contains the resolved thread path, and creates a thread process on first use. This matters for two reasons: * messages for the same thread go to the same backend process * unrelated threads do not share one live execution state In practice, this is what prevents turns on the same thread from stepping on each other while still letting one process-backed agent serve many threads. ## Local memory channel `meshagent process run` can also use a `memory` channel. This is separate from the Memories toolkit. * `--channel memory` is a local process-run channel used by the CLI's interactive process session. * `meshagent process run` defaults to the memory channel when no channel is provided. * `--no-room` uses that path to run locally without connecting to a room. * `--use-memory ` is different: it adds the room-backed Memories toolkit to the agent. Use `--channel chat` when the agent should be reachable from room chat in Studio or Powerboards. Use the memory channel when you want a local interactive process run that does not need room chat. ## Streaming and live turn state The process runtime does not just wait for a final answer. It emits incremental state as a turn progresses. That includes: * text deltas * file output updates * reasoning summary updates * tool call progress and logs * turn lifecycle events such as started, completed, failed, or interrupted Those updates are written into the thread model so UIs and other clients can reflect what is happening while the turn is still running. ## Approvals, steering, and interrupts Process also handles live control flows around an active turn: * tool calls can pause and wait for approval * turns can be steered with additional input * turns can be interrupted and resumed or cancelled These are runtime features, not channel-specific hacks. Channels deliver the messages, and the process runtime handles them in a thread-aware way. This is part of what makes process-backed agents useful for coding, research, and other longer-running workflows. ## What thread storage does `ThreadStorage` is the bridge between the process runtime and the persisted thread representation. It is responsible for turning process events into thread updates such as: * messages and content items * tool call state * status updates * turn lifecycle data This keeps the process runtime aligned with the same thread model used elsewhere in MeshAgent. It also maintains per-thread status and pending-message metadata so clients can show whether a thread is thinking, waiting for approval, or ready to be steered. ## Context isolation The important rule is: * **context isolation is by thread path, not by process** That means one process-backed agent can accept input from several channels without automatically mixing those histories together. Context only overlaps when two inputs use the same thread path. ## Adapter-provided model behavior Some behavior comes from the configured LLM adapter rather than from the process runtime itself. For example, streaming model events and reasoning summaries are surfaced through the process runtime, but capabilities such as automatic context compaction depend on whether the selected adapter supports them. ## Where to go next * [Process Agents Overview](./overview): when to choose `process` * [Agent Turns](./agent_turns): the product-facing turn lifecycle model * [Threads Overview](../threads_overview): the persistence model process agents build on # Codex Process Backend Source: https://docs.meshagent.com/agents/process/codex_backend Run a MeshAgent process agent whose turns are handled by Codex. Use the Codex backend when you want Codex to run the turns for a room-connected process agent. MeshAgent owns the room-facing runtime: the agent participant, channels, deployment, routing, and stored thread history. Codex handles each turn behind that process agent. This is different from using MeshAgent with Codex CLI or Codex Desktop. If you want to run Codex normally and route model traffic through the MeshAgent LLM Proxy, use `meshagent setup` or `meshagent launch codex`; see [Use Codex and Claude with MeshAgent](../routing/use_codex_claude). A Codex-backed process agent creates an agent participant in a room and sends that participant's turns to Codex app-server. ## Run locally Start a chat agent in the `gettingstarted` room: ```bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name codex-agent \ --channel chat \ --backend codex ``` Open the same room in [MeshAgent Studio](https://studio.meshagent.com) and chat with `codex-agent`. While the command is running, the agent is connected to the room. You can test it in Studio like any other process agent because the room, participant, and chat channel are still managed by MeshAgent. Stop the local process when you are done testing. ## Select the Codex backend Use `--backend codex` for the default Codex-backed process agent. Use `--model codex/gpt-5.5` when you need to pin a specific Codex model. If you pass a normal model name such as `--model gpt-5.5`, the process agent uses the standard LLM backend. That path sends turns through MeshAgent's LLM adapters. If you pass a Codex model path such as `--model codex/gpt-5.5`, the process agent uses the Codex backend. `--model` can be repeated when you want to choose the exact models the agent can switch between. `--backend` is broader: it makes a backend's default model set available. `--backend codex` currently adds `codex/gpt-5.5`. `--backend llm` currently adds `llm/openai/gpt-5.2` and `llm/anthropic/claude-3-5-sonnet-latest`. If you omit both `--backend` and `--model`, the process command defaults to `--model gpt-5.5`, which is a standard LLM-backed agent. You can also make both backends available from the same agent by passing both models: ```bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name codex-agent \ --channel chat \ --model gpt-5.5 \ --model codex/gpt-5.5 ``` This uses the default dataset-backed process-agent thread storage, so the room thread remains the durable history while the selected model can change. In chat, use `/models` to list available models, then use `/model codex/gpt-5.5` to switch to Codex or `/model gpt-5.5` to switch back to the standard LLM backend. Do not use `--thread-storage codex` for a mixed-backend agent; Codex thread storage only supports Codex backends. ## Deploy the agent When the local version works, deploy the same agent so it stays available without your terminal open: ```bash theme={null} meshagent process deploy \ --service-name codex-agent \ --room gettingstarted \ --agent-name codex-agent \ --channel chat \ --backend codex ``` This creates or updates a room service for `codex-agent`. ## Pin a Codex model ```bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name codex-agent \ --channel chat \ --model codex/gpt-5.5 ``` Use this form when you need to choose an exact Codex model. Otherwise, prefer `--backend codex` so the process agent uses the default Codex model. ## How it works The process agent still runs through MeshAgent, but turn execution moves to Codex: 1. `meshagent process` joins the room as `codex-agent`. 2. The `chat` channel turns room chat into process-agent turns. 3. The process supervisor routes each turn to the selected backend. 4. The Codex backend starts the local Codex app-server and sends the turn to it. 5. Codex app-server runs the Codex thread with Codex's native coding-agent runtime. 6. MeshAgent records the thread history using the default dataset-backed process-agent storage. Codex app-server is the local Codex runtime used by the Codex SDK. OpenAI describes it as a local app-server controlled over JSON-RPC. MeshAgent uses that runtime so the room participant can use Codex behavior while still using MeshAgent rooms, channels, deployment, and thread storage. See the [OpenAI Codex SDK docs](https://developers.openai.com/codex/sdk#python-library) for the app-server client model. Use this instead of `--model gpt-5.5` when you specifically want Codex's coding-agent runtime behind the MeshAgent room participant. Use a normal model name when you need a standard LLM-backed process agent. ## Tool support Codex-backed process agents use Codex app-server's native runtime, not MeshAgent's LLM tool pipeline. That means Codex app-server owns coding-agent behavior such as command execution, file changes, plans, sandboxing, approvals, and any MCP tools configured for Codex itself. MeshAgent receives those Codex events and records them in the process thread. MeshAgent also surfaces Codex diff updates as `codex` tool events in the turn stream so Studio can show code changes as part of the work. Use the standard LLM backend when the agent needs MeshAgent tool flags such as `--require-toolkit`, `--tool-search`, `--web-search`, `--storage`, `--mcp`, `--shell`, or `--advanced-shell`. Those flags add tools to LLM turns. Custom MeshAgent room toolkits are not exposed to Codex turns through `--tool-search` or `--require-toolkit`. ## Where to go next * [Process Agents](./overview): learn the standard process-agent pattern * [Use Codex and Claude with MeshAgent](../routing/use_codex_claude): route Codex CLI or Codex Desktop through the MeshAgent LLM Proxy # Process Agents Source: https://docs.meshagent.com/agents/process/overview `meshagent process` is the main CLI runtime for agents that stay available in a room. Use it when you want one agent identity that people can talk to conversationally and that can also handle background work from queues, mail, or toolkit calls. ## Run a multi-channel process agent locally If you want the agent to receive email, create the mailbox first: ```bash theme={null} meshagent mailbox create \ --address support-agent@mail.meshagent.com \ --room quickstart \ --queue support-agent@mail.meshagent.com ``` Then start one agent with chat, mail, queue, and toolkit channels: ```bash theme={null} meshagent process join \ --room quickstart \ --agent-name support-agent \ --channel chat \ --channel mail:support-agent@mail.meshagent.com \ --channel queue:support-jobs \ --channel toolkit:support-agent \ --threading-mode default-new \ --thread-dir ".threads/support-agent" \ --web-search \ --storage \ --rule "You are a helpful support agent. Answer clearly, use web search when needed, and save important artifacts to storage." ``` This gives you one room-connected agent that: * can be reached through chat, mail, queue, and toolkit channels * keeps thread history under `.threads/support-agent` * has built-in web search and storage tools * has one inline rule This is the default `meshagent process` pattern: one long-running agent can serve several entry points while keeping continuity organized by thread. If you want to see more channels, model options, and built-in tool flags, run: ```bash theme={null} meshagent process join --help ``` ## How to reach the agent Once the process is running, you can use the same agent in a few different ways. ### Chat with it conversationally Open the same room in [MeshAgent Studio](https://studio.meshagent.com) and start chatting with `support-agent`. * MeshAgent Studio is the main place to test the agent while you are building * you can inspect the room, participants, logs, traces, and metrics while the process is running ### Send background work through the queue Use the queue channel when you want the same agent to do non-interactive work: ```bash theme={null} meshagent room queue send \ --room quickstart \ --queue support-jobs \ --json '{"prompt":"Summarize the current support backlog and save a report."}' ``` This is the background-task path. It is useful for recurring jobs, automation, imports, and other work that should not start from a live chat message. ### Invoke it from another agent or app Use the toolkit channel when another participant should be able to call this agent as a tool: ```bash theme={null} meshagent room agents invoke-tool \ --room quickstart \ --toolkit support-agent \ --tool run_support_agent_task \ --arguments '{"prompt":"Draft a short reply explaining the refund policy."}' ``` ### Send it email If you enabled `mail:support-agent@mail.meshagent.com`, you can also email the agent at that address and let the mail channel turn the message into room work. ## Deploy the same agent When the local version looks right, deploy the same agent shape so it stays available without your terminal open: ```bash theme={null} meshagent process deploy \ --service-name support-agent \ --room quickstart \ --agent-name support-agent \ --channel chat \ --channel mail:support-agent@mail.meshagent.com \ --channel queue:support-jobs \ --channel toolkit:support-agent \ --threading-mode default-new \ --thread-dir ".threads/support-agent" \ --web-search \ --storage \ --rule "You are a helpful support agent. Answer clearly, use web search when needed, and save important artifacts to storage." ``` Use `meshagent process join` while developing and `meshagent process deploy` when you want the agent to stay available as a room or project service. ## What `meshagent process` is Supported channels: | Channel | Use it for | | -------------- | -------------------------------------------------------------------------------- | | `chat` | Interactive conversation in MeshAgent Studio, Powerboards, or other chat clients | | `mail:EMAIL` | Turning inbound email into agent work | | `queue:NAME` | Running background jobs from a room queue | | `toolkit:NAME` | Letting other agents or apps call this agent like a toolkit | Each `--channel` flag adds another entry point to the same running agent. The core idea is simple: * the **agent** is the running participant * the **channels** are how work reaches that agent * the **thread** is the continuity boundary That means one running agent can serve several entry points without automatically mixing unrelated work together. Work shares continuity when it uses the same thread path. ## Shape the agent with rules and tools The process command is also where you shape what the agent can do. * use `--rule` for inline instructions * use `--room-rules` when you want editable room-backed rules * use tool flags such as `--web-search`, `--storage`, `--mcp`, `--shell`, or `--advanced-shell` to add capabilities * choose the model with `--model` That means `meshagent process` is not just how the agent starts. It is also how you define its channels, rules, tools, and continuity behavior. ## Choose a backend The backend is the part of the process agent that handles a turn after a channel delivers it. | Backend | How to select it | Use | | ------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- | | LLM | `--model gpt-5.5`, another standard model name, or `--backend llm` | General-purpose process agents that use MeshAgent's LLM adapters | | Codex | `--backend codex` or `--model codex/gpt-5.5` | Room-connected agents whose turns should be handled by Codex | Most process agents use the LLM backend. Use the [Codex Process Backend](./codex_backend) page when you want the same process-agent channel and deployment model, but Codex handling the turns. Use `--model` when you want to choose the exact model or models the agent can use. `--model` can be repeated. A plain model name such as `gpt-5.5` selects the LLM backend. A backend-qualified model such as `codex/gpt-5.5` selects the Codex backend. Use `--backend` when you want to make a backend's default model set available without naming every model yourself. `--backend llm` currently adds `llm/openai/gpt-5.2` and `llm/anthropic/claude-3-5-sonnet-latest`. `--backend codex` currently adds `codex/gpt-5.5`. If you omit both `--backend` and `--model`, the command defaults to `--model gpt-5.5`. You can also make more than one backend available from the same running agent by passing multiple model flags: ```bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name support-agent \ --channel chat \ --model gpt-5.5 \ --model codex/gpt-5.5 ``` With the default dataset-backed thread storage, the same agent can switch between those models on the same thread. In chat, use `/models` to see the available models, then use `/model` with a backend-qualified model when needed, such as `codex/gpt-5.5`. Keep the default dataset storage for this pattern; Codex thread storage only supports Codex backends. ## When to use `meshagent process` Use `meshagent process` when you want an agent that should: * stay available over time instead of acting like a one-shot run * work across chat, mail, queues, or toolkit calls * keep one rules and tools setup across those entry points * preserve thread continuity across longer workflows * be easy to run locally and then deploy with the CLI ## Threads and continuity Thread configuration matters most when the agent needs durable history. * `--thread-dir` controls where persisted thread history is organized * `--threading-mode` controls how chat-oriented clients treat thread creation and selection Use a dedicated thread directory when you want one agent to support many conversations or jobs without mixing them together. For the deeper persistence model, see [Threads Overview](../threads_overview). ## Main commands | Command | Use | | -------------------------- | ----------------------------------------------- | | `meshagent process join` | Run the agent locally in a room | | `meshagent process run` | Run the agent and wait for interactive messages | | `meshagent process use` | Send work to a running process agent | | `meshagent process spec` | Generate a service manifest from CLI flags | | `meshagent process deploy` | Deploy the agent as a service | ## Where to go next * [Codex Process Backend](./codex_backend): run a room-connected process agent with Codex as the backend * [Agent Turns](./agent_turns): understand how one request becomes one process-backed turn and how turn lifecycle differs from plain messages * [Process Agent Architecture](./architecture): understand how channels, supervisors, and per-thread execution fit together * [Threads Overview](../threads_overview): understand thread paths, thread directories, and persisted continuity * [Tools and Toolkits](../tools/tools_and_toolkits): understand built-in tools, custom tools, and toolkit patterns * [Queues and Scheduled Tasks](../queues_and_scheduled_tasks): use queues for background work # Queues and Scheduled Tasks Source: https://docs.meshagent.com/agents/queues_and_scheduled_tasks Run background and recurring work with queues and scheduled tasks. Queues and scheduled tasks are the main building blocks for background and recurring work in MeshAgent. ## Run a queue-backed agent Start an agent that listens on a room queue: ```bash theme={null} meshagent setup meshagent rooms create myroom --if-not-exists meshagent process join \ --room myroom \ --agent-name queue-agent \ --channel queue:support-jobs \ --storage \ --web-search \ --rule "You are a queue-based support operations agent. Process queued jobs without asking follow-up questions unless the job explicitly asks for interactive behavior." ``` This gives you one agent that consumes background work from the `support-jobs` queue. ## Send work into the queue Once the agent is running, enqueue a job: ```bash theme={null} meshagent room queue send \ --room myroom \ --queue support-jobs \ --json '{"prompt":"Summarize the latest support backlog and save a report."}' ``` This is the main queue pattern: * the queue holds the work item * the agent consumes it * the agent runs without needing a live chat message For MeshAgent queue consumers such as `meshagent process` queue channels, the payload can also be structured. For example, you can provide typed prompt content and a thread template: ```bash theme={null} meshagent room queue send \ --room myroom \ --queue support-jobs \ --json '{"path":"dataset://threads/support/{YYYY}/{MM}/{DD}/{HH}/{mm}/summary","prompt":[{"type":"file","url":"room:///prompts/support-summary.md"},{"type":"text","text":"Summarize the current support backlog and highlight urgent issues."}]}' ``` Use `prompt` when you want room prompt files such as `room:///prompts/support-summary.md` resolved into text before the turn starts. Use `content` when you want typed file items preserved as file inputs for the agent. ## Schedule recurring work Scheduled tasks run on a cron schedule. Schedules must be at least 15 minutes apart. Add a task that sends one job into the same queue every day: ```bash theme={null} cat > support-summary-task.yaml <<'YAML' version: v1 kind: ScheduledTask schedule: 30 17 * * * queue: name: support-jobs payload: prompt: Generate the daily support summary and save it to storage. YAML meshagent scheduled-task add \ --room myroom \ --file support-summary-task.yaml ``` This creates a project-level scheduled task that targets the `support-jobs` queue in `myroom`. Scheduled-task payloads use the same queue message format, so you can also send structured `prompt` or `content` payloads and thread templates when the target consumer is a MeshAgent queue channel. Scheduled tasks can also start a container directly by using the `container` target in the same `ScheduledTaskSpec` file: ```bash theme={null} cat > hourly-container-task.yaml <<'YAML' version: v1 kind: ScheduledTask schedule: 0 * * * * container: image: alpine:latest command: echo scheduled YAML meshagent scheduled-task add \ --room myroom \ --file hourly-container-task.yaml ``` List scheduled tasks: ```bash theme={null} meshagent scheduled-task list --room myroom ``` Update a scheduled task: ```bash theme={null} meshagent scheduled-task update TASK_ID \ --file support-summary-task.yaml ``` View recent task runs: ```bash theme={null} meshagent scheduled-task runs TASK_ID ``` Delete a scheduled task: ```bash theme={null} meshagent scheduled-task delete TASK_ID ``` ## How queues and scheduled tasks fit together * **Queues** are the delivery mechanism for asynchronous work * **Scheduled tasks** are the trigger that enqueues work on a schedule * **Agents or services** consume the queued work That makes queues useful for one-off background jobs and scheduled tasks useful for recurring work such as daily digests, periodic reports, monitoring jobs, or imports. ## Room scope and project scope Queue operations are room-level operations. Scheduled tasks are managed at the project level, but they usually target a queue for a specific room. That is why the scheduled-task commands take both a queue and an optional `--room`. ## Related guides * [Queues API](../room_api/queue): room-level queue operations * [Process Agents](./process/overview): run one agent across chat, queue, mail, and toolkit channels * [Projects > Scheduled Tasks](../project_admin/scheduled_tasks): create and manage scheduled tasks at the project level * [Deploy a Process Agent](../services/deployment/process_agent_service): deployment pattern that includes scheduled work * [CLI Reference](../reference/meshagent_cli_help): full queue and scheduled-task command reference # Ask MeshAgent from the CLI Source: https://docs.meshagent.com/agents/routing/ask_meshagent_cli Send direct prompts through MeshAgent from the terminal without starting a room agent. `meshagent ask` is the direct terminal prompt path for MeshAgent. Use it when you want to: * ask one question through the active MeshAgent project * get a streamed terminal answer without starting a room agent * open a lightweight interactive terminal UI `meshagent ask` uses the hosted [MeshAgent LLM Proxy](./llm_proxy) path directly for the active project. It does not require `meshagent llm proxy` to be running. If you want Codex or Claude configured for normal use, use [Use Codex and Claude with MeshAgent](./use_codex_claude). If you want another local SDK or tool to talk through MeshAgent, use [Local CLI Proxy](./local_cli_proxy). ## Get started If you have not set up MeshAgent yet, start with: ```bash bash theme={null} meshagent setup ``` `meshagent ask` uses: * the active MeshAgent project * either a MeshAgent token in `MESHAGENT_TOKEN` or a logged-in CLI session from `meshagent auth login` If `meshagent ask` cannot find a MeshAgent token or logged-in CLI session, run `meshagent setup` first, then retry. ## One-shot prompt ```bash bash theme={null} meshagent ask --message "Summarize the differences between queue channels and messaging channels." ``` You can also choose the output format: ```bash bash theme={null} meshagent ask \ --message "Write release notes for this diff." \ --format markdown ``` And override the model for the request: ```bash bash theme={null} meshagent ask \ --message "Explain this API at a beginner level." \ --model gpt-5.4 ``` ## Interactive terminal UI Run `meshagent ask` with no `--message` in a TTY to open the interactive prompt UI: ```bash bash theme={null} meshagent ask ``` This is useful when you want a quick back-and-forth in the terminal but do not need a persistent room agent. ## When to use `meshagent ask` vs `meshagent process` Use `meshagent ask` when: * you want direct terminal prompting * you do not need a room-connected agent identity * you do not need chat, queue, mail, or toolkit channels Use `meshagent process` when: * the agent should stay available in a room * the agent should accept chat, queue, mail, or toolkit work * the workflow needs persisted room and thread behavior ## Related docs * [Use Codex and Claude with MeshAgent](./use_codex_claude) * [Local CLI Proxy](./local_cli_proxy) * [MeshAgent LLM Proxy](./llm_proxy) * [Process Agents](../process/overview) # MeshAgent LLM Proxy Source: https://docs.meshagent.com/agents/routing/llm_proxy Centralize provider setup, usage, billing, and budget controls for OpenAI- and Anthropic-compatible traffic routed through MeshAgent. The MeshAgent LLM Proxy is an HTTP proxy that lets OpenAI- and Anthropic-compatible clients send requests through MeshAgent. Instead of pointing your app, SDK, or framework directly at OpenAI or Anthropic, you point it at MeshAgent. MeshAgent authenticates the request, applies project-level routing, sends the request to the selected provider, and records usage against the right project and user. With the LLM Proxy you can: * Manage provider configuration centrally at the project level in MeshAgent. * Track usage, billing, and budget controls across tools and team members in one place. * Use the same integration pattern for raw HTTP requests, official SDKs, and higher-level frameworks. ## Before you start MeshAgent provides managed OpenAI and Anthropic access by default. To use your own provider credentials, configure them per project in [MeshAgent Studio](https://studio.meshagent.com) under [Integrations](../../project_admin/integrations). For localhost URLs and temporary local credentials on your machine, use the [Local CLI Proxy](./local_cli_proxy). For [Codex or Claude](./use_codex_claude), `meshagent setup` can configure them to use MeshAgent directly. To inspect your own LLM usage for the current project, open the **LLM Proxy** page in [MeshAgent Studio](../../interfaces/meshagent_studio) and check the **My Usage** tab. To get more information about usage, manage billing, and control which models are allowed, use [MeshAgent Accounts](https://accounts.meshagent.com). ## How it works 1. Your client sends a normal OpenAI-compatible or Anthropic-compatible request to MeshAgent. 2. Your client authenticates with a MeshAgent participant token, API key, or OAuth access token. 3. MeshAgent validates the provider path and model, then forwards the request. 4. MeshAgent returns the provider-compatible response and records usage for the project resolved from the credential. This is the same route used by `meshagent ask` and the [MeshAgent Codex and Claude](./use_codex_claude) integrations. ## How to use the LLM Proxy `meshagent room connect` runs a local command with the same environment variables it will have in a MeshAgent room. It connects to the room, starts your local command, and sets `MESHAGENT_TOKEN` to a participant token with access to that room. It also sets `OPENAI_BASE_URL`, `OPENAI_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_API_KEY`, `MESHAGENT_PROJECT_ID`, and `MESHAGENT_ROOM`. Use those environment variables directly. Do not hardcode the proxy address in local code; let `meshagent room connect` provide the OpenAI and Anthropic base URLs and credentials. ### Connect a local command to a room ```bash theme={null} meshagent setup meshagent project list meshagent project activate PROJECT_ID # optional: switch the active project ``` `meshagent setup` signs you in and stores an OAuth session locally. `meshagent project list` shows the projects you can use and their IDs. The current project is marked with `*`. Use `meshagent project activate PROJECT_ID` to switch projects first. Then run your local command through `meshagent room connect`: ```bash theme={null} meshagent room connect --room=my-room --identity=sample-participant -- ``` The signed-in user must have permission to connect to the room and use the LLM proxy for the selected project. When `--identity` is set, `meshagent room connect` mints the participant token locally using the active API key for the selected project. See [API Keys](../../project_admin/api_keys) for the CLI commands used to create, activate, rotate, and remove project API keys. ### Make a Raw HTTP Request #### Send an OpenAI-compatible request ```bash theme={null} meshagent room connect --room=my-room --identity=sample-participant -- bash -c ' curl "$OPENAI_BASE_URL/responses" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ --data @- ' <<'JSON' { "model": "gpt-5.4", "input": "Tell me a fun fact about AI." } JSON ``` #### Anthropic-compatible request ```bash theme={null} meshagent room connect --room=my-room --identity=sample-participant -- bash -c ' curl "$ANTHROPIC_BASE_URL/v1/messages" \ -H "Authorization: Bearer $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ --data @- ' <<'JSON' { "model": "claude-sonnet-4-6", "max_tokens": 512, "messages": [ {"role": "user", "content": "Tell me a fun fact about AI."} ] } JSON ``` For Anthropic-compatible raw HTTP requests, append `/v1` to the `ANTHROPIC_BASE_URL` value that `meshagent room connect` provides. The Anthropic SDK examples below use `ANTHROPIC_BASE_URL` as-is. ### Use The OpenAI And Anthropic SDKs Run these examples through `meshagent room connect` so the SDKs receive the MeshAgent base URLs and participant token API keys. #### OpenAI SDK ```python Python theme={null} # meshagent room connect --room=my-room --identity=sample-participant -- python3 llm-proxy-openai-sdk.py import os from openai import OpenAI client = OpenAI( base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) response = client.responses.create( model="gpt-5.4", input="Tell me a fun fact about AI.", ) print(response.output_text) ``` ```typescript TypeScript theme={null} // meshagent room connect --room=my-room --identity=sample-participant -- npx tsx llm-proxy-openai-sdk.ts import OpenAI from "openai"; async function main() { const client = new OpenAI({ baseURL: process.env.OPENAI_BASE_URL!, apiKey: process.env.OPENAI_API_KEY!, }); const response = await client.responses.create({ model: "gpt-5.4", input: "Tell me a fun fact about AI.", }); console.log(response.output_text); } void main(); ``` #### Anthropic SDK ```python Python theme={null} # meshagent room connect --room=my-room --identity=sample-participant -- python3 llm-proxy-anthropic-sdk.py import os from anthropic import Anthropic client = Anthropic( base_url=os.environ["ANTHROPIC_BASE_URL"], api_key=os.environ["ANTHROPIC_API_KEY"], ) message = client.messages.create( model="claude-sonnet-4-6", max_tokens=512, messages=[ { "role": "user", "content": "Tell me a fun fact about AI.", } ], ) print(message.content[0].text) ``` ```typescript TypeScript theme={null} // meshagent room connect --room=my-room --identity=sample-participant -- npx tsx llm-proxy-anthropic-sdk.ts import Anthropic from "@anthropic-ai/sdk"; async function main() { const client = new Anthropic({ baseURL: process.env.ANTHROPIC_BASE_URL!, apiKey: process.env.ANTHROPIC_API_KEY!, }); const message = await client.messages.create({ model: "claude-sonnet-4-6", max_tokens: 512, messages: [ { role: "user", content: "Tell me a fun fact about AI.", }, ], }); console.log(message.content[0]); } void main(); ``` ### Use Other Frameworks Configure OpenAI- or Anthropic-compatible frameworks with the MeshAgent base URL and a MeshAgent credential: a participant token, API key, or OAuth access token. For local testing, `meshagent room connect` supplies the MeshAgent base URLs and participant token as environment variables. For OpenAI-compatible transports: * Set the base URL from `OPENAI_BASE_URL` * Set the API key from `OPENAI_API_KEY` For Anthropic-compatible transports: * Set the base URL from `ANTHROPIC_BASE_URL` for Anthropic SDKs * Set the base URL to `$ANTHROPIC_BASE_URL/v1` for raw HTTP transports * Set the API key or bearer token from `ANTHROPIC_API_KEY` For example, LangChain can use the OpenAI-compatible route directly: ```python Python theme={null} # meshagent room connect --room=my-room --identity=sample-participant -- python3 llm-proxy-langchain.py import os from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-5.4", base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) result = llm.invoke("Tell me a fun fact about AI.") print(result.content) ``` For frameworks or local tools that require localhost provider endpoints, use [Local CLI Proxy](./local_cli_proxy). The local proxy gives you temporary localhost OpenAI and Anthropic endpoints that forward through MeshAgent while the `meshagent llm proxy` process is running. ### Use OAuth Credentials Directly A client that authenticates using OAuth, such as the MeshAgent CLI, can call the proxy with OAuth credentials directly. OAuth proxy requests do not require a room to be running. Because they are not authenticated with a room participant token, cost is attributed to the selected project and user, not to a room in the usage dashboards. OAuth clients can access multiple projects, so OAuth proxy requests must include `Meshagent-Project-Id` to choose the project for routing and usage. The OAuth token must include the `llm:invoke` scope, and the user must have direct LLM proxy access enabled in the [MeshAgent Accounts](https://accounts.meshagent.com) account management console. ```bash theme={null} export MESHAGENT_ACCESS_TOKEN="$(meshagent auth token)" export MESHAGENT_PROJECT_ID= curl "https://api.meshagent.com/openai/v1/responses" \ -H "Authorization: Bearer $MESHAGENT_ACCESS_TOKEN" \ -H "Meshagent-Project-Id: $MESHAGENT_PROJECT_ID" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.4", "input": "Tell me a fun fact about AI." }' ``` ### Log proxy traffic to a feed Use `meshagent llm logger` to manage project loggers that copy matching LLM proxy events into a destination feed. Create the destination feed first, then create a logger with a JMESPath metadata filter: ```bash bash theme={null} meshagent feed create \ --name llm-proxy-logs \ --description "LLM proxy request and response events" # Use the returned feed id as FEED_ID. meshagent llm logger create \ --feed-id FEED_ID \ --filter-expression '`true`' ``` Use `meshagent llm logger list`, `meshagent llm logger get LOGGER_ID`, `meshagent llm logger update LOGGER_ID`, and `meshagent llm logger delete LOGGER_ID` to manage existing loggers. ## Authentication Notes * `meshagent room connect` sets `MESHAGENT_TOKEN`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` to a participant token with access to the room. * The participant token must carry the room grant and LLM API grant. * The signed-in user must have permission to connect to the room and use the LLM proxy for that project. * Provider base URLs use the project API endpoint: `${MESHAGENT_API_URL}/openai/v1` for OpenAI-compatible requests and `${MESHAGENT_API_URL}/anthropic` for Anthropic SDK requests. * OAuth proxy requests require an access token with the `llm:invoke` scope and `Meshagent-Project-Id`. ## Supported Provider Paths MeshAgent exposes these provider-compatible paths. MeshAgent proxies both OpenAI and Anthropic endpoints. ### OpenAI-Compatible * `/v1/chat/completions` * `/v1/responses` * `/v1/responses/compact` * `/v1/responses/input_tokens` * `/v1/embeddings` * `/v1/audio/speech` * `/v1/audio/transcriptions` * `/v1/audio/translations` * `/v1/models` and `/v1/models/*` * `/v1/images/*` * `/v1/realtime` and `/v1/realtime/*` Supported OpenAI websocket paths are: * `/v1/realtime` * `/v1/responses` ### Anthropic-Compatible * `/v1/messages` * `/v1/messages/count_tokens` * `/v1/messages/batches*` * `/v1/complete` * `/v1/models` and `/v1/models/*` ## Related Docs * [Local CLI Proxy](./local_cli_proxy) * [Use Codex and Claude with MeshAgent](./use_codex_claude) * [Ask MeshAgent from the CLI](./ask_meshagent_cli) * [OAuth Clients](../../project_admin/oauth) * [Billing and Usage](../../project_admin/billing) # Local CLI Proxy Source: https://docs.meshagent.com/agents/routing/local_cli_proxy Run meshagent llm proxy when a local SDK, framework, or tool expects localhost base URLs and temporary local keys. `meshagent llm proxy` starts a local proxy server on your machine. It exposes temporary OpenAI-compatible and Anthropic-compatible localhost endpoints that forward requests to the hosted [MeshAgent LLM Proxy](./llm_proxy), so usage is still routed through your MeshAgent project and user. The local endpoints and keys only work while the command is running, and by default the terminal shows live usage as requests come through. Use it for local tools that are easiest to configure as if they were talking to OpenAI or Anthropic directly or can't send custom headers like `Meshagent-Project-Id`. For Codex or Claude, use [Use Codex and Claude with MeshAgent](./use_codex_claude). `meshagent setup` can configure those tools directly against the hosted MeshAgent endpoints. ## Start the local proxy Run `meshagent setup` once to authenticate with MeshAgent and select a project, then start the local proxy: ```bash theme={null} meshagent llm proxy ``` By default the local proxy listens on: * `http://127.0.0.1:8766/openai/v1` for OpenAI-compatible clients * `http://127.0.0.1:8766/anthropic` for Anthropic-compatible clients When it starts, it prints the local settings your tool should use: ```bash theme={null} export OPENAI_BASE_URL=http://127.0.0.1:8766/openai/v1 export OPENAI_API_KEY=... export ANTHROPIC_BASE_URL=http://127.0.0.1:8766/anthropic export ANTHROPIC_API_KEY=... ``` The printed API keys authenticate requests to the local proxy only. The proxy separately uses your MeshAgent CLI session to forward requests upstream through MeshAgent. By default, the terminal running `meshagent llm proxy` shows live usage by model and recent request activity as traffic passes through the proxy. ## How It Works * Your tool sends requests to the localhost OpenAI-compatible or Anthropic-compatible URL printed by `meshagent llm proxy`. * The local proxy authenticates that request with the temporary local proxy key it printed for the session. * The local proxy then forwards the request to the hosted MeshAgent LLM Proxy using your active MeshAgent project and an upstream MeshAgent token from your CLI session or `MESHAGENT_TOKEN`. * MeshAgent handles the real project-level routing, usage attribution, billing, and provider credentials. ## Use the Local Proxy ### OpenAI-compatible `curl` request ```bash theme={null} curl "$OPENAI_BASE_URL/responses" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.4", "input": "Tell me a fun fact about AI." }' ``` ### Anthropic-compatible `curl` request ```bash theme={null} curl "$ANTHROPIC_BASE_URL/v1/messages" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "max_tokens": 512, "messages": [ {"role": "user", "content": "Tell me a fun fact about AI."} ] }' ``` ### OpenAI SDK examples ```python Python theme={null} import os from openai import OpenAI client = OpenAI( base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) response = client.responses.create( model="gpt-5.4", input="Tell me a fun fact about AI.", ) print(response.output_text) ``` ```typescript TypeScript theme={null} import OpenAI from "openai"; async function main() { const client = new OpenAI({ baseURL: process.env.OPENAI_BASE_URL, apiKey: process.env.OPENAI_API_KEY, }); const response = await client.responses.create({ model: "gpt-5.4", input: "Tell me a fun fact about AI.", }); console.log(response.output_text); } void main(); ``` ### Anthropic SDK examples ```python Python theme={null} import os from anthropic import Anthropic client = Anthropic( base_url=os.environ["ANTHROPIC_BASE_URL"], api_key=os.environ["ANTHROPIC_API_KEY"], ) message = client.messages.create( model="claude-sonnet-4-6", max_tokens=512, messages=[ { "role": "user", "content": "Tell me a fun fact about AI.", } ], ) print(message.content[0].text) ``` ```typescript TypeScript theme={null} import Anthropic from "@anthropic-ai/sdk"; async function main() { const client = new Anthropic({ baseURL: process.env.ANTHROPIC_BASE_URL, apiKey: process.env.ANTHROPIC_API_KEY, }); const message = await client.messages.create({ model: "claude-sonnet-4-6", max_tokens: 512, messages: [ { role: "user", content: "Tell me a fun fact about AI.", }, ], }); console.log(message.content[0]); } void main(); ``` ### Using Agent Frameworks with the local proxy Any framework that lets you override an OpenAI or Anthropic compatible base URL and API key can use the local proxy. For example, with LangChain: ```python Python theme={null} import os from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-5.4", base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) result = llm.invoke("Tell me a fun fact about AI.") print(result.content) ``` If your framework can send MeshAgent authentication and project headers directly, you can also use the hosted [MeshAgent LLM Proxy](./llm_proxy). Use the local proxy when you want the framework to talk to a local provider-compatible endpoint during development. ## When to use the local proxy vs the hosted proxy The local proxy is a local adapter on top of the hosted MeshAgent LLM Proxy. Requests still route through MeshAgent and use the active MeshAgent project. Use the hosted proxy when your app, service, SDK, or framework can call MeshAgent directly with a MeshAgent OAuth token and `Meshagent-Project-Id`. Use the local proxy when you're working with a tool on your machine that's easiest to configure with provider-style base URLs and API keys. It's especially useful when the tool can't reliably send custom headers like `Meshagent-Project-Id`, when you'd rather use local proxy keys than a MeshAgent OAuth token, or when you want live usage visible in your terminal as requests come through. ## Advanced options The local proxy signs upstream MeshAgent requests with: * `MESHAGENT_TOKEN`, if it is set * otherwise your current MeshAgent CLI auth session You can override that behavior: * `--host ` to choose the local bind host * `--port ` to choose the local bind port * `--project-id ` to bypass the active project * `--token-from-env ` to forward a different MeshAgent token env var upstream * `--bearer ` to set the local bearer token explicitly * `--insecure` to disable local bearer-token enforcement * `--no-tui` to skip the live usage dashboard If you do not pass `--bearer` or `--insecure`, MeshAgent reuses a stored local bearer token or generates one on first run. That local bearer token protects the localhost proxy only. It is separate from the upstream MeshAgent credential used to talk to the hosted proxy. ## Related docs * [MeshAgent LLM Proxy](./llm_proxy) * [Use Codex and Claude with MeshAgent](./use_codex_claude) * [Ask MeshAgent from the CLI](./ask_meshagent_cli) # Use Codex and Claude with MeshAgent Source: https://docs.meshagent.com/agents/routing/use_codex_claude Configure Codex and Claude to use MeshAgent-managed routing. MeshAgent can configure Codex CLI, Codex Desktop, and Claude Code to route through the hosted [MeshAgent LLM Proxy](./llm_proxy) automatically, giving you project-level routing, usage tracking, billing, and budget controls instead of sending model traffic directly to OpenAI or Anthropic. Claude Desktop support is coming soon. By default, MeshAgent provides managed OpenAI and Anthropic access. To use your own provider credentials, configure them per project in [Integrations](../../project_admin/integrations). MeshAgent supports two workflows: * `meshagent setup`: Can be used to configure Codex or Claude to use MeshAgent by default, best when you want persistent local configuration changes. * `meshagent launch codex` or `meshagent launch claude`: For when you want a one-off session through MeshAgent without changing your normal default configuration. ## `meshagent setup` Start with: ```bash theme={null} meshagent setup ``` `meshagent setup` is the guided, persistent setup flow. It can: * Sign you in or reuse your existing session. * Let you choose or create a project and activate it. * Create and activate a project API key if needed. * Check whether your account can use the LLM Proxy for that project. * Offer to configure supported Codex or Claude installations found on your machine. If your account does not have LLM Proxy access for the selected project, setup tells you and stops before trying to configure the local tool integrations. ### What `meshagent setup` changes for Codex For Codex, setup can configure, update, or remove MeshAgent as the default provider in `~/.codex/config.toml`. After setup: * Run `codex` normally to use Codex through the active MeshAgent project. * Rerun `meshagent setup` to update the MeshAgent Codex default or reset Codex back to OpenAI. ### What `meshagent setup` changes for Claude For Claude, setup can create, update, or remove MeshAgent-managed settings in `~/.claude/settings.json`. After that, run `claude` normally and it uses the configured MeshAgent project. ## `meshagent launch` commands Use these commands for a one-off Codex or Claude session through MeshAgent. They work whether or not MeshAgent is configured as your default. ```bash theme={null} meshagent launch codex meshagent launch claude ``` These commands do not make MeshAgent your permanent default. * `meshagent launch codex` launches `codex` with temporary Meshagent settings and environment for that process. * `meshagent launch claude` launches `claude` with temporary MeshAgent settings and environment for that process. Both commands use the active MeshAgent project by default. To target a different project for that launch, pass `--project-id` before any forwarded tool arguments. ### Forwarding tool arguments `meshagent launch codex` and `meshagent launch claude` have their own MeshAgent options: * `--project-id` * `--api-url` If you want to pass options through to Codex or Claude, put them after `--`. For example: ```bash theme={null} meshagent launch codex -- app meshagent launch codex --project-id PROJECT_ID -- --search "how do agents work?" ``` For Codex, `app` is a forwarded Codex subcommand that can be used to launch the Codex Desktop app. ### Desktop apps Codex Desktop is supported today through the same Codex configuration that `meshagent setup` manages. To launch Codex Desktop through MeshAgent for a one-off session, use: ```bash theme={null} meshagent launch codex -- app ``` If you want Codex Desktop to use MeshAgent automatically when you open it normally, make MeshAgent the Codex default during `meshagent setup`. Claude Desktop automatic support is coming soon, so this page does not document a Claude Desktop launch command yet. ## Switch Back To Your Regular Provider Setup If you only used `meshagent launch codex` or `meshagent launch claude`, there is nothing to undo. Those commands only affect that launch. If you changed persistent local configuration: * For Codex, rerun `meshagent setup` and choose the option to remove the MeshAgent Codex configuration. This resets Codex to OpenAI as the default provider. * For Claude, rerun `meshagent setup` and choose the option to remove the MeshAgent Claude configuration. If you install Codex or Claude after running setup, rerun `meshagent setup` so MeshAgent can detect and configure them. ## Related docs * [MeshAgent LLM Proxy](./llm_proxy) * [Local CLI Proxy](./local_cli_proxy) * [Ask MeshAgent from the CLI](./ask_meshagent_cli) * [MeshAgent CLI Commands](../../reference/meshagent_cli_help) # VoiceBot Source: https://docs.meshagent.com/agents/standard/voicebot ## Overview `VoiceBot` is the standard agent for building real-time, speech-based conversational experiences in MeshAgent. It builds on the Python `SingleRoomAgent` base class from [`meshagent-agents`](../../reference/python_package_overview) and adds streaming audio input/output, LiveKit session management, speech recognition, and natural voice responses. A `VoiceBot` joins a MeshAgent room, listens for `voice_call` messages, connects to a LiveKit breakout room where it can speak and listen to participants in real-time. It combines speech-to-text (STT), text-to-speech (TTS), voice activity detection (VAD), LLM reasoning, and tool calling automatically. The MeshAgent CLI is the recommended way to run and deploy VoiceBots. Configure speech, tools, and rules with CLI flags, then deploy the same command when you want the agent to stay available in a room. ### In this guide you will learn 1. When to use `VoiceBot` 2. How to run and deploy a `VoiceBot` with the MeshAgent CLI 3. How `VoiceBot` works, including lifecycle, voice sessions, conversation flow, hooks, and methods ## When to use VoiceBot Use the `VoiceBot` when you need an agent that: * **Talks and listens in real time** using speech * **Manages live voice sessions** automatically via LiveKit * **Runs LLM reasoning and tools** during spoken interaction * **Supports natural interruptions and turn-taking** * **Feels like a phone call or meeting assistant**, instead of using a text based chat. If your agent only handles text-based chat, background work, mail, queues, or toolkit entry points, use the [process runtime](../process/overview). ## Run and deploy a VoiceBot with the CLI ### Step 1: Run a `VoiceBot` from the CLI Let's run a `VoiceBot` from the CLI with a custom rule and shared rules that can be edited by anyone in the room. The room rules can be modified per conversation turn while the base rule will be applied to the entire conversation. ```bash bash theme={null} # Authenticate to MeshAgent if not already signed in meshagent setup # Call a voicebot into your room meshagent voicebot join --room quickstart --agent-name voiceagent --room-rules "agents/voiceagent/rules.md" --rule "You are a helpful assistant" ``` When you add the `--room-rules "agents/voiceagent/rules.md"` flag and supply a file path for the rules, the file will be created if it does not already exist, this file is relative to the room storage. ### Step 2: Interact with the agent in MeshAgent Studio 1. Go to [MeshAgent Studio](https://www.studio.meshagent.com) and log in 2. Enter your room `quickstart` 3. Select the agent `voiceagent` and begin speaking! If you've added the `--room-rules` flag to your agent you can modify the agent's `rules.md` file to refine the agent's behavior. Changes to the `rules.md` will be applied per message. > **Tip**: Mute your microphone after you finish speaking to prevent background noise from interfering with the agent. ### Step 3: Package and deploy the agent Once your agent works locally to make it always available you'll need to [package and deploy](../../services/deployment/deploy_services) it as a project or room service. You can do this using the CLI, by creating a YAML file, or from MeshAgent Studio. **Both options below deploy the same VoiceBot** - choose based on your workflow: * **Option 1 (`meshagent voicebot deploy`)**: One command that deploys immediately (fastest/easiest approach) * **Option 2 (`meshagent voicebot spec` + `meshagent service create`)**: Generates a yaml file you can review, or further customize before deploying **Option 1: Deploy directly** Use the CLI to automatically deploy the `VoiceBot` to your room. ```bash bash theme={null} meshagent voicebot deploy --service-name voiceagent --room quickstart --agent-name voiceagent --room-rules "agents/voiceagent/rules.md" --rule "You are a helpful assistant" ``` **Option 2: Generate a YAML spec** Create a `meshagent.yaml` file that defines how our service should run, then deploy the agent to our room. The service spec can be dynamically generated from the CLI by running: ```bash bash theme={null} meshagent voicebot spec --service-name voiceagent --agent-name voiceagent --room-rules "agents/voiceagent/rules.md" --rule "You are a helpful assistant" ``` Next, copy the output to a `meshagent.yaml` file ```yaml Yaml theme={null} kind: Service # switch to service Template if installing from link for Powerboards version: v1 metadata: name: voiceagent description: "An agent that responds using voice" annotations: meshagent.service.id: "meshagent.voiceagent" agents: - name: voiceagent description: "A voice agent" annotations: meshagent.agent.type: "VoiceBot" container: image: "us-central1-docker.pkg.dev/meshagent-public/images/cli:latest" command: "/usr/bin/meshagent voicebot join --agent-name=voiceagent --room-rules='agents/voiceagent/rules.md'" environment: - name: MESHAGENT_TOKEN token: identity: voiceagent role: agent ``` Then, deploy it to your Room. ```bash bash theme={null} # Deploy as a room service (specific room only) meshagent service create --file meshagent.yaml --room quickstart ``` The `VoiceBot` is now deployed to the `quickstart` room! Now the agent will always be available inside the room for us to chat with. You can interact with the agent directly from the Studio or from [Powerboards](https://www.powerboards.com/). With Powerboards you can easily share your agents with others or use built in agents. ## How VoiceBot Works ### Constructor Parameters The CLI configures the underlying Python `VoiceBot` class. If you extend that class directly, it accepts the current `SingleRoomAgent` base options and adds voice-specific configuration options. | Parameter | Type | Description | | -------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------- | | `name` | `str \| None` | Optional explicit participant name. Most CLI and deployment flows set the participant identity outside the class. | | `title` | `str \| None` | Human-friendly name for clients, logs, and operator surfaces. | | `description` | `str \| None` | Short description of what the voice agent does. | | `annotations` | `list[str] \| None` | Optional string metadata for clients and services that inspect the agent. | | `voice` | `str` | OpenAI Realtime voice name. Defaults to `"echo"`. | | `rules` | `list[str] \| None` | System or behavior rules sent to the LLM. Defaults to `["You are a helpful assistant communicating through voice."]`. | | `auto_greet_message` | `str \| None` | Optional message spoken to the participant when the session starts. | | `auto_greet_prompt` | `str \| None` | Optional text prompt that seeds the first LLM response at session start. | | `tool_adapter` | `ToolResponseAdapter \| None` | Optional adapter that converts tool responses into plain speech. | | `toolkits` | `list[Toolkit] \| None` | Additional Toolkits to expose beyond `requires`; pass instantiated toolkits you want available to the LLM. | | `requires` | `list[Requirement] \| None` | Toolkits or schemas needed before running (e.g., for tool access or shared data). | | `client_rules` | `dict[str, list[str]] \| None` | Optional map keyed by the participant's `client` attribute that appends extra rules when matched. | ### Lifecycle Overview `VoiceBot` inherits all lifecycle hooks from `SingleRoomAgent` and adds voice session handling on top. * `await start(room: RoomClient)`: Registers the bot as a voice-capable participant by setting `"supports_voice": True` and listening for `voice_call` messages. When a voice call is received, the bot joins a LiveKit breakout room and starts a real-time session. * `await stop()`: Clears the room reference. Active voice sessions end when the LiveKit room disconnects (for example, when the caller hangs up). * **room** property: Returns the active `RoomClient` (inherited from `SingleRoomAgent`). ### Conversational Flow When a user starts a voice call: 1. The participant sends a message of type `"voice_call"` with a breakout room ID (and optionally a `transcript_path`). 2. The `VoiceBot` receives it through `on_message()` and joins the corresponding LiveKit room. 3. It creates a `VoiceBotContext` scoped to that participant. 4. A new `AgentSession` is created, containing: * Speech-to-Text (STT) * Text-to-Speech (TTS) * Voice Activity Detection (VAD) * LLM model interface 5. A conversational Agent is built with these components and any registered tools. 6. The bot begins listening, thinking (with background “typing” sounds), and speaking responses in real time. When the participant hangs up or disconnects, the session ends automatically. If `transcript_path` is provided in the `voice_call` message, the session uses a `Transcriber` to log `conversation_item_added` events to that path while running. ### Key Behaviors and Hooks * **Voice connection management:** Each session is isolated in its own LiveKit breakout room. The internal `VoiceConnection` helper handles joining, connecting, and disconnecting from the session safely. * **Session creation:** `create_session()` constructs an AgentSession with STT, TTS, VAD, and LLM components wired to the room’s proxy API. * **Agent creation:** `create_agent()` builds the conversational logic layer that uses the LLM, applies your rules, and exposes tool functions like `say()`. * **Greeting behavior:** When configured, `auto_greet_prompt` triggers the LLM to generate an initial spoken message, and `auto_greet_message` plays a prewritten greeting. * **Tool integration:** Tools are automatically converted into callable functions for the LLM via `make_function_tools()`. Responses are adapted to speech when a `tool_adapter` is provided. * **Transcript logging:** When a `transcript_path` is supplied, `create_agent()` returns a `Transcriber` that logs conversation items to that location. * **Lifecycle hooks:** Override `on_session_created()`, `on_session_started()`, or `on_session_ended()` to add custom logic around the session lifecycle. * **Interruptions and natural flow:** Sessions allow interruption mid-speech and handle turn-taking automatically through VAD. ### Key Methods | Method | Description | | ------------------------------------------------------- | ---------------------------------------------------------------------------- | | `async def start(room)` | Registers the bot for voice calls and listens for `voice_call` messages. | | `async def run_voice_agent(participant, breakout_room)` | Connects to the specified LiveKit room and starts a full voice session. | | `async def create_session(context)` | Creates a new `AgentSession` wired with STT, TTS, VAD, and LLM capabilities. | | `async def create_agent(context, session)` | Builds a conversational agent with your rules and available tools. | | `async def make_function_tools(context)` | Converts all registered toolkits into LLM-callable functions. | | `async def _wait_for_disconnect(room)` | Awaits the end of the voice call and cleans up resources. | | `async def on_session_created(context, session)` | Hook called after an AgentSession is constructed but before it starts. | | `async def on_session_started(context, session)` | Hook called immediately after the session starts. | | `async def on_session_ended(context, session)` | Hook called after the session ends. | ### Built-in Components and Behavior VoiceBot comes pre-integrated with: * **Speech-to-Text (STT):** Converts live audio input into text using OpenAI STT via the room's proxied client (override `create_session` to swap providers). * **Text-to-Speech (TTS):** Streams generated responses as natural audio output using OpenAI TTS. * **Voice Activity Detection (VAD):** Detects pauses or user interruptions automatically (Silero VAD). * **Room I/O defaults:** Text input is disabled; audio output and transcription are enabled for the LiveKit room session. * **Background Audio Player:** Plays gentle “thinking” keyboard sounds during LLM processing to indicate the bot is working. * **Tool Invocation:** Voice commands can trigger registered tools and return spoken responses. These components can be swapped or extended through adapters if you need different models or behaviors. ## Next Steps `VoiceBot` builds directly on `SingleRoomAgent`, inheriting connection management and toolkit installation, and extends it with real-time audio and speech features. Where process-backed agents focus on text and background channels, `VoiceBot` handles spoken conversations end-to-end. Discover other agents in MeshAgent: * [Process Agents Overview](../process/overview): Text-based and multi-channel process-backed agents. * [Agents Overview](../overview): How agents, channels, threads, and tools fit together. To learn more about deploying agents with MeshAgent * [Service YAML](../../services/deployment/deploy_services): write service manifests for voice agents. * [Secrets and Credentials](../../secrets/overview): Learn how to store credentials securely for deployment # Threads Overview Source: https://docs.meshagent.com/agents/threads_overview ## What is a thread? A **thread** is the persisted conversation or work history an agent can use to continue from where it left off. In MeshAgent, a thread is addressed by a thread path and stored by the agent's configured thread storage backend. Process agents store thread history in the room dataset; the legacy MeshDocument-backed thread storage path is no longer supported. A thread is the durable state behind things like: * an ongoing conversation with a process-backed agent * a resumable process-backed toolkit workflow * queue or mail work history you want to keep and revisit The main idea is: * **Session/context** is the in-memory state for the current run * **Thread** is the persisted state that future runs can reload If you want continuity across turns, runs, or agents, you usually need a thread. ## Threads vs rooms, sessions, tools, and skills These concepts work together, but they are not the same: * **Room**: the shared collaboration environment where people, agents, files, tools, and documents live * **Session/context**: the current in-memory LLM conversation state for one run * **Thread**: the persisted transcript or work log that an agent session can resume from * **Tool**: a callable capability such as storage, shell, or web search * **Skill**: reusable guidance that helps an agent decide how to approach a task The key distinction is: * **Sessions are live** * **Threads persist** An agent may create a fresh session every time it runs, but still choose to reload that session from an existing thread. ## What lives in a thread? A MeshAgent thread can store more than plain chat text. A thread can contain: * user and assistant messages * file attachments * tool and command output * reasoning summaries * UI events * generated images and related status That makes a thread useful as both: * a memory source for future agent runs * a durable audit trail of what happened ## Do all agents use threads? Different agents use threads in different ways. ### Process-backed chat agents For a process-backed agent with a `chat` channel, threads are the normal model. A chat conversation is typically backed by a thread path, and the agent reopens that thread to reload prior history and continue the conversation. If a chat UI supports multiple conversations, each conversation is usually a different thread. ### Toolkit-style process calls A toolkit-style process invocation does **not** have to use threads, but it can. If the same invocation flow reuses a thread path, the agent can continue from that persisted history later. Use this when you want a callable agent workflow to be resumable or inspectable over time. ### Queue-backed process work Queue-backed process work also does **not** have to use threads. A queue channel can process jobs with fresh context each time, or it can write the work into thread storage so jobs have durable history. Use this when queued work should leave behind a readable log, or when later work should build on earlier work. ### Process-backed agents Process-backed agents also use threads, but the boundary is still the thread path rather than the overall process. In practice, that means: * one `meshagent process` runtime can accept turns from chat, mail, queues, or toolkit calls * each turn is still routed by its resolved thread path * context is only shared when those inputs reuse the same thread path So a process-backed agent can have one runtime and still keep unrelated work separate. ## When should I think about threads? You should think about threads when you want: * conversations to continue across turns or sessions * a user or agent to reopen earlier work * multiple runs to build on the same history * an auditable record of tool use, outputs, or reasoning * multiple agents to collaborate through shared persisted state You usually do **not** need to think much about threads when: * every run should start fresh * the output is purely one-shot * there is no need to reopen or inspect the history later ## Shared threads Agents can share threads. This is not a separate special feature or agent mode. It simply means that multiple agents or clients read from and write to the same thread path. That is useful when: * a conversational agent and a background agent should collaborate on the same work * one agent creates work and another agent continues it * you want a user-facing conversation and background processing to stay in one shared history The important rule is: * **same thread path = same persisted history** If two agents use different thread paths, they have different histories even if they are working in the same Room. ## What is a thread directory? A **thread directory** is a path prefix used to organize many thread paths together. For example: ```text theme={null} .threads/support-bot/ ``` A thread directory typically contains: * one thread path per conversation or work item * one thread list path that lists the known threads Example: ```text theme={null} dataset://.threads/support-bot/ 2d8b6f0e-0c9a-4f50-8e1c-2d83d6a64d4f 660ef9d1-c70c-46e6-b309-4fe2b8c73b90 index ``` ## Example: process chat channel with thread-related CLI flags Here is a simple `meshagent process` command that enables a thread-aware chat UI and stores its thread history under a dedicated thread directory: ```bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name support-bot \ --channel chat \ --threading-mode default-new \ --thread-dir ".threads/support-bot" \ --storage \ --room-rules "agents/support-bot/rules.md" \ --rule "You are a helpful support assistant." ``` The thread-related flags here are: * `--threading-mode default-new`: tells chat UIs to treat this agent as thread-oriented and to show a new-thread composer before loading an existing thread * `--thread-dir ".threads/support-bot"`: tells the agent where its thread history and thread list should live With the default dataset-backed thread storage, MeshAgent normalizes that directory into dataset-backed thread paths like: ```text theme={null} dataset://.threads/support-bot/ index ``` When you write a process-agent YAML file directly, use the explicit dataset-backed annotations that `meshagent process spec` emits: ```yaml theme={null} annotations: meshagent.agent.type: ChatBot meshagent.chatbot.threading: default-new meshagent.chatbot.thread-dir: dataset://.threads/support-bot meshagent.chatbot.thread-list: dataset://.threads/support-bot/index ``` `meshagent.chatbot.thread-list` can be derived by MeshAgent clients when `thread-dir` is present, which is why some built-in service templates only set `meshagent.chatbot.thread-dir`. Public examples should include both values so the YAML is self-contained and matches generated process-agent specs. This is a good default when: * one chatbot should support many separate conversations * you want a UI to show a thread list * you want to keep this agent's threads separate from other agents in the same Room If you omit `--thread-dir`, the chat-oriented process runtime will choose a default thread directory for you. If you omit thread-related settings entirely, you can still chat with the agent, but you are no longer explicitly configuring thread list behavior or thread organization. ## What is the thread list? The thread list is the index for a thread directory. It is not the source of truth for the thread contents. Each thread path holds the actual history. The index exists so UIs and agents can: * list available threads * sort them by recent activity * show readable names * open a thread by path In other words: * a thread path stores the conversation or work itself * the thread list stores the list of known threads ## How UIs use threads Many chat-style UIs need two things: 1. a thread list 2. a selected thread path The thread list usually comes from the thread directory's index path, and the selected conversation comes from a specific thread path. This is why thread directories matter most for process-backed agents with a chat channel: they let a UI show many conversations instead of only one. ## Choosing the right model Use one of these mental models: * **No thread**: best for isolated, one-off work * **One thread per user/agent pair**: best for simple persistent chat * **One thread per task or case**: best for work that evolves over time * **One shared thread across agents**: best for collaboration on the same persisted history * **A thread directory with many threads**: best for multi-conversation chat UIs ## Where to go next * [Process Agents Overview](./process/overview): the main thread-aware runtime for new CLI agents * [Key Concepts](../introduction/introduction): Rooms, agents, tools, and services # Built-in MeshAgent Toolkits Source: https://docs.meshagent.com/agents/tools/built_in_toolkits MeshAgent ships built-in tool capabilities that you can add to an agent from the CLI. Some flags map to different underlying tool implementations depending on the model. MeshAgent keeps the CLI surface stable so the same flag can work across OpenAI- and Anthropic-backed agents when the capability exists on both. This matters most for flags such as `--web-search`, `--web-fetch`, and `--shell`. You choose the capability once, and MeshAgent selects the provider-specific tool path that matches the model you are running. ## Add built-in capabilities from the CLI ```bash theme={null} meshagent process join \ --room my-room \ --agent-name researcher \ --channel chat \ --model gpt-5.4 \ --web-search \ --mcp \ --storage \ --use-memory agents/researcher/memories ``` This command starts an agent that can use web search, MCP tools, storage, and room-backed memory tools. Most built-in capabilities now use one canonical CLI flag, such as `--web-search`, `--storage`, `--shell`, or `--document-authoring`. `--require-toolkit` is the exception for attaching an external toolkit by name. The tables below show the current CLI flags for each built-in capability. Run `meshagent process join --help` to see the current tool flags and related configuration options. ## Built-in capabilities ### Web and retrieval | Capability | Toolkit or tool | Flags | What it does | | ---------- | --------------- | -------------- | --------------------------------- | | Web search | `WebSearchTool` | `--web-search` | Search the web | | Web fetch | `WebFetchTool` | `--web-fetch` | Fetch and read web pages directly | ### Storage and memory | Capability | Toolkit or tool | Flags | What it does | | -------------- | ---------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------- | | Storage | `StorageToolkit` | `--storage`, `--read-only-storage` | Work with room or mounted storage | | Memory | `MemoriesToolkit` | `--use-memory ` | Add, search, inspect, and delete room-backed memories | | Dataset access | `DatasetToolkit`, `make_dataset_toolkit` | `--dataset-namespace`, `--table-read `, `--table-write
` | Add table-specific dataset tools | | UUID tools | `UUIDToolkit` | `--uuid` | Provide UUID generation helpers | | Time tools | `DatetimeToolkit` | `--time` | Provide time and datetime tools | ### MCP and external tools | Capability | Toolkit or tool | Flags | What it does | | ---------- | -------------------------- | ------- | ----------------------------------------------------------------- | | MCP tools | room-provided MCP toolkits | `--mcp` | Use MCP tools available in the room on turns where MCP is enabled | For setup paths such as Powerboards installs, MCP URL auto-discovery, and OpenAI connector manifests, see [MCP Servers](./mcp_servers). In the current `meshagent process` runtime, MCP is exposed through `--mcp` rather than as a required named toolkit. ### Shell and execution | Capability | Toolkit or tool | Flags | What it does | | ----------------------- | ----------------------------------- | ------------------------------------------ | ------------------------------------------------------------- | | Function shell | `ShellTool` or `ContainerShellTool` | `--shell` | Give the agent direct shell tool calling | | Managed container shell | `ContainerToolkit` | `--advanced-shell` | Give the agent container start, list, stop, and run tools | | Script tools | `get_script_tools(...)` | `--script-tool`, `--discover-script-tools` | Add script-based tools or discover script tools from the room | `--advanced-shell` is the right choice when the agent needs to manage a working container across several steps instead of treating each shell command as an isolated call. If the shell environment needs access to runtime metadata from the current room or service, add `--shell-tool-config-mount `. When the current runtime exposes `MESHAGENT_SPEC_PATH` or `MESHAGENT_MEMBERS_PATH`, MeshAgent mounts those runtime files into the shell container as `spec.json` and `members.json` under the target directory and points the env vars at the mounted paths. ### Provider-native tools | Capability | Toolkit or tool | Flags | What it does | | ---------------- | --------------------- | ------------------------------------------------------ | ------------------------------------------ | | Image generation | `ImageGenerationTool` | `--image-generation ` | Use OpenAI-native image generation | | Apply patch | `ApplyPatchTool` | `--apply-patch` | Use OpenAI-native patch editing | | Computer use | `ComputerToolkit` | `--computer-use`, `--starting-url`, `--allow-goto-url` | Use browser and computer-interaction tools | ### Document and content tools | Capability | Toolkit or tool | Flags | What it does | | ----------------------- | ------------------------------ | ---------------------------------- | ---------------------------------------------------------------------- | | Document authoring | `DocumentAuthoringToolkit` | `--document-authoring` | Create and modify MeshDocuments | | Document type authoring | `DocumentTypeAuthoringToolkit` | `--document-authoring` | Add type-specific document tools for the built-in widget document type | | MarkItDown | `MarkItDownToolkit` | no direct `meshagent process` flag | Convert PDFs and Office documents into LLM-friendly formats | ### Discovery | Capability | Toolkit or tool | Flags | What it does | | --------------- | ------------------ | ------------- | ----------------------------------------------- | | Discovery tools | `DiscoveryToolkit` | `--discovery` | Discover agents and tools available in the room | If a built-in capability does not have a direct `meshagent process` flag, add it from the SDK or package it into your own service or custom toolkit. ## Related guides * [How Tools and Toolkits Work](./tools_and_toolkits) * [Create Custom Tools](./quickstart) * [MCP Servers](./mcp_servers) * [Build and Deploy Images](../../services/containers/meshagent_image) # Dynamic Tool Discovery Source: https://docs.meshagent.com/agents/tools/dynamic_tool_discovery Dynamic tool discovery lets an OpenAI-backed `meshagent process` agent use [OpenAI Responses tool search](https://developers.openai.com/api/docs/guides/tools-tool-search#tool-search-types) to choose from toolkits that MeshAgent makes available for a turn. Use this when an agent should not load every possible tool directly into every model request. Tool search gives the model a searchable set of candidate tools and lets it pull in the ones that match the user's request. ## `--require-toolkit` vs `--tool-search` `--require-toolkit` attaches a known toolkit by name. Use it when the agent should always have a specific toolkit available. `--tool-search` changes how available toolkits are exposed to OpenAI Responses models. It does not create or start a toolkit by itself. The toolkit must already come from the agent's configured capabilities or from the room. `--tool-search` supports two modes: | Mode | What the model can search | | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agent` | Toolkits already configured on the process agent, such as built-in capabilities and toolkits added with flags like `--require-toolkit`. This is useful when the agent already knows its candidate toolkits but you do not want every tool schema loaded directly on every request. | | `room` | The agent toolkits from `agent` mode, plus room toolkits annotated with `meshagent.tool_search: "true"`. | `--tool-search` is only supported for OpenAI Responses models. Use a model such as `gpt-5.5`. OpenAI's tool-search guidance makes the same distinction: use tool search over known candidate tools when the candidates are already available at request time, and use client-executed discovery when lookup depends on project, tenant, or other application state. ## Start the example toolkit The examples below use the custom tools quickstart's `tools-adder.py` sample. It exposes `math-toolkit` from a room-connected `SingleRoomAgent`. ```python Python theme={null} import asyncio from meshagent.api import TOOL_SEARCH_ANNOTATION from meshagent.agents import SingleRoomAgent from meshagent.tools import FunctionTool, ToolContext, Toolkit from meshagent.otel import otel_config otel_config(service_name="math_tools") class Add(FunctionTool): def __init__(self): super().__init__( name="add", title="adding tool", description="a tool that adds two numbers", input_schema={ "type": "object", "additionalProperties": False, "required": ["a", "b"], "properties": { "a": {"type": "integer"}, "b": {"type": "integer"}, }, }, ) async def execute(self, context: ToolContext, *, a: int, b: int): result = {"result": a + b} print(result) return result class Subtract(FunctionTool): def __init__(self): super().__init__( name="subtract", title="subtracting tool", description="a tool that subtracts two numbers", input_schema={ "type": "object", "additionalProperties": False, "required": ["a", "b"], "properties": { "a": {"type": "integer"}, "b": {"type": "integer"}, }, }, ) async def execute(self, context: ToolContext, *, a: int, b: int): result = {"result": a - b} print(result) return result class MathToolkit(Toolkit): def __init__(self): super().__init__( name="math-toolkit", title="math-toolkit", description="a toolkit for adding and subtracting numbers", annotations={TOOL_SEARCH_ANNOTATION: "true"}, tools=[Add(), Subtract()], ) class MathAgent(SingleRoomAgent): async def get_exposed_toolkits(self) -> list[Toolkit]: return [MathToolkit()] async def main() -> None: agent = MathAgent(title="math-agent") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` The annotation is the part that makes this room toolkit eligible for dynamic room discovery: ```python Python theme={null} from meshagent.api import TOOL_SEARCH_ANNOTATION annotations={TOOL_SEARCH_ANNOTATION: "true"} ``` Start the toolkit and leave this terminal running: ```bash bash theme={null} meshagent rooms create gettingstarted --if-not-exists meshagent room connect --room=gettingstarted --identity=math-tools -- python3 tools-adder.py ``` ## Search the agent's configured tools Use `--tool-search agent` when the process agent already has a configured set of toolkits and you want OpenAI Responses tool search to choose from that configured set. This is most useful for larger configured agents; for a single small toolkit, `--require-toolkit` by itself is simpler. In a second terminal, require `math-toolkit` by name, then expose the configured toolkit through tool search: ```bash bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name math-helper \ --channel chat \ --model gpt-5.5 \ --require-toolkit math-toolkit \ --tool-search agent ``` Open the Studio link printed by the command and ask: ```text theme={null} Use the math toolkit to add 389 and 457. ``` `math-toolkit` is still required by name. Tool search controls how the OpenAI Responses model sees and selects tools from the agent's configured toolkits. ## Search annotated room toolkits Use `--tool-search room` when the agent should be able to discover eligible toolkits that are already registered in the room. With the annotated `math-toolkit` still running, start a process agent with room tool search: ```bash bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name math-helper \ --channel chat \ --model gpt-5.5 \ --tool-search room \ --log-llm-requests ``` Open the Studio link printed by the command and ask: ```text theme={null} Use the available math tool to add 389 and 457. ``` `--tool-search room` includes annotated room toolkits in the model's search set. The agent does not need `--require-toolkit math-toolkit` because the toolkit is discovered from the room. ## Make a room toolkit discoverable Room tool search only includes toolkits that opt in with the `meshagent.tool_search` annotation. If the toolkit does not set the annotation, `--tool-search room` leaves it out even if the toolkit is visible in the room. Then verify the room sees the annotation: ```bash bash theme={null} meshagent room agents list-toolkits --room=gettingstarted ``` The output should include: ```json theme={null} "annotations": { "meshagent.tool_search": "true" } ``` ## Troubleshooting If the agent does not find a room toolkit: * Check that the toolkit process is still running. * Run `meshagent room agents list-toolkits --room=` and confirm the toolkit is visible. * Confirm the toolkit has `"meshagent.tool_search": "true"` in its annotations. * Use `--tool-search room`, not `--tool-search agent`, when you want annotated room toolkits included. * Use an OpenAI Responses model. `--tool-search` is not supported by non-OpenAI process-agent models. * Do not use `--tool-search` with `--no-room`; room tool search needs a room connection. ## Next Steps * [Create Custom Tools](./quickstart): build and run the `math-toolkit` sample used above. * [How Tools and Toolkits Work](./tools_and_toolkits): understand toolkit registration and hosted toolkit lifecycle. * [OpenAI tool search types](https://developers.openai.com/api/docs/guides/tools-tool-search#tool-search-types): understand the underlying Responses tool-search behavior. # Dynamic UI Tools Source: https://docs.meshagent.com/agents/tools/dynamic_ui_tools This guide explains how dynamic User Interface (UI) tools work in MeshAgent. These elements are client-side tools that run on a user's browser, desktop, or mobile app. Dynamic UIs enable agents to interact directly with users by presenting responsive, on-demand interfaces as needed. They allow agents to do things like: * Collect a document from the user in the middle of a task * Pop up a one-off approval dialog * Fan out a survey to multiple participants in the room ## Why Dynamic UI Tools Matter | Problem in multi-user agent apps | How a Dynamic UI Tool solves it | | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Mid-task input**: An agent needs extra input *during* a task (e.g. “Which PDF should I summarise?”). | Pop a file-picker on only the requester's screen, collect the answer, continue the run. | | **Room wide polls/surveys**: You want a one-off survey of everyone currently in the Room. | Allow the agent to fan-out an **ask\_user** dialog to each participant and gather the responses asynchronously. | | **Targeted notifications**: Agents must present notifications, approvals, or error messages *only* to the relevant user—not the whole Room. | Each UI toolkit is automatically scoped to the participant who registered it, so dialogs can’t leak across screens. | | **Security / Phishing**: Users should not be able to show dialogs on another user's screen just because a tool to show dialogs is exposed. | Toolkits are scoped to the participant that registers them. An agent must pass `participant_id` when it calls `invoke_tool`, so dialogs can’t leak to other users. | ## How MeshAgent Safely Routes UI Tool calls Behind the scenes MeshAgent supports **private tool registrations**. This ensures that dialogues only appear on the intended user's screen even if several clients register toolkits with the same name. For example, you might have multiple `ui` toolkits: one with an `ask_user` tool that shows dialogues on a mobile app, and another with an `ask_user` tool that shows a dialogue in the browser. When a user interface registers a private tool, that tool is accessible only to the registering user. An agent can then invoke this private tool by including the unique identifier of the user (the participant ID) in its call. This ensures that the interface is displayed solely to the intended recipient. ## Example: Survey Room Participants Let’s create a tool that surveys participants in the Room. The tool will conduct a survey of the participants, summarize the results, and store both the raw results and the summary to the Room storage. The survey fields are dynamically generated so that we can gather a variety of information using the same UI tools. This means we can use the same tool to conduct a survey where participants respond yes/no to a question, or to provide more detailed feedback on their experience, etc. ```python Python theme={null} import asyncio import json import logging from meshagent.api.messaging import JsonContent, TextContent from meshagent.api.room_server_client import RoomClient from meshagent.agents import SingleRoomAgent from meshagent.agents.llmrunner import LLMTaskRunner from meshagent.otel import otel_config from meshagent.openai import OpenAIResponsesAdapter from meshagent.tools import LocalRoomTool, ToolContext, Toolkit otel_config(service_name="my-service") log = logging.getLogger("my-service") async def save_to_storage(room: RoomClient, path: str, data: bytes): await room.storage.upload(path=path, data=data) class Survey(LocalRoomTool): def __init__(self, *, room: RoomClient): super().__init__( room=room, name="survey", title="survey", description="a tool that conducts a survey of the participants", input_schema={ "type": "object", "additionalProperties": False, "required": ["subject", "description", "name"], "properties": { "subject": { "type": "string", "description": "The subject of the form", }, "description": { "type": "string", "description": "The content to fill in (e.g. feedback, poll result)", }, "name": { "type": "string", "description": "A short name to be used on the form", }, }, }, ) async def execute( self, context: ToolContext, subject: str, description: str, name: str ): room = self.room participants = await self._wait_for_user_participants(room) log.info("Starting survey for %d participant(s)", len(participants)) if not participants: return TextContent( text=( "No user participants are available to survey. Open a MeshAgent UI " "client in this room, confirm it is registered as a user participant, " "and invoke the survey again." ) ) MAX_ATTEMPTS = 2 async def ask_participant(p): errors = [] for attempt in range(1, MAX_ATTEMPTS + 1): try: log.info("→ ask_user attempt %d --> %s", attempt, p.id) resp = await room.agents.invoke_tool( toolkit="ui", tool="ask_user", participant_id=p.id, input={ "subject": subject, "help": description, "form": [ { "input": { "multiline": False, "name": name, "description": description, "default_value": "", }, }, ], }, ) answer = resp.json.get(name) if answer: log.info("participant_id", p.id, "response", answer) return {"participant_id": p.id, "response": answer} raise RuntimeError("empty or timed-out response") except Exception as exc: errors.append(f"attempt {attempt}: {exc}") if attempt < MAX_ATTEMPTS: log.info("Retrying %s after: %s", p.id, exc) await asyncio.sleep(1) # brief back-off # All attempts failed – return aggregated error list return {"participant_id": p.id, "errors": errors} log.info("Surveying participants") tasks = [asyncio.create_task(ask_participant(p)) for p in participants] results = await asyncio.gather(*tasks) summary = { "meta": { # save the prompt generated for the survey "subject": subject, "description": description, "name": name, }, "success": {}, "failed": {}, } for item in results: pid = item["participant_id"] if "response" in item: summary["success"][pid] = item["response"] else: summary["failed"][pid] = item["errors"] # write survey results to the room log.info("Survey completed, writing raw results to Room storage") await save_to_storage( room=room, path=f"survey/{room.room_name}-{name}.json", data=json.dumps({"summary": summary}, indent=2).encode("utf-8"), ) # summarize results log.info("Summarizing survey results") summary_schema = { "type": "object", "properties": {"summary": {"type": "string"}}, "required": ["summary"], "additionalProperties": False, } runner = LLMTaskRunner( llm_adapter=OpenAIResponsesAdapter(), output_schema=summary_schema, ) summary_resp = await runner.run( room=room, arguments={ "prompt": f"Summarize these survey results:\n{json.dumps(summary)}", "model": None, }, caller=context.caller, ) if isinstance(summary_resp, JsonContent): summary_text = summary_resp.json.get("summary") or summary_resp.json.get( "result", "" ) elif isinstance(summary_resp, TextContent): summary_text = summary_resp.text else: summary_text = str(summary_resp) log.info("Saving survey result summary") await save_to_storage( room=room, path=f"survey/{room.room_name}-{name}-summary.doc", data=summary_text.encode("utf-8"), ) return TextContent(text=summary_text) async def _wait_for_user_participants(self, room: RoomClient, timeout: float = 5.0): deadline = asyncio.get_running_loop().time() + timeout while True: participants = [ p for p in room.messaging.remote_participants if p.role == "user" ] if participants: return participants if asyncio.get_running_loop().time() >= deadline: return [] await asyncio.sleep(0.25) class SurveyToolkit(Toolkit): def __init__(self, *, room: RoomClient): super().__init__( name="survey-toolkit", title="survey-toolkit", description="a toolkit for conducting a survey", tools=[Survey(room=room)], ) class SurveyAgent(SingleRoomAgent): async def start(self, *, room: RoomClient) -> None: await room.messaging.enable() await super().start(room=room) async def get_exposed_toolkits(self) -> list[Toolkit]: return [SurveyToolkit(room=self.room)] async def main() -> None: agent = SurveyAgent(title="survey-toolkit-host") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` Copy this code, activate your virtual environment, and run the toolkit in the `gettingstarted` room. Leave this `room connect` process running; it is the process that hosts `survey-toolkit` and watches for messaging-enabled user participants. ```bash bash theme={null} meshagent setup # this will prompt you to authenticate to MeshAgent, select your project and API keys meshagent rooms create gettingstarted --if-not-exists meshagent room connect --room=gettingstarted --identity=survey-toolkit -- python3 private-tool-call.py ``` Next go to [studio.meshagent.com](https://studio.meshagent.com) and click into the `gettingstarted` room. You can also use a Powerboards room page. The survey toolkit looks for messaging-enabled room participants with the `user` role and then invokes that participant's private `ui.ask_user` tool. Before invoking the survey, confirm the room sees a user participant. This command joins the room as a temporary CLI participant, enables messaging for that CLI participant, and lists the other messaging-enabled participants it discovers: ```bash bash theme={null} meshagent room messaging list --room=gettingstarted ``` Copy the `id` for the user participant from that output. Then confirm the room sees the public `survey-toolkit` and, for that user participant, a private `ui` toolkit: ```bash bash theme={null} meshagent room agents list-toolkits --room=gettingstarted meshagent room agents list-toolkits --room=gettingstarted --participant-id ``` If `meshagent room messaging list` returns only agents or `[]`, the toolkit host does not currently see a user participant it can survey. Make sure the Studio or Powerboards room page is open in the same MeshAgent project and room. In that state no browser UI will appear, even if the survey tool itself is reachable. Invoke the survey tool from a separate terminal: ```bash bash theme={null} meshagent room agents invoke-tool \ --room gettingstarted \ --toolkit survey-toolkit \ --tool survey \ --arguments '{"subject":"Hiring feedback","description":"What did you think of the candidate?","name":"feedback"}' ``` Connected user participants will be prompted to fill out the survey in their UI client. Once the results are captured, the tool summarizes the responses and saves both the raw results and summary to Room storage. ## Next Steps: Using Dynamic Tools in Your Own App MeshAgent UI client libraries include a private `ui` toolkit pattern with tools such as `ask_user` and `ask_user_for_file`. A connected UI client must register that toolkit for its participant before another agent can invoke it. If you want custom dialogs in your own web or mobile client, register a private toolkit named `ui` with the same tool names and schemas. When an agent invokes the tool with that participant's ID, MeshAgent routes the call to your application's client-side UI implementation. # MCP Servers & OpenAI Connectors Source: https://docs.meshagent.com/agents/tools/mcp_servers Connect external MCP tools to MeshAgent with Powerboards, meshagent service, or meshagent mcp. MCP servers and OpenAI connectors are two ways to expose external tools in MeshAgent. * **[OpenAI connectors](https://platform.openai.com/docs/guides/tools-remote-mcp?lang=python)** wrap supported third-party products such as Gmail, Google Drive, Outlook, Microsoft Teams, and Dropbox. * **[MCP servers](https://modelcontextprotocol.io/introduction)** expose tools over the Model Context Protocol, whether the server is public, self-hosted, or provided by another vendor. Use an OpenAI connector when OpenAI already provides the integration for the product you want. Use an MCP server when the tool is exposed over MCP by you or by another vendor. For a concrete vendor-specific walkthrough, see [Supabase MCP Guide](./supabase_mcp). ## Installation paths | Path | Use it when | What you get | | ----------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | | **Powerboards** | The server already exposes a hosted MCP endpoint and the install flow works in the UI. | A room install without writing YAML yourself. | | **`meshagent service`** | You want a saved deployment in MeshAgent, need room or project scope, or need to control the manifest. | A deployed service that stays available after your terminal closes. | | **`meshagent mcp`** | You want a live CLI bridge, are testing a server, or need to connect a local stdio server quickly. | A toolkit registration that stays available while the command is running. | OpenAI connectors belong to the **`meshagent service`** path. You configure them in the service manifest with `openai_connector_id` and the provider's OAuth settings. ## Install from Powerboards Powerboards is the fastest path when the MCP server already exposes a hosted endpoint that can be inspected and installed directly. ### Good fit for Powerboards * Public no-auth servers such as DeepWiki (`https://mcp.deepwiki.com/mcp`) are the simplest case. * Hosted OAuth-aware servers such as [Linear MCP](https://linear.app/docs/mcp) can guide you through sign-in when the server exposes the right remote MCP metadata. * Servers that need custom headers, secrets, a saved deployment, or a local stdio process are usually a better fit for `meshagent service` or `meshagent mcp`. ### How to install an MCP server in Powerboards 1. Open the room in [Powerboards](https://app.powerboards.com). 2. Click the agent dropdown. 3. Click **Manage Agents**. 4. Click **Install**. 5. Enter the URL for the custom agent or MCP server. Powerboards will install the MCP server if it is available. Powerboards can also install from a hosted `ServiceTemplate` link when you want to distribute a more opinionated setup flow. For more on those install paths, see [Powerboards](../../interfaces/powerboards). ## Use `meshagent service` for a saved deployment Use `meshagent service` when you want the tool to stay deployed in MeshAgent and be available to the project or room that needs it. ### Generate a service from an MCP URL If the MCP server is already hosted, the CLI can generate the service manifest for you. Inspect the generated manifest first: ```bash theme={null} meshagent service spec \ --mcp https://mcp.deepwiki.com/mcp ``` Create the service immediately: ```bash theme={null} meshagent service create \ --mcp https://mcp.deepwiki.com/mcp \ --room quickstart ``` The CLI auto-discovers the MCP server metadata. If the server exposes OAuth registration metadata, the generated service is configured for that flow automatically. ### Example: deploy a standard MCP server This example exposes the public DeepWiki MCP server as a room service: ```yaml Yaml theme={null} kind: Service version: v1 metadata: name: mcp-deepwiki description: "Expose DeepWiki MCP server" ports: - num: 443 # SSL is 443 for non SSL it's 80 type: http endpoints: - path: /mcp # url + path are appended together mcp: label: "mcp-deepwiki" description: "MCP DeepWiki Tools" external: url: "https://mcp.deepwiki.com" ``` You can deploy it from a YAML file: ```bash theme={null} meshagent service create --file meshagent.yaml --room quickstart ``` Or generate the YAML from the MCP URL first and then deploy it: ```bash theme={null} meshagent service spec \ --mcp https://mcp.deepwiki.com/mcp \ > meshagent.yaml meshagent service create --file meshagent.yaml --room quickstart ``` ### Example: deploy an OpenAI connector Use this path when OpenAI already provides the integration you want and you want that connector available inside MeshAgent as a deployed service. For connector-specific setup details and the latest OpenAI-side behavior, see the [OpenAI remote MCP and connectors guide](https://platform.openai.com/docs/guides/tools-remote-mcp) and [OpenAI connector docs](https://platform.openai.com/docs/guides/tools-connectors). This example exposes the Microsoft Teams connector through a MeshAgent service: ```yaml Yaml theme={null} kind: Service version: v1 metadata: name: microsoft-teams-connector description: "Expose Microsoft Teams via OpenAI Connector" ports: - num: "*" type: http endpoints: - path: / mcp: label: "microsoft-teams-connector" description: "OpenAI Connector for Microsoft Teams" openai_connector_id: "connector_microsoftteams" oauth: client_id: "YOUR_CLIENT_ID" client_secret: "..." authorization_endpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" token_endpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token" no_pkce: false # Optional: depends on if pkce is used scopes: ["User.Read", "Chat.Read", "ChannelMessage.Read.All"] external: {} ``` ```bash theme={null} meshagent service create --file meshagent.yaml --room quickstart ``` The key difference from a standard MCP URL is that you define the connector explicitly in the manifest: * `openai_connector_id` selects the OpenAI connector * `oauth` provides the third-party provider OAuth settings for that connector * the service is still deployed with `meshagent service`, just like any other saved external tool ## Use `meshagent mcp` for a live CLI bridge Use `meshagent mcp` when you want to register a toolkit in a room directly from the CLI instead of creating a saved service first. For a hosted streamable HTTP server: ```bash theme={null} meshagent mcp http \ --room quickstart \ --url https://mcp.deepwiki.com/mcp \ --toolkit-name deepwiki ``` Use `meshagent mcp sse` for SSE servers, and `meshagent mcp stdio` when the MCP server runs as a local process and should be bridged into the room. ### Other `meshagent mcp` commands * `meshagent mcp stdio`: run a local stdio MCP server and register it in the room * `meshagent mcp http-proxy`: expose a stdio MCP server as streamable HTTP * `meshagent mcp sse-proxy`: expose a stdio MCP server as SSE * `meshagent mcp stdio-service`: run a stdio MCP server through the local service bridge `meshagent mcp` is session-based. The toolkit stays available while the command is running. It does not create a saved MeshAgent service. ## Start an agent that can use MCP tools Once the MCP service or toolkit is available in the room, start an agent that can use it: ```bash theme={null} meshagent process join \ --room quickstart \ --agent-name agent \ --channel chat \ --mcp ``` Open [MeshAgent Studio](https://studio.meshagent.com), join the room, and enable the MCP tool when you want the agent to use it. For the broader tool model, see [How Tools and Toolkits Work](./tools_and_toolkits). ## Security and setup notes When adding an MCP server, think about: * what data the external service will receive * who operates the MCP server * whether the agent should opt into MCP tool use with `--mcp` * whether the server needs additional secrets, headers, or OAuth setup ## Related topics * [Built-in MeshAgent Toolkits](./built_in_toolkits) * [Tools and Toolkits](./tools_and_toolkits) * [Powerboards](../../interfaces/powerboards) * [Service YAML](../../services/deployment/deploy_services) * [Secrets and Credentials](../../secrets/overview) * [MeshAgent CLI Commands](../../reference/meshagent_cli_help) # Create Custom Tools Source: https://docs.meshagent.com/agents/tools/quickstart Custom tools let you add capabilities beyond the built-in MeshAgent toolkits. A `Toolkit` groups related `Tool`s together so they can be registered in a room and used by people or agents. In this guide you'll: * Write custom tools * Create a toolkit to group your related tools * Register a toolkit in a room * Invoke tools using the MeshAgent CLI, MeshAgent Studio UI, and code * Give a process agent access to the toolkit * Let a process agent dynamically discover annotated room toolkits ## Creating a custom toolkit ### Step 1: Writing custom tools Let's create a simple toolkit with two tools, one that can add two numbers, and one that can subtract two numbers. First write the logic for the `add` and `subtract` tools. Then bundle them into a `Toolkit` that a `SingleRoomAgent` can expose for room calls. Save this example as `tools-adder.py`: ```python Python theme={null} import asyncio from meshagent.api import TOOL_SEARCH_ANNOTATION from meshagent.agents import SingleRoomAgent from meshagent.tools import FunctionTool, ToolContext, Toolkit from meshagent.otel import otel_config otel_config(service_name="math_tools") class Add(FunctionTool): def __init__(self): super().__init__( name="add", title="adding tool", description="a tool that adds two numbers", input_schema={ "type": "object", "additionalProperties": False, "required": ["a", "b"], "properties": { "a": {"type": "integer"}, "b": {"type": "integer"}, }, }, ) async def execute(self, context: ToolContext, *, a: int, b: int): result = {"result": a + b} print(result) return result class Subtract(FunctionTool): def __init__(self): super().__init__( name="subtract", title="subtracting tool", description="a tool that subtracts two numbers", input_schema={ "type": "object", "additionalProperties": False, "required": ["a", "b"], "properties": { "a": {"type": "integer"}, "b": {"type": "integer"}, }, }, ) async def execute(self, context: ToolContext, *, a: int, b: int): result = {"result": a - b} print(result) return result class MathToolkit(Toolkit): def __init__(self): super().__init__( name="math-toolkit", title="math-toolkit", description="a toolkit for adding and subtracting numbers", annotations={TOOL_SEARCH_ANNOTATION: "true"}, tools=[Add(), Subtract()], ) class MathAgent(SingleRoomAgent): async def get_exposed_toolkits(self) -> list[Toolkit]: return [MathToolkit()] async def main() -> None: agent = MathAgent(title="math-agent") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` ### Step 2: Register the toolkit in a room Create the room and start the toolkit locally. This guide uses `gettingstarted`, the same room created in the CLI quickstart, so you can reuse a room you already own. ```bash bash theme={null} meshagent setup # authenticate to MeshAgent meshagent rooms create gettingstarted --if-not-exists meshagent room connect --room=gettingstarted --identity=math-tools -- python3 tools-adder.py ``` This command runs the local Python agent and registers the `math-toolkit` toolkit into `gettingstarted`. The toolkit is available while that terminal session is still running. `SingleRoomAgent.run()` creates the room connection, starts the agent, and unregisters the exposed toolkit when the process stops. ### Step 3: Invoke and inspect the toolkit #### Invoking tools programmatically While the agent is running, invoke the toolkit from another terminal or from code. Run the Python and .NET examples through `meshagent room connect` so MeshAgent injects the room connection environment. The Python tab can be saved as `tools-calling.py` and run directly. For .NET, add the C# tab to a .NET project that references `Meshagent.Api`, then run the project through `meshagent room connect`. ```bash CLI theme={null} meshagent room agents invoke-tool \ --room=gettingstarted \ --toolkit=math-toolkit \ --tool=add \ --arguments='{"a": 5, "b":7}' ``` ```python Python theme={null} # Run with: # meshagent room connect --room=gettingstarted --identity=sample-participant -- python3 tools-calling.py import asyncio import logging from meshagent.api import RoomClient from meshagent.otel import otel_config otel_config() log = logging.getLogger(__name__) async def main(): try: async with RoomClient() as room: log.info("Connected to room: %s", room.room_name) add_result = await room.agents.invoke_tool( toolkit="math-toolkit", tool="add", input={"a": 1, "b": 2} ) log.info("The result from adding the numbers is: %s", add_result) subtract_result = await room.agents.invoke_tool( toolkit="math-toolkit", tool="subtract", input={"a": 1, "b": 2} ) log.info("The result from subtracting the numbers is: %s", subtract_result) except Exception as e: log.error("Error invoking tool: %s", e) raise asyncio.run(main()) ``` ```dotnet C# theme={null} using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Meshagent.Api.Room; // Run with: // meshagent room connect --room=gettingstarted --identity=sample-participant -- dotnet run class Program { static async Task Main() { await using var room = new RoomClient(); await room.ConnectAsync(); var arguments = new Dictionary { ["a"] = 1, ["b"] = 2 }; var addResult = await room.Agents.InvokeTool("math-toolkit", "add", arguments); Console.WriteLine($"The result from adding the numbers is: {JsonSerializer.Serialize(addResult.ToJson())}"); var subtractResult = await room.Agents.InvokeTool("math-toolkit", "subtract", arguments); Console.WriteLine($"The result from subtracting the numbers is: {JsonSerializer.Serialize(subtractResult.ToJson())}"); } } ``` Invoking the tools using the RoomClient will give you the following result: ```text Output theme={null} The result from adding the numbers is: Json: json={"result": 3} The result from subtracting the numbers is: Json: json={"result": -1} ``` #### Inspecting available toolkits You can also verify which toolkits are registered in the room. Run the Python and .NET discovery examples through the same `meshagent room connect` pattern. ```bash CLI theme={null} meshagent room agents list-toolkits --room=gettingstarted ``` ```python Python theme={null} # Run with: # meshagent room connect --room=gettingstarted --identity=sample-participant -- python3 tools-discovery.py import asyncio import logging from meshagent.api import RoomClient from meshagent.otel import otel_config otel_config() log = logging.getLogger(__name__) async def main(): try: async with RoomClient() as room: toolkits = await room.agents.list_toolkits() print("The tools connected to our room are:") for toolkit in toolkits: print( f"\n Toolkit: {toolkit.name}: {toolkit.title} - {toolkit.description}" ) for tool in toolkit.tools: print(f" Tool: {tool.name}: {tool.title} - {tool.description}") except Exception as e: log.error("Error listing available toolkits: %s", e) raise asyncio.run(main()) ``` ```dotnet C# theme={null} using System; using System.Threading.Tasks; using Meshagent.Api.Room; // Run with: // meshagent room connect --room=gettingstarted --identity=sample-participant -- dotnet run class Program { static async Task Main() { await using var room = new RoomClient(); await room.ConnectAsync(); var toolkits = await room.Agents.ListToolkits(); Console.WriteLine("The tools connected to our room are:"); foreach (var toolkit in toolkits) { Console.WriteLine($"\n Toolkit: {toolkit.Name}: {toolkit.Title} - {toolkit.Description}"); foreach (var tool in toolkit.Tools) { Console.WriteLine($" Tool: {tool.Name}: {tool.Title} - {tool.Description}"); } } } } ``` The output should include `math-toolkit`, its `add` and `subtract` tools, and this annotation: ```json theme={null} "annotations": { "meshagent.tool_search": "true" } ``` #### Invoking tools in MeshAgent Studio 1. Go to [studio.meshagent.com](https://studio.meshagent.com) and login 2. From the **Sessions** tab enter `gettingstarted` 3. From the menu in the upper left, click **Toolkits** 4. Find the tool you want to run and click **Invoke** 5. Enter any required values and click **Ok** The tool will execute and display the result in the Studio UI. From the "Developer Console" on the bottom half of the screen you'll be able to see logs, traces, and metrics from tool calls as they happen in the room. Because this example is running locally through `meshagent room connect`, the toolkit is only available while that terminal session is still running. ### Step 4: Give a process agent access to the toolkit There are two common ways to make a room toolkit available to a process agent. #### Option A: Require the toolkit by name Use `--require-toolkit` when the agent should always have access to a specific room toolkit. This is the simpler path when you already know which toolkit the agent should use. Leave the terminal running `meshagent room connect --room=gettingstarted --identity=math-tools -- python3 tools-adder.py`; that process is hosting `math-toolkit` in the room. In a second terminal, start a chat agent that requires `math-toolkit`: ```bash bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name math-helper \ --channel chat \ --model gpt-5.5 \ --require-toolkit math-toolkit ``` Open the Studio link printed by the command and ask the agent an arithmetic question, such as: ```text theme={null} Use the available math tool to add 389 and 457. ``` If you deploy the process agent with the same required toolkit, the agent will request that toolkit by name whenever it handles a turn in the room. #### Option B: Let the agent discover annotated room toolkits Use `--tool-search room` when the agent should be able to dynamically discover annotated toolkits that are already present in the room. This is useful when you do not want to configure every toolkit directly on the agent. This option uses OpenAI Responses tool search behind the scenes, so it only applies to OpenAI-backed process-agent models. The sample toolkit sets the `meshagent.tool_search` annotation. Start a chat agent with room tool search enabled: ```bash bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name math-helper \ --channel chat \ --model gpt-5.5 \ --tool-search room \ --log-llm-requests ``` Open the Studio link printed by the command and ask the agent an arithmetic question: ```text theme={null} Use the available math tool to add 389 and 457. ``` `--tool-search room` adds annotated room toolkits to the model's tool-search candidate set. In the process-agent logs, `math-toolkit` should appear as a deferred toolkit available to the model. ## Next Steps If you want the toolkit to stay available after your local terminal session ends, package and deploy it as a MeshAgent service. * [Dynamic UI Tools](./dynamic_ui_tools): Learn what Dynamic UI tools are and how to build and use them in your applications * Learn how to use custom tools inside a [Process Agent](../process/overview) or [Voice Agent](../standard/voicebot) * [Service YAML](../../services/deployment/deploy_services): write service manifests for agents and tools. # Supabase MCP Guide Source: https://docs.meshagent.com/agents/tools/supabase_mcp Supabase is an open-source backend platform that provides a hosted Postgres database, auth, storage, and realtime APIs. The Supabase MCP server exposes these capabilities as tools that can be used in MeshAgent. In this guide you'll learn how to: * Create a Supabase account and access token * Quick start: Install a pre-built Supabase toolkit into Powerboards in minutes * Build and customize: Connect, test, and deploy the Supabase MCP server using the MeshAgent CLI ## Supabase Setup (required for both paths) 1. Create a Supabase account and a project at [https://supabase.com](https://supabase.com). 2. From the Project Settings -> General page you will see the Project ID (also called Project Reference). You will use this value to connect MeshAgent to your Supabase project. 3. Create a Supabase access token. Go to [Account Settings -> Access Tokens](https://supabase.com/dashboard/account/tokens). Generate a new token and set an expiration date for it. Keep this value private. > **Note**: Each MCP connection is scoped to a single Supabase project. If you need to connect multiple projects, repeat the steps below with a different project reference and toolkit name. ## Quickstart: Install via Powerboards If you want to get up and running without using the MeshAgent CLI, you can install the Supabase toolkit directly into [Powerboards](https://app.powerboards.com). 1. Click the link below to open the supabase toolkit installer: [Install Supabase Toolkit in Powerboards](https://app.powerboards.com/install?url=https://gist.githubusercontent.com/tmasterman/314481e88893b7e0107f91f9c2248a14/raw/bb7754ec7c79ec1cdfe69372fa309212e6a5c311/meshagent.yaml). 2. Powerboards will walk you through the setup, you will sign in, create/select a Project, create/select a room, then install the toolkit. You will need to paste in your Supabase Project ID and Supabase Access Token you generated above. Powerboards will automatically store the access token as a secret. 3. Next, click the link to install an agent that uses the toolkit: [Install Agent that Uses Supabase Toolkit in Powerboards](https://app.powerboards.com/install?url=https://gist.githubusercontent.com/tmasterman/242347b76701ec064b327b3909fe8881/raw/35c4609114f215d58bcbdb8c052340fce7cb8db4/meshagent.yaml). 4. Follow the same process to install the agent. Once installed, the Supabase toolkit will be available in your room. Any agent in the room with access to the toolkit can use it to interact with your Supabase project. ## Build and Customize: CLI Guide This path walks you through connecting and testing the Supabase MCP server locally, then deploying it as a persistent service. This is useful if you want to customize the toolkit, test changes before deploying, or understand how the pre-built Powerboards template works under the hood. ### Prerequisites Before you begin, make sure you have: * The [MeshAgent CLI](../../introduction/cli_quickstart) installed * Connected to the MeshAgent project you want to work in (run `meshagent setup` to authenticate and select your project) * Your Supabase Project Reference and Access Token from the setup step above **Credential note:** Supabase MCP credential setup uses user-owned secrets plus MCP proxy access. This CLI example passes the token directly into the deployed template when proxy-backed setup is not configured. ### Step 1: Export your credentials Export your Supabase credentials so the following commands can reference them: ```bash bash theme={null} export SUPABASE_PROJECT_REF="your_project_ref" export SUPABASE_ACCESS_TOKEN="your_access_token" ``` ### Step 2: Configure credentials Supabase MCP credentials can be configured with user-owned secrets and MCP proxy grants, or passed directly into the deployed template for local CLI-driven setup. ### Step 3: Start the MCP Session The `project_ref` parameter in the URL determines which Supabase project this toolkit can access. Agents or humans using this toolkit will only be able to interact with that specific project. This will print an output like ``` Connecting to room... INFO:mcp.client.streamable_http:Received session ID: ... ``` **How can I see the MCP toolkit?** Open a new terminal tab then run: ```bash bash theme={null} meshagent setup # authenticate and connect to the same project meshagent room agents list-toolkits --room myroom ``` You should see the supabase toolkit listed along with all its available tools. You can also verify in [MeshAgent Studio](https://studio.meshagent.com). Navigate to `myroom`, open the menu in the upper left, and select **Toolkits**. You will see the **supabase** toolkit and its associated tools. ### Step 4: Test with an agent With the MCP session still running in your first terminal tab, from a second tab in your terminal start a process-backed agent that uses the Supabase toolkit: ```bash bash theme={null} meshagent process join \ --room myroom \ --agent-name supabase-agent \ --channel chat \ --require-toolkit supabase \ --web-search \ --room-rules "agents/supabase-agent/rules.md" \ --rule "You are an agent who helps users work with Supabase. Use the Supabase toolkit to interact with a specific Supabase project. If the web search tool is enabled, you can search the web to learn more about the latest updates to Supabase." ``` > **Note**: The `--room-rules` flag is optional. It creates a file at the specified path that anyone in the room can edit to customize the agent's rules. This is useful if you want to tweak the agent's behavior without redeploying it. Try it out in [MeshAgent Studio](https://studio.meshagent.com): 1. Enter `myroom` 2. Select the **supabase-agent** from the participants list 3. Ask the agent to perform a task, such as listing tables in your Supabase project. 4. Optionally, click the + button and enable **Web Search** to let the agent look up Supabase documentation on the fly. Now that you've tried it in MeshAgent Studio you can deploy the supabase toolkit and accompanying agent. ### Step 5: Deploy the Supabase toolkit as a persistent service Once you've verified everything works locally, you can deploy the Supabase toolkit as a persistent service so the toolkit stays available without a local terminal session. Create a ServiceTemplate configuration file, `meshagent.yaml`, that defines the service: Deploy the service template: ```bash bash theme={null} meshagent service create-template \ --file "meshagent.yaml" \ --value supabase_project_ref=$SUPABASE_PROJECT_REF \ --value supabase_access_token=$SUPABASE_ACCESS_TOKEN \ --room myroom ``` > Warning: Until MCP proxy support is fully rolled out, rotating the Supabase token requires updating and redeploying the service template. After deployment, the Supabase toolkit will be available to any participant or agent in the room without a local MCP session. To deploy the process-backed agent that uses the toolkit run: ```bash bash theme={null} meshagent process deploy \ --service-name supabase-agent \ --room myroom \ --agent-name supabase-agent \ --channel chat \ --require-toolkit supabase \ --web-search \ --room-rules "agents/supabase-agent/rules.md" \ --rule "You are an agent who helps users work with Supabase. Use the Supabase toolkit to interact with a specific Supabase project. If the web search tool is enabled, you can search the web to learn more about the latest updates to Supabase." ``` Once the agent is deployed you'll be able to interact with it from both MeshAgent Studio and Powerboards. ### Publishing to Powerboards Once you're happy with your service template, you can make it installable via Powerboards so others can use it without going through the CLI steps. 1. Push your `meshagent.yaml` to a GitHub Gist (or any publicly accessible URL). 2. Click the Raw button on the gist to get the direct URL to the file. 3. Construct the Powerboards install link: [https://app.powerboards.com/install?url=YOUR\_RAW\_URL](https://app.powerboards.com/install?url=YOUR_RAW_URL) Anyone who clicks that link will be able to install the toolkit into their own room. Configure any required credentials as user-owned secrets and grant the service account MCP proxy access to the secret. # How Tools and Toolkits Work Source: https://docs.meshagent.com/agents/tools/tools_and_toolkits MeshAgent tools are room-connected capabilities that humans and agents can discover, call, and share. Use this page to understand the core model: what a tool is, what a toolkit is, how shared tool registration works, and how MeshAgent handles always-on versus per-turn tool access. ## Mental model * `Tool` = one discrete action an agent or human participant can take. * `ToolContext` = the execution context available when a tool runs. * `LocalRoomTool` = a mixin for tools that need a bound `RoomClient`; room-aware tools use `self.room`. * `Toolkit` = a named bundle of related tools plus optional rules and descriptions. * Hosted toolkit = a `Toolkit` that a service or room participant registers with a room so other participants can discover and call it. ## Tools ### `Tool` A `Tool` defines one action that an agent or person can perform. The tool declares what it expects in `input_schema` and what work to perform in `execute()`. **Constructor parameters** | Parameter | Type | Default | Description | | -------------- | --------------------------- | ------: | -------------------------------------------------------------------- | | `name` | `str` | — | Unique tool name within a toolkit. | | `input_schema` | `dict` | — | JSON Schema for the tool arguments. Enforced at call time. | | `title` | `Optional[str]` | `name` | Human-readable display name. | | `description` | `Optional[str]` | `""` | Short description of the tool. | | `rules` | `Optional[list[str]]` | `None` | Behavioral guidance for LLMs. | | `defs` | `Optional[dict[str, dict]]` | `None` | Reusable JSON Schema definitions merged into the schema via `$defs`. | **Method** ```python Python theme={null} async def execute(self, context: ToolContext, **kwargs): ... ``` ### Tool return types Tools commonly return subclasses of `Content` declared in `meshagent.api.messaging`. | Content type | When to use it | | -------------- | ------------------------------------------------------------------------------- | | `JsonContent` | Structured JSON output, such as API payloads or summarized data. | | `TextContent` | Plain-text answers or status messages. | | `FileContent` | Binary content such as generated documents, images, or archives. | | `LinkContent` | A URL pointing to an external resource. | | `EmptyContent` | No payload, usually for successful operations that do not need a response body. | ### `ToolContext` `ToolContext` carries the runtime information a tool needs. If a tool needs room access, use `RoomToolContext` or a room-bound toolkit. | Property | Description | | -------------- | ------------------------------------------------------ | | `caller` | The participant who called the tool. | | `on_behalf_of` | The participant a calling agent is acting for, if any. | If a tool needs room access, inherit `LocalRoomTool` and use `self.room` inside `execute(...)`. Toolkits and hosting helpers bind the active `RoomClient` before the tool runs. ## Toolkits ### Toolkit vs hosted toolkit A `Toolkit` is the definition of a group of tools plus the metadata and validation rules that go with them. Use a plain `Toolkit` when the tools only need to exist inside one process, such as a single agent runtime. Use a hosted toolkit when the tools should be registered in a room so other participants can discover and call them. ### `Toolkit` A `Toolkit` bundles related tools under a single name so callers can discover, invoke, and permission them together. **Constructor parameters** | Parameter | Type | Default | Description | | ----------------- | ---------------- | ----------: | -------------------------------------------------------------------------------- | | `name` | `str` | — | Toolkit identifier used for discovery and invocation. | | `tools` | `list[BaseTool]` | — | The tools this toolkit exposes. | | `rules` | `list[str]` | `list[str]` | Optional global guidance that applies to the toolkit. | | `title` | `Optional[str]` | `name` | Human-readable toolkit name. | | `description` | `Optional[str]` | `""` | Description used for discovery and display in MeshAgent Studio. | | `validation_mode` | `ValidationMode` | `"full"` | Validation policy used when the toolkit is invoked. | | `public` | `bool` | `True` | Whether the toolkit should be publicly discoverable when it is hosted in a room. | **Methods** * `get_tool(name)`: returns the named tool or raises a `RoomException` if it is not present. * `execute(context, name, input)`: validates the input content, invokes the tool, and returns a response. > Toolkits emit OpenTelemetry spans out of the box, so MeshAgent can track who called a tool, how long it took, and what room it ran in. ### Hosted toolkit lifecycle Hosted toolkits are plain `Toolkit` instances across the SDKs. * In Python, expose local toolkits from a room-connected `SingleRoomAgent` by overriding `get_exposed_toolkits()` and running the agent with `SingleRoomAgent.run()`. If your application already owns a `RoomClient`, use MeshAgent's lower-level room-hosting helpers to register the toolkit and keep it available for room calls. * In TypeScript and Dart, `startHostedToolkit(...)` registers the toolkit and returns a `HostedToolkit` handle. Higher-level helpers like React's `useClientToolkits(...)` and Flutter's `ClientToolkits` widget use that same hosting API internally. `Toolkit` itself does not expose `start()` / `stop()`. Those lifecycle operations live on the room-hosting helper or the returned hosted-toolkit handle. **Hosted handle methods** * `stop()`: * stops listening for room tool calls, * unregisters the toolkit from the room. ## Toolkit patterns MeshAgent supports two complementary ways to make tools available during an agent turn. ### Static toolkits Static toolkits stay attached to the agent for its full lifetime. * Construct the toolkit up front and pass it in the agent's `toolkits` list. * The toolkit is instantiated once and participates in every LLM turn. * Use this when the agent should always have a capability available. On the CLI, built-in capabilities now use one canonical flag per capability, such as `--web-search`, `--web-fetch`, `--storage`, `--shell`, `--advanced-shell`, `--document-authoring`, and `--discovery`. `--require-toolkit` remains the flag for attaching an external toolkit by name. If you need a capability available for every turn, add the corresponding toolkit directly in code or start the agent with the relevant CLI flag. If the capability should be discoverable by other participants, host the toolkit in a room and let callers invoke it over MeshAgent's room-tool protocol. ## Tool access and availability ### `RequiredToolkit` Agents can declare toolkit dependencies explicitly: ```python Python theme={null} from meshagent.api import RequiredToolkit requires = [ RequiredToolkit(name="my-toolkit-name", tools=[my_first_tool(), my_second_tool()]) ] ``` When the agent connects, the room server verifies the required toolkit is available. If not, the agent gets an error instead of starting with missing capabilities. ### Tool access and permissions Tool access is controlled by the participant token's `ApiScope.agents` grant: * `register_public_toolkit` / `register_private_toolkit`: allow registering public or private toolkits. * `use_tools`: required to list or inspect toolkits. * `call`: required to invoke tools. Public toolkits are visible to any participant with `use_tools`. Private toolkits are only listed for the participant that registered them. Use [API scope grants](../../rest_api/api_scopes) to decide which services or users can register, inspect, and call tools. ## Related guides * [Built-in MeshAgent Toolkits](./built_in_toolkits) * [Create Custom Tools](./quickstart) * [Dynamic UI Tools](./dynamic_ui_tools) * [MCP Servers](./mcp_servers) * [Supabase MCP Guide](./supabase_mcp) # Document Connections Source: https://docs.meshagent.com/flutter/document_connection_scope Open and keep a MeshAgent room document in sync from React or Flutter. Use a document connection helper when your UI needs a live room document. This sits one level below a room connection: first connect to the room, then open the document you want to render or edit. ## React Use `useDocumentConnection` from `@meshagent/meshagent-react`: ```tsx theme={null} import { useDocumentConnection } from "@meshagent/meshagent-react"; export function DocumentView({ room }: { room: any }) { const { document, error, loading } = useDocumentConnection({ room, path: "/notes/thread.thread", }); if (loading) return
Loading document...
; if (error) return
Error: {String(error)}
; if (!document) return
No document
; return
Connected to document {document.id}
; } ``` ## Flutter Use `DocumentConnectionScope` from `meshagent_flutter`: ```dart theme={null} import 'package:flutter/widgets.dart'; import 'package:meshagent/meshagent.dart'; import 'package:meshagent_flutter/meshagent_flutter.dart'; class SampleWidget extends StatelessWidget { const SampleWidget({ super.key, required this.room, required this.path, }); final RoomClient room; final String path; @override Widget build(BuildContext context) { return DocumentConnectionScope( path: path, room: room, builder: (context, document, error) { if (error != null) { return Text('Error: $error'); } if (document == null) { return Text('Loading...'); } return Text('Document loaded: ${document.id}'); }, ); } } ``` ## What these helpers do * open the document from an existing `RoomClient` * keep the connection alive while your component or widget is mounted * surface loading or error state back into the UI * close the document connection when the UI goes away ## When to use this Use a document connection when your app needs a live, room-backed document surface such as: * shared notes * thread documents * structured room content For the lower-level runtime model behind these helpers, see [Sync / Documents](../room_api/sync). # Room Connections Source: https://docs.meshagent.com/flutter/room_connection_scope Connect your app to a MeshAgent room from React or Flutter. Use a room connection helper when your app needs a live `RoomClient`. This is the primitive that turns a room URL and participant token into an active room connection your UI can render on top of. ## What you need * A room URL * A participant token * A way to fetch both from your backend In production, your backend usually gets those values from MeshAgent and returns them to the client. For local or controlled development flows, the SDKs also expose static or development authorization helpers. ## React Use `useRoomConnection` from `@meshagent/meshagent-react`: ```tsx theme={null} import { useRoomConnection } from "@meshagent/meshagent-react"; export function RoomScreen() { const { client, state, error } = useRoomConnection({ authorization: async () => { const resp = await fetch("/api/room-connection"); return await resp.json(); // { url, jwt } }, }); if (state === "authorizing" || state === "connecting") { return
Connecting...
; } if (state === "done" || !client) { return
Connection failed: {String(error)}
; } return
Connected to {client.roomName}
; } ``` `useRoomConnection` creates the `RoomClient`, starts it, and optionally enables messaging. If your React app also needs OAuth login, pair this with `@meshagent/meshagent-react-auth` for hook-based auth flows or `@meshagent/meshagent-ts-auth` for framework-agnostic auth helpers. ## Flutter Use `RoomConnectionScope` from `meshagent_flutter`: ```dart theme={null} import 'package:flutter/widgets.dart'; import 'package:meshagent/meshagent.dart'; import 'package:meshagent_flutter/meshagent_flutter.dart'; class SampleWidget extends StatelessWidget { const SampleWidget({ super.key, required this.projectId, required this.roomName, required this.url, required this.jwt, }); final String projectId; final String roomName; final Uri url; final String jwt; @override Widget build(BuildContext context) { return RoomConnectionScope( authorization: staticAuthorization( projectId: projectId, roomName: roomName, url: url, jwt: jwt, ), authorizingBuilder: (context) => const Center(child: CircularProgressIndicator()), connectingBuilder: (context, client) => const Center(child: Text('Connecting...')), builder: (context, client) => const Text('Connection established'), doneBuilder: (context, error) => Text('Connection ended with error: $error'), enableMessaging: true, ); } } ``` `RoomConnectionScope` manages authorization, connection state, reconnect behavior, and disposal for you. ## When to use which helper * Use **React `useRoomConnection`** in web apps built around React hooks. * Use **Flutter `RoomConnectionScope`** in Flutter apps where you want connection state to drive the widget tree. ## What to do next Once the room is connected, you can: * render messages and participants * call agents or tools * open documents with [Document Connections](./document_connection_scope) * use the runtime APIs documented in [Room API](../room_api/overview) # UI SDKs Source: https://docs.meshagent.com/flutter/ui_overview Build your own MeshAgent UI with the React and Flutter SDK packages. MeshAgent UI SDKs are for building your own application on top of MeshAgent rooms, documents, and agent interactions. They are different from [MeshAgent Accounts](../interfaces/accounts), [MeshAgent Studio](../interfaces/meshagent_studio), and [Powerboards](../interfaces/powerboards). Those are product interfaces. The UI SDKs are developer packages you use inside your own app. ## What exists today * **React** * `@meshagent/meshagent-react` for room and document connection hooks, chat helpers, toolkits, and file upload helpers * `@meshagent/meshagent-ts-auth` for framework-agnostic OAuth/PKCE login, token storage, and refresh helpers * `@meshagent/meshagent-react-auth` for React auth helpers built on top of the TypeScript auth package, including `useAuth` and `useEnsureLogin` * **Flutter** * `meshagent_flutter` for room and document connection widgets and related helpers * `meshagent_flutter_auth` for auth helpers * `meshagent_flutter_widgets` for higher-level Flutter widgets ## Core building blocks The two most important primitives are: * **Room connections**: establish and hold a `RoomClient` connection inside your app * **Document connections**: open a room document and keep it in sync while your UI is mounted Those patterns exist in both React and Flutter: * React exports hooks such as `useRoomConnection` and `useDocumentConnection` * Flutter exports widgets such as `RoomConnectionScope` and `DocumentConnectionScope` ## How to use this section 1. Start with [Room Connections](./room_connection_scope) to connect your app to a room. 2. Use [Document Connections](./document_connection_scope) when your UI needs a live room document. 3. Use the [Room API](../room_api/overview) docs for the runtime capabilities available after the connection is established. ## Which package to pick * Use **React** when you are building a web app and want hooks around the MeshAgent JS client. * Add **`@meshagent/meshagent-ts-auth`** when you want provider-agnostic auth helpers outside React. * Add **`@meshagent/meshagent-react-auth`** when your React app should handle OAuth login, callback exchange, token refresh, and profile loading with hooks. * Use **Flutter** when you want one codebase across mobile, desktop, or embedded form factors. In both cases, the app model is the same: your backend mints a participant token, your UI connects to a room with that token, and then your UI uses the room runtime from there. For the broader cross-language SDK map, see [SDK Overview](../reference/sdk_reference). # MeshAgent Accounts Source: https://docs.meshagent.com/interfaces/accounts Manage projects, members, billing, and usage across your MeshAgent account. [MeshAgent Accounts](https://accounts.meshagent.com) is the account and project-management interface for MeshAgent. Use it when you need to manage the parts of MeshAgent that live above any one room: * projects * project members and roles * billing and AI credits * usage reports MeshAgent Accounts works alongside [MeshAgent Studio](./meshagent_studio) and [Powerboards](./powerboards). Studio is the developer workspace. Powerboards is the end-user room experience. MeshAgent Accounts is where you manage account and project administration. ## What it is for * Create and switch between projects. * Manage project members and roles. * View project balance and add credits. * Configure auto-recharge and an optional monthly auto-recharge budget. * Review usage reports for a project. ## How it relates to the other interfaces * Use **MeshAgent Accounts** for project membership, billing, and usage. * Use **MeshAgent Studio** for rooms, services, routes, mailboxes, secrets, sessions, and developer workflows. * Use **Powerboards** for end-user room experiences and install flows. Although MeshAgent Accounts is its own app, the resources you manage there are still mostly project-scoped. Billing, usage, and members are selected per project, not shared globally across every project in your account. If a project uses [MeshAgent LLM Proxy](../agents/routing/llm_proxy), the related provider usage and proxy surcharge roll up into that project's billing and usage views. ## Open the app Go to [accounts.meshagent.com](https://accounts.meshagent.com). ## Related docs * [Project Roles and Access](../project_admin/project_roles) * [Billing and Usage](../project_admin/billing) * [MeshAgent Studio](./meshagent_studio) * [Powerboards](./powerboards) # Desktop Apps Source: https://docs.meshagent.com/interfaces/desktop_apps Download the production MeshAgent Studio and Powerboards desktop apps. MeshAgent Studio and Powerboards are available as desktop apps for macOS and Windows. Use these links to install the production versions. ## MeshAgent Studio | Platform | Download | | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | macOS | [Download MeshAgent Studio for macOS](https://storage.googleapis.com/meshagent-desktop-builds/studio/mac/Meshagent%20Studio.dmg) | | Windows | [Download MeshAgent Studio for Windows](https://storage.googleapis.com/meshagent-desktop-builds/studio/windows/meshagent-studio.appinstaller) | ## Powerboards | Platform | Download | | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | macOS | [Download Powerboards for macOS](https://storage.googleapis.com/meshagent-desktop-builds/powerboards/mac/Powerboards.dmg) | | Windows | [Download Powerboards for Windows](https://storage.googleapis.com/meshagent-desktop-builds/powerboards/windows/powerboards.appinstaller) | ## Related * [MeshAgent Studio](./meshagent_studio) * [Powerboards](./powerboards) * [Product Interfaces](./overview) # MeshAgent Studio Source: https://docs.meshagent.com/interfaces/meshagent_studio [MeshAgent Studio](https://studio.meshagent.com) is the browser-based workspace for building, testing, and operating MeshAgent projects. With [MeshAgent Studio](https://studio.meshagent.com) you can: * Create projects and rooms and jump between them. * Inspect [sessions](../room_api/sessions) (logs, traces, metrics) for live debugging. * Create and rotate [API keys](../project_admin/api_keys). * Manage room-scoped and project-scoped [services](../services/deployment/deploy_services). * Manage project registries, [routes](../project_admin/routes), [scheduled tasks](../project_admin/scheduled_tasks), [mailboxes](../project_admin/mailboxes), [feeds](../project_admin/feeds), [integrations](../project_admin/integrations), and [OAuth clients](../project_admin/oauth). * Inspect files, messages, datasets, memory, images, containers, services, and terminals inside a room. * Open [billing](../project_admin/billing) when a project needs more credits. ## Project selector and account menu MeshAgent Studio opens to an active project. Use the dropdown in the upper-left corner to switch between projects you belong to or create a new one. Use the menu in the upper-right corner to sign out. Admins may also see an **Account management** entry that opens [MeshAgent Accounts](./accounts). ## Project navigation The main project sidebar and available actions depend on your project role: * **Everyone**: **Rooms**, [**Feeds**](../project_admin/feeds), [**LLM Proxy**](../agents/routing/llm_proxy) * **Developers and Admins**: [**Sessions**](../room_api/sessions), **Registries**, [**Routes**](../project_admin/routes), [**Scheduled Tasks**](../project_admin/scheduled_tasks), [**Mailboxes**](../project_admin/mailboxes), [**System Services**](../services/deployment/deploy_services) * **Admins and focused project roles**: create and management actions for services, routes, scheduled tasks, mailboxes, and [**OAuth Clients**](../project_admin/oauth) * **Admins only**: [**API Keys**](../project_admin/api_keys), [**Integrations**](../project_admin/integrations) Some project pages are opened contextually instead of living in the permanent sidebar. For example, Studio links to **Billing** when a project is out of credits or after checkout flows. ## Rooms Use rooms to isolate agent runtime environments. Rooms are secure environments where humans and agents can collaborate and share context. Rooms can have their own services, scheduled tasks, routes, mailboxes, and feed subscriptions. From the MeshAgent Studio UI you can: * **Create** a room with **New Room** when your project role allows room creation * Toggle between **My Rooms** and **All Rooms**. **All Rooms** is available to developers and admins. * Open a room from the list to enter its workspace. * Use the room menu to open **Edit**, **Services**, **Scheduled Tasks**, **Mailboxes**, **Feeds**, **Routes**, **Permissions**, or **Delete**. ## Sessions Monitor and debug live and recent room sessions. A session starts when a room starts and stops when the room stops. For the API and data model behind what you see here, see [Sessions](../room_api/sessions). From the **Sessions** page you can: * Create a session with **New Session** * Toggle between **Active Sessions** and **Recent Sessions** * Open a session to inspect **Logs**, **Traces**, and **Metrics** * Stop an active session from the row menu ## Room Workspace (inside a Room) From both **Rooms** and **Sessions** you can open the **Room Workspace**. This is where you develop, test, and debug agents and tools. Opening a room starts or joins a live session. Room-scoped services remain available to the room beyond any single session. ### Layout * **File Browser (left)**: Browse room files. Depending on your permissions, you can create folders and text files, upload and download files, and remove files. * **File Previews (center)**: Open documents, code, tables, markdown notes, memory viewers, and other room resources in tabs. * **Messaging (right)**: Chat with human and agent participants in the room. * **Developer Console (bottom)**: Live debugging tabs for **Logs**, **Traces**, **Metrics**, **Images**, **Containers**, **Services**, and **Terminal**. The container-related tabs serve different jobs: * **Images** shows images already pulled or built for the room runtime. * **Containers** shows running and stopped room containers, along with logs and runtime actions. ### Room Menu (upper left) * **Leave Room**: Exit the room and return to the project view * **Call Agent**: Invoke a room-connected agent directly * **Toolkits**: View available tools and toolkits in the room and invoke them directly * **Queues**: View room queues and the number of messages in each queue * **Dataset**: Open the room dataset and work with tables * **Memory**: Open room memory viewers * **Room Services**: View, add, remove, and update services tied to this room * **Scheduled Tasks**: Manage tasks that enqueue work on a schedule * **Mailboxes**: Manage mailboxes that route into this room * **Feeds**: Manage visible feeds and storage subscriptions for this room * **Routes**: Manage domains that route to room service ports or serve room content * **Keychain**: Review and manage user-owned credentials as the new secret workflows roll out * **View Toggles**: Show/hide File Browser, File Previews, Messaging, and Developer Console ## API Keys Issue and rotate project-scoped credentials used by automations, CI, and services that call MeshAgent APIs. See [API Keys](../project_admin/api_keys) for the full reference. You can: * Create, relabel, and revoke keys * Track when a key was created for audit and rotation ## System Services Services turn your agents, toolkits, or connectors into reusable building blocks. Project-wide services are managed from the **System Services** page. Room-scoped services are managed on the room itself, either from the room list or from inside the **Room Workspace**. For deployment flows and service packaging, see [Service YAML](../services/deployment/deploy_services). From **System Services** you can: * Inspect what’s deployed to the project * Create, update, or remove deployed services * Change the **Room Server Version** if you need to pin a project to a specific version of MeshAgent or return to `latest` Service inspection is available to users with service inventory access. Creating services requires the project `service_creator` role, and updating or deleting services requires `service_manager`. ## Integrations Bring your own model routing and observability settings. See [Integrations](../project_admin/integrations) for the full configuration reference: **LLM provider settings** * Use MeshAgent-managed routing by default, or configure your own provider credentials and base URLs for providers such as OpenAI and Anthropic. * Services, coding agents, and compatible SDK clients can use [MeshAgent LLM Proxy](../agents/routing/llm_proxy) to route requests through those project settings. **Telemetry (OTEL)** * Export room/runtime metrics and traces by providing an OTEL endpoint and optional bearer token. * Optionally configure an OTEL filter endpoint before MeshAgent processes and forwards telemetry. ## LLM Proxy Open [**LLM Proxy**](../agents/routing/llm_proxy) from the project navigation when you want the project's provider-compatible base URLs or want to inspect routed usage for your own account. From this page you can: * open the **About** tab to copy the OpenAI-compatible and Anthropic-compatible base URLs * open the **My Usage** tab to inspect your routed LLM usage for the current project * open the main LLM Proxy docs from the built-in **Read docs** link ## OAuth Create OAuth2/OIDC clients to enable MeshAgent to sign in for your apps. A client is used to identify a single app to MeshAgent's OAuth servers. OAuth client actions require the project OAuth client inventory, creator, or manager roles. See [OAuth Clients](../project_admin/oauth) for the full setup flow. * Register a client with redirect URIs, scopes, grant types, and response types. * Create, edit, and delete clients from the project. ## Routes Use **Routes** to map project or room traffic to the right room. See [Routes](../project_admin/routes) for the full route model and setup details. From this page you can inspect routes, and users with route creator or manager access can create, edit, refresh, and delete routes, including domains that target service ports or content in room storage. ## Scheduled Tasks Use **Scheduled Tasks** to enqueue work on a schedule. See [Scheduled Tasks](../project_admin/scheduled_tasks) for the full behavior and examples. From this page you can inspect scheduled tasks, and users with scheduled task creator or manager access can create tasks at the project or room level, edit schedules, toggle tasks on or off, and delete tasks that are no longer needed. ## Mailboxes Provision room-scoped mailboxes that agents can read from or send through. See [Mailboxes](../project_admin/mailboxes) for the full setup flow: * Inspect mailboxes, or create mailboxes and assign them to rooms when you have mailbox creator or manager access * Map incoming mail to queues so worker agents can process it asynchronously * Edit or delete mailboxes when your routing changes ## Feeds Use **Feeds** to manage project feeds and room storage subscriptions. See [Feeds](../project_admin/feeds) for the full model and examples: * Inspect feeds, or create feeds and choose visibility, schema validation, and paused state when you have feed creator access * Publish a single JSON message or import a JSONL file into a feed * Open a room-scoped **Feeds...** view to manage which feed subscriptions deliver into that room * Inspect subscriptions that write feed batches into room storage paths ## Billing Billing is available through direct Studio flows when a project needs attention, but the underlying billing surface lives in [MeshAgent Accounts](./accounts). From the billing page you can: * View current credit balance and spend * Purchase credits * Configure automatic recharge ## Next Steps * Follow the [Quickstart](../introduction/cli_quickstart) to create your first project, room, and agent from the CLI. * When you are ready for production, read [Service YAML](../services/deployment/deploy_services) to write and deploy service manifests. # Interfaces Overview Source: https://docs.meshagent.com/interfaces/overview How MeshAgent Accounts, MeshAgent Studio, and Powerboards fit together. MeshAgent provides three main human-facing interfaces: * [MeshAgent Accounts](https://accounts.meshagent.com) for projects, members, billing, and usage. See [docs](./accounts). * [MeshAgent Studio](https://studio.meshagent.com) for developers and operators. See [docs](./meshagent_studio). * [Powerboards](https://app.powerboards.com) for end users working with agents in rooms. See [docs](./powerboards). All three are part of the same MeshAgent account and project model. That means a room is not "in Studio" or "in Powerboards." It is the same room either way. You might manage the project in Accounts, build and debug it in Studio, then open that same room in Powerboards for a cleaner end-user experience. ## When to use each interface **[MeshAgent Accounts](https://accounts.meshagent.com)** * Create or switch projects. * Manage project members and roles. * View billing, credits, auto-recharge, and usage reports. * Docs: [MeshAgent Accounts](./accounts) **[MeshAgent Studio](https://studio.meshagent.com)** * Create and organize projects and rooms. * Build, test, and debug agents, tools, and services. * Inspect room sessions with logs, traces, and metrics. * Manage services, secrets, routes, mailboxes, feeds, and other project controls. * Docs: [MeshAgent Studio](./meshagent_studio) **[Powerboards](https://app.powerboards.com)** * Start quickly with built-in agents. * Install shared agents and services into rooms. * Give non-technical users a focused UI for chat, voice, documents, and files. * Depending on room grants, open the developer console and inspect logs, traces, and metrics. * Use deployed room experiences without exposing the full project-administration surface by default. * Docs: [Powerboards](./powerboards) ## How they work together The usual split looks like this: 1. Create or choose a project in Accounts, Studio, or the CLI. 2. Use Accounts for members, billing, and usage. 3. Use Studio and the CLI to build, test, deploy, and inspect what runs in rooms. 4. Use Powerboards when you want people to install or use agents in a simpler end-user interface. This is also why the same room can be useful to different people in different interfaces: * an admin can manage members and billing in Accounts * a developer can inspect logs and traces in Studio * a room member can talk to the agent and work with room files in Powerboards * both are working against the same room state, services, documents, and data ## Next steps * [MeshAgent Accounts](https://accounts.meshagent.com) * [MeshAgent Accounts docs](./accounts) * [MeshAgent Studio](https://studio.meshagent.com) * [MeshAgent Studio docs](./meshagent_studio) * [Powerboards](https://app.powerboards.com) * [Powerboards docs](./powerboards) * [Quickstart](../introduction/cli_quickstart) # Powerboards Source: https://docs.meshagent.com/interfaces/powerboards Share agents and services with end users through a polished UI. Powerboards is the end-user-facing interface for MeshAgent. It is included with your MeshAgent account, it is open source, and it connects to the same underlying projects and rooms as [MeshAgent Studio](./meshagent_studio). To sign in and open your rooms, go to [app.powerboards.com](https://app.powerboards.com). Powerboards is room-first. It is designed around talking to agents, working with room files, and using installed experiences without exposing the full project administration surface by default. The same room can be opened in Powerboards for end-user workflows and in Studio for development and operations. ## What Powerboards is for * Provide a clean UI for chat, threads, meetings, documents, and files. * Let non-technical users run agents with one click. * Share repeatable installs for the same service across rooms. * Keep the same room reachable from an end-user focused interface, even if that room is also being inspected in Studio. ## How it works Powerboards includes a built-in directory of prebuilt agents you can install into a room, including: * **assistant**, a general-purpose room assistant for chat, files, and thread-based workflows that can be configured with either GPT or Claude * **voice**, a voice-first agent experience for live spoken interaction, meetings, and room-level voice controls * **transcriber**, a meeting transcription experience that joins a room session, captures speech, and writes the transcript back into the room context Depending on which built-in experience you install, Powerboards can expose editable rules, voice controls, thread-based chat, meetings, or other room-specific configuration. Powerboards also works with custom services and MCP-based installs. The main patterns are: 1. **Install a built-in agent** Open a room, choose one of the built-in options, and install it directly from Powerboards. 2. **Deploy a custom service to a room or project** Build the service, define the YAML, then deploy it with [MeshAgent Studio](./meshagent_studio) or the CLI. Once that service is available to the room, it shows up in Powerboards automatically. 3. **Share a `ServiceTemplate` install link** Host a `ServiceTemplate` YAML at a public URL, then share a link in the form `https://app.powerboards.com/install?url=...`. Powerboards downloads the template, prompts for any required variables, and installs it into the selected room. 4. **Install from an MCP server URL** The installer can also take an MCP server URL directly. Powerboards will try to discover an installable MCP service template from that URL and then walk the user through setup. In every case, the result is still a service installed into a room. Powerboards is the interface for using that room experience after it is installed. ## Install links and shared distribution If you want other people to install an experience into their own rooms, the main path is a Powerboards install link. The flow is: 1. Define a `ServiceTemplate`. 2. Host it at a public URL, such as a raw GitHub Gist URL. 3. Share a link in the form `https://app.powerboards.com/install?url=...`. 4. Powerboards signs the user in, lets them choose a project and room, collects any required variables, and deploys the service. Users do not need the CLI for this flow. They can open the link, choose where to install it, and start using the service from Powerboards. If you are distributing an MCP integration instead of a hosted template, users can also start from the Powerboards installer and paste the MCP server URL directly. ## What users can do * Chat or talk to agents in a room. * Work in thread-based conversations and collaborate with other participants. * Browse, upload, and work with room files when storage access is available. * Use tools exposed by the service. * View and edit documents generated by agents. * Join meetings or voice experiences when the room supports them. Depending on the room grants and room ownership: * users may be able to open the developer console and inspect logs, traces, and metrics * room owners may be able to install or remove agents * users may be able to view or update room permissions That is the main difference from [MeshAgent Studio](./meshagent_studio): Powerboards stays centered on the room experience itself, while Studio exposes the broader developer and project-management surface. If a room grant includes developer-log access, Powerboards can also expose a developer console inside the same room. ## Room rules and shared customization Powerboards can also expose editable room-scoped rules for agents. Some built-in installs, such as `assistant` and `voice`, use an editable `rules.md` file in room storage so room members can steer behavior together. When you build your own agents, you can choose whether rules are: * fixed inline in the service definition * baked into the image * editable in room storage with `--room-rules` That matters because Powerboards is not just a place to chat with an agent. It can also be the place where room members adjust the behavior of that agent together. ## Next steps * [Service YAML](../services/deployment/deploy_services) * [Interfaces Overview](./overview) # Quickstart Source: https://docs.meshagent.com/introduction/cli_quickstart Install MeshAgent, connect the CLI, run your first agent, and deploy it. MeshAgent is a platform for building, deploying, and operating room-based agent systems. If you want to start with built-in agents, you can start in [Powerboards](../interfaces/powerboards) instead. Powerboards is included with your MeshAgent account. Sign in, create a project and room, install one of the built-in agents, and start using it. This guide walks you through installing the MeshAgent CLI and deploying your first agent. ## Step 1: Install the MeshAgent CLI Choose the installation path that matches how you plan to work. ### Option 1: Install globally ```bash macOS theme={null} brew tap meshagent/homebrew-meshagent brew trust --formula meshagent/homebrew-meshagent/meshagent brew install meshagent # To install a specific version: # brew install meshagent@[version] meshagent --help ``` ```bash Windows theme={null} choco install meshagent # To install a specific version: # choco install meshagent --version=[version] meshagent --help ``` ```bash Linux theme={null} pipx install "meshagent[cli]" --include-deps pipx ensurepath # To install a specific version: # pipx install "meshagent[cli]==[version]" --include-deps meshagent --help ``` **To update:** ```bash macOS theme={null} brew update brew upgrade meshagent ``` ```bash Windows theme={null} choco upgrade meshagent ``` ```bash Linux theme={null} pipx upgrade meshagent ``` ### Option 2: Install in a Python environment If you are developing with the Python SDK, you can install the CLI in your project environment instead. If you need help setting up Python and `uv`, start with the [Machine Setup Guide](../reference/machine_setup). ```bash pip theme={null} pip install "meshagent[cli]" # or "meshagent[all]" ``` ```bash uv theme={null} uv add "meshagent[cli]" # or "meshagent[all]" ``` If you install MeshAgent in a Python virtual environment, you can prefix the commands below with `uv run` instead of activating the environment first. For the full command reference, see [MeshAgent CLI Commands](../reference/meshagent_cli_help). ## Step 2: Connect the CLI to MeshAgent and activate a project Authenticate in the browser and run the setup flow: ```bash bash theme={null} meshagent setup ``` `meshagent setup` signs you in, or if you are already signed in lets you continue with the current account or switch accounts, then lets you choose or create a project and activates the project for the CLI. If Codex or Claude are installed, setup can also configure them to use MeshAgent for the active project, reuse or update existing MeshAgent integrations, or remove them when you want to switch back. At the end of setup, the TUI asks whether you want to create a sample MeshAgent application. Choose that option when you want the guided sample app wizard. It opens the same scaffolding flow as `meshagent create`. By default MeshAgent provides OpenAI and Anthropic access for the project through MeshAgent-managed routing. You do not need to add your own OpenAI or Anthropic keys first unless you want the project to use your own provider accounts. If setup or later CLI commands behave unexpectedly, run: ```bash bash theme={null} meshagent doctor meshagent doctor --fix ``` `meshagent doctor` checks common local configuration issues. `meshagent doctor --fix` applies the fixes the doctor can safely make for you. ## Step 3: Choose a starting path You can start from a generated app or run a room-connected process directly. ### Option A: Scaffold a sample app Use `meshagent create` when you want a deployable sample application that already includes MeshAgent wiring for one of the supported SDKs and app patterns: ```bash bash theme={null} meshagent create my-meshagent-app ``` The interactive wizard lets you choose the SDK language and app focus. For non-interactive use, pass both values: ```bash bash theme={null} meshagent create my-python-agent \ --language python \ --focus backend-agent ``` Use this path when you want to start from a sample app and then customize the generated project. ### Option B: Run an agent with `meshagent process` Use `meshagent process` when you want to start a room-connected agent directly from the CLI. Continue below to create a room, connect an agent identity, and optionally deploy it. **Create a room and mailbox** If you chose the `meshagent process` path, create the room you will use for this guide now. If you already created a room in the MeshAgent Studio or Powerboards UI, you can reuse it here: ```bash bash theme={null} meshagent rooms create gettingstarted --if-not-exists ``` This example uses chat, mail, queue, and toolkit channels. Before starting the agent, create the mailbox for the mail channel: ```bash bash theme={null} # You will need to create a unique email address meshagent mailbox create \ --address my-first-agent@mail.meshagent.com \ --room gettingstarted \ --queue my-first-agent@mail.meshagent.com ``` **Start your first agent** `meshagent process` is the main CLI path for running a room-connected agent. This example starts one agent identity with all four primary channels: * `chat` * `mail:EMAIL` * `queue:NAME` * `toolkit:NAME` ```bash bash theme={null} meshagent process join \ --room gettingstarted \ --agent-name my-first-agent \ --channel chat \ --channel mail:my-first-agent@mail.meshagent.com \ --channel queue:my-first-agent \ --channel toolkit:my-first-agent \ --threading-mode default-new \ --thread-dir ".threads/my-first-agent" \ --model gpt-5.4 \ --web-search \ --storage \ --rule "You are a helpful first agent. Answer clearly, use web search when needed, and save important artifacts to storage." ``` This keeps the agent running from your terminal. Press `Ctrl+C` when you want to stop it. **Talk to the agent in MeshAgent Studio** 1. Open [MeshAgent Studio](https://studio.meshagent.com/). 2. Join the `gettingstarted` room. 3. In the participants tab, select `my-first-agent`. 4. Send it a message and ask it to do something that uses the tools you enabled. At this point you have a live room-connected agent running through the CLI. You can also open the same room in [Powerboards](https://powerboards.com) if you want to use an end-user-facing UI instead of Studio. Studio and Powerboards both connect to the same underlying room. **Try the other channels** You can now reach the same agent through queue, mail, and toolkit entry points. Send work through the queue: ```bash bash theme={null} meshagent room queue send \ --room gettingstarted \ --queue my-first-agent \ --json '{"prompt":"Summarize the current room activity and save a note."}' ``` Invoke the toolkit channel: ```bash bash theme={null} meshagent room agents invoke-tool \ --room gettingstarted \ --toolkit my-first-agent \ --tool run_my_first_agent_task \ --arguments '{"prompt":"Draft a short welcome message for a new customer."}' ``` You can also email the agent at `my-first-agent@mail.meshagent.com`. **Deploy the agent as a managed service** Running the agent locally is the fastest way to test it. When you want it to stay available without keeping your terminal open, deploy it as a service. The fastest path is to deploy it directly from `meshagent process`: ```bash bash theme={null} meshagent process deploy \ --room gettingstarted \ --service-name my-first-agent \ --agent-name my-first-agent \ --channel chat \ --channel mail:my-first-agent@mail.meshagent.com \ --channel queue:my-first-agent \ --channel toolkit:my-first-agent \ --model gpt-5.4 \ --web-search \ --storage ``` If you want to inspect or customize the service manifest first, generate it and deploy it yourself: ```bash bash theme={null} meshagent process spec \ --service-name my-first-agent \ --agent-name my-first-agent \ --channel chat \ --channel mail:my-first-agent@mail.meshagent.com \ --channel queue:my-first-agent \ --channel toolkit:my-first-agent \ --model gpt-5.4 \ --web-search \ --storage > meshagent.yaml # Deploy as a room service meshagent service create --file meshagent.yaml --room gettingstarted # Deploy as a project service meshagent service create --file meshagent.yaml --global ``` **Inspect and manage what you deployed** Use these commands to inspect the project and the services you now have running: ```bash bash theme={null} # List projects meshagent project list # Activate a different project meshagent project activate -i # List project services meshagent service list # List services in a room meshagent service list --room gettingstarted # View service details meshagent service get ``` ## Next steps * [Process Agents Overview](../agents/process/overview): learn how `meshagent process` works and how to shape rules, tools, channels, and threads * [Powerboards](../interfaces/powerboards): learn how end users can work with deployed and built-in agents * [Rooms](../room_api/overview): learn the room runtime and built-in room APIs * [Service YAML](../services/deployment/deploy_services): write service manifests and configure permissions * [MeshAgent CLI Commands](../reference/meshagent_cli_help): browse the full CLI reference # Key Concepts Source: https://docs.meshagent.com/introduction/introduction What MeshAgent is, the core concepts to know, and how the main product surfaces fit together. # MeshAgent [MeshAgent](https://www.meshagent.com) is the platform for building, deploying, and operating **room-based agent systems**. A **room** is the runtime and collaboration boundary where humans, agents, tools, services, and shared state work together. Instead of treating every agent interaction as an isolated run, MeshAgent gives you a live workspace with built-in infrastructure, deployment surfaces, and product interfaces around that room. If you want commands you can copy and run, start with [Quickstart](./cli_quickstart). This page is the short mental model for everything else in the docs. Most agent products give you one part of the stack: model access, a sandbox, an orchestration loop, or a chat surface. MeshAgent gives you the full operating surface for collaborative agent applications: rooms, agents, built-in runtime APIs, deployable services, developer tooling, end-user interfaces, permissions, and observability. If you want agents that can do real work with people, data, documents, queues, mail, tools, and custom code without stitching together your own runtime, that is what MeshAgent is for. Every MeshAgent account includes [MeshAgent Accounts](../interfaces/accounts), [MeshAgent Studio](../interfaces/meshagent_studio), and [Powerboards](../interfaces/powerboards). They share the same underlying projects and rooms, but each surface is optimized for a different kind of work. ## Why teams use MeshAgent * **Rooms as the center of the system**: Every room has shared context, participants, built-in APIs, and runtime behavior in one place. * **Built-in infrastructure**: Storage, dataset, queues, sync/documents, containers, messaging, and developer events are already part of the room runtime. * **Agents that can do more than chat**: Run agents across chat, mail, queues, toolkit calls, and other room-connected workflows. * **One platform from local testing to production**: Use the CLI and MeshAgent Studio to iterate quickly, then deploy the same capabilities as project or room services. * **Developer and end-user surfaces**: Developers build and inspect in [MeshAgent Studio](../interfaces/meshagent_studio). End users can work with agents in [Powerboards](../interfaces/powerboards), and both surfaces can reach the same rooms. * **Fast start or full customization**: Start with built-in agents in Powerboards or MeshAgent Studio, or bring and build your own agents, tools, and services. * **Governance and observability built in**: Control access, scope permissions, inspect logs and traces, and understand usage and cost without bolting on a separate control plane. ## What MeshAgent includes * **[Rooms](../room_api/overview)** with built-in runtime APIs for messaging, storage, dataset, queues, documents, containers, and developer events * **[Agents](../agents/overview)** that can work across chat, mail, queues, toolkit calls, and other room-connected workflows * **[Services](../services/intro)** you can deploy at the project or room level * **[MeshAgent Accounts](../interfaces/accounts)** for project membership, billing, and usage * **[MeshAgent Studio](../interfaces/meshagent_studio)** for developers and operators * **[Powerboards](../interfaces/powerboards)** for end users working with agents in rooms * **[CLI and SDKs](../reference/sdk_reference)** for local development, automation, and custom applications ## Core concepts ### [Project](../project_admin/projects) A **project** is the top-level container for related work in MeshAgent. Projects group: * rooms * members and roles * API keys and credentials * deployed services * routes, mailboxes, and scheduled tasks * billing and other project-level settings Most administrative and deployment actions happen at the project level. ### [Room](../room_api/overview) A **room** is the runtime and collaboration boundary in MeshAgent. It is the place where humans, agents, tools, services, files, queues, and shared documents come together around the same live context. Rooms belong to projects, and each room can have its own participants, room-scoped services, and persisted state. Rooms become active on demand, provision the runtime they need for that session, and shut down automatically when idle. That means they scale with usage rather than staying running all the time. ### [Session](../room_api/sessions) A **session** is one active run of a room. When a room becomes active, MeshAgent starts a session for that room. During the session, participants connect, services run, and logs, traces, metrics, and events are recorded. When activity stops, the room shuts down automatically. ### Participant A **participant** is anything that joins a room and takes part in the runtime. Participants can be: * humans * agents * services * tools exposed into the room Participants run with identities and permissions that control what they can access. See [Participant Tokens](../rest_api/participant_tokens) and [API Scopes](../rest_api/api_scopes). ### [Agent](../agents/overview) An **agent** is a room-connected participant that receives work, uses tools and room capabilities, and produces results back into the room. Agents can: * answer in chat * consume queued work * handle mail * be invoked by other agents * run locally during development or be deployed as services For agent workflows, MeshAgent uses [`meshagent process`](../agents/process/overview). ### [Tool / Toolkit](../agents/tools/tools_and_toolkits) A **tool** is a callable capability an agent can use to take action. A **toolkit** is a group of related tools exposed together. MeshAgent supports built-in tools, custom tools, MCP-based tools, and toolkit-style agents that can be invoked by other agents. ### [Skills](../agent_skills/overview) A **skill** is reusable guidance that helps an agent handle a class of tasks better. Skills are not callable tools. They are playbooks the agent can discover and apply when relevant. In practice, skills often tell the agent which tools to use, what files to inspect, and how to structure the output. ### [Threads](../agents/threads_overview) A **thread** is the continuity boundary for agent work. Threads let an agent keep related work together without mixing unrelated conversations or jobs into the same history. This is especially important for agents that work across chat, queues, mail, and toolkit calls. ### [Service](../services/intro) A **service** is how code is packaged and deployed into MeshAgent. Services can package: * agents * tools and toolkits * connectors and integrations * supporting application logic Services can be **MeshAgent-native** for deeper room integration or **external** when MeshAgent is routing to something you host elsewhere. Once deployed, a service can be made available across a project or scoped to a specific room. ### [Project Services and Room Services](../services/intro) A **project service** is available across the project. A **room service** is scoped to one room. Use project services for shared capabilities that should be broadly available. Use room services for room-specific or user-specific behavior. Choose that scope when you deploy the service. ### [Room APIs](../room_api/overview) The **Room APIs** are the built-in runtime capabilities available inside a room. These include: * messaging * storage * dataset * queues * sync/documents * containers * secrets * developer events and logs They are the main way agents, services, and humans interact with room infrastructure. ### [Interfaces](../interfaces/overview) An **interface** is a product surface people use to work with MeshAgent. Today the main interfaces are: * **[MeshAgent Accounts](../interfaces/accounts)** for project membership, billing, and usage * **[MeshAgent Studio](../interfaces/meshagent_studio)** for developers building, testing, deploying, and inspecting * **[Powerboards](../interfaces/powerboards)** for end users interacting with deployed agents ## How the system fits together 1. Work starts inside a **project**. 2. People and services create or join a **room**. 3. When the room becomes active, MeshAgent starts a **session**, provisions the room runtime, and starts the services that should run there. 4. Humans and agents use the room's built-in APIs and shared state to do work together. 5. [MeshAgent Accounts](../interfaces/accounts), [MeshAgent Studio](../interfaces/meshagent_studio), and [Powerboards](../interfaces/powerboards) give different kinds of users access to the same underlying projects and rooms. The important boundary is the room. That is where runtime state, live collaboration, room APIs, room-scoped services, and participant permissions come together. ## What MeshAgent lets you build * custom agents and tools that work with teams over shared context * customer-facing agents you can ship in Powerboards or your own UI * document-heavy workflows where agents and people need to read, write, and coordinate over the same data * multi-agent systems that combine chat, background queues, mail, toolkit calls, and scheduled work * custom applications where agents need real runtime capabilities, not just prompt wrappers ## Where to go next * [**Quickstart**](./cli_quickstart): install MeshAgent, connect the CLI, run your first agent, and deploy it * [**Rooms**](../room_api/overview): explore the room runtime and built-in APIs * [**Agents & Tools**](../agents/overview): learn how agents work in MeshAgent * [**Deploy & Manage**](../services/deployment/deploy_services): package, deploy, observe, and manage services * [**Interfaces**](../interfaces/overview): see how Studio and Powerboards fit together # Custom Logs, Traces, and Metrics Source: https://docs.meshagent.com/observability/custom_telemetry Add your own OpenTelemetry spans, logs, and metrics inside a MeshAgent service or room-connected toolkit. MeshAgent already gives you logs, traces, metrics, session data, and developer logs in MeshAgent Studio. Use this page when you want to add your own spans, logs, and metrics inside a custom Python service or room-connected toolkit. For the built-in observability model first, see [Observability](./overview). ## Enable telemetry in your process Call `otel_config()` once at process startup: ```python Python theme={null} from meshagent.otel import otel_config otel_config(service_name="weather-service") ``` When this code runs inside MeshAgent, `otel_config()` uses the injected `OTEL_ENDPOINT` and room/session environment to send telemetry to MeshAgent Studio. ## Example: Weather Toolkit with custom instrumentation The example adds custom spans around validation, the external HTTP call, and response parsing. It also adds logs and metrics. ```python Python theme={null} import asyncio import logging import httpx from meshagent.agents import SingleRoomAgent from meshagent.otel import otel_config from meshagent.tools import FunctionTool, ToolContext, Toolkit from opentelemetry import metrics, trace from opentelemetry.trace import Status, StatusCode # Configure OpenTelemetry otel_config(service_name="weather_tools") log = logging.getLogger(__name__) tracer = trace.get_tracer(__name__) meter = metrics.get_meter(__name__) # Counters calls = meter.create_counter( "weather.calls", unit="1", description="Total weather tool invocations" ) errors = meter.create_counter( "weather.errors", unit="1", description="Errors during execution" ) class WeatherTool(FunctionTool): def __init__(self): super().__init__( name="get_weather", title="Weather Tool", description="Get current weather for a city using wttr.in API", input_schema={ "type": "object", "additionalProperties": False, "required": ["city", "units"], "properties": { "city": {"type": "string", "description": "City name"}, "units": { "type": "string", "enum": ["metric", "imperial"], "description": "Units the temperature will be returned in", }, }, }, ) async def execute(self, context: ToolContext, *, city: str, units: str): """ This shows custom instrumentation that meshagent doesn't do automatically: 1. Separate spans for validation, API call, parsing 2. Custom attributes (API endpoint, response size) 3. Events for important moments (rate limits etc.) 4. Error handling with span status """ log.info(f"Weather tool is running for city: {city} with units: {units}") calls.add(1, attributes={"city": city.lower(), "units": units}) # Custom span for input validation with tracer.start_as_current_span("validate_input") as span: span.set_attribute("city", city) if not city or len(city) < 2: span.set_status(Status(StatusCode.ERROR, "Invalid city name")) span.add_event("validation_failed", {"reason": "city too short"}) return {"error": "City name must be at least 2 characters"} span.add_event("validation_passed") # Custom span for external API call with tracer.start_as_current_span("fetch_weather_api") as span: # Add attributes about the API call api_url = f"https://wttr.in/{city}?format=j1" span.set_attribute("http.url", api_url) span.set_attribute("http.method", "GET") span.set_attribute("api.provider", "wttr.in") span.add_event("api_request_start") try: async with httpx.AsyncClient(timeout=10.0) as client: response = await client.get(api_url) # Record response attributes span.set_attribute("http.status_code", response.status_code) span.set_attribute("http.response_size", len(response.content)) if response.status_code == 429: span.add_event("rate_limit_exceeded") span.set_status(Status(StatusCode.ERROR, "Rate limited")) return {"error": "Rate limit exceeded, try again later"} response.raise_for_status() data = response.json() span.add_event( "api_request_success", { "data_keys": list(data.keys()), }, ) except httpx.TimeoutException: span.set_status(Status(StatusCode.ERROR, "API timeout")) span.add_event("api_timeout") errors.add(1, attributes={"kind": "timeout", "city": city.lower()}) return {"error": "Weather service timeout"} except Exception as e: errors.add( 1, attributes={"kind": type(e).__name__, "city": city.lower()} ) span.set_status(Status(StatusCode.ERROR, str(e))) span.add_event("api_error", {"error_type": type(e).__name__}) return {"error": f"Failed to fetch weather: {str(e)}"} # Custom span for parsing and formatting with tracer.start_as_current_span("parse_response") as span: try: current = data["current_condition"][0] location = data["nearest_area"][0] if units == "metric": temperature = current["temp_C"] degrees_in = "°C" elif units == "imperial": temperature = current["temp_F"] degrees_in = "°F" else: log.warning( f"Units {units} is not a valid unit. Must use metric or imperial" ) return {"error": "Invalid units: must be 'metric' or 'imperial'"} result = { "city": location["areaName"][0]["value"], "country": location["country"][0]["value"], "temperature": temperature, "units": degrees_in, "description": current["weatherDesc"][0]["value"], "humidity": current["humidity"], "wind_speed": current["windspeedKmph"], } # Record what we parsed span.set_attribute("parsed_fields", len(result)) span.add_event("parse_success") return result except (KeyError, IndexError) as e: span.set_status(Status(StatusCode.ERROR, "Parse failed")) span.add_event("parse_error", {"error": str(e)}) errors.add(1, attributes={"kind": "parse_error"}) return {"error": "Failed to parse weather data"} class WeatherToolkit(Toolkit): def __init__(self): super().__init__( name="weather-toolkit", title="Weather Toolkit", description="Tools for getting weather information", tools=[WeatherTool()], ) class WeatherAgent(SingleRoomAgent): async def get_exposed_toolkits(self) -> list[Toolkit]: return [WeatherToolkit()] async def main() -> None: agent = WeatherAgent(title="weather-toolkit-host") await agent.run() if __name__ == "__main__": asyncio.run(main()) ``` ### Custom spans Use spans to track specific operations inside a trace. This example records: * `execute.weather-toolkit.get_weather`, which MeshAgent creates for the overall tool call * `validate_input` for city and units validation * `fetch_weather_api` for the outbound HTTP request, including attributes such as `http.url`, `http.method`, `http.status_code`, and `http.response_size` * `parse_response` for the final response shaping step This gives you finer-grained visibility inside the spans MeshAgent already creates. **Pattern:** ```python Python theme={null} from opentelemetry import trace from opentelemetry.trace import Status, StatusCode tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("fetch_weather_api") as span: span.set_attribute("http.url", api_url) span.add_event("api_request_start") ... if resp.status_code == 429: span.set_status(Status(StatusCode.ERROR, "Rate limited")) ``` These spans appear in the room's **Traces** tab. ### Custom logs `otel_config()` sets up an OTEL logging handler so normal `logging` calls are captured too. ```python Python theme={null} import logging log = logging.getLogger(__name__) log.info(f"Weather tool is running for city: {city} with units: {units}") ``` These logs appear in the room's **Logs** tab. ### Custom metrics You can also add counters and histograms to track trends over time. ```python Python theme={null} from opentelemetry import metrics meter = metrics.get_meter("weather.tools") calls = meter.create_counter("weather.calls", unit="1", description="Total weather tool invocations") # When a call starts calls.add(1, attributes={"city": city.lower(), "units": units}) ``` These metrics appear in the room's **Metrics** tab. ## Deploy the sample You can run this toolkit locally with `meshagent room connect`, deploy it as a service, and invoke `get_weather()` from Studio or the CLI. ### Run it locally During development, run the toolkit with `meshagent room connect` so MeshAgent provides the room token, room name, LLM proxy credentials, and telemetry environment: ```bash bash theme={null} meshagent rooms create gettingstarted --if-not-exists meshagent room connect --room=gettingstarted --identity=weather-toolkit -- python3 observability.py ``` ### Step 1: Package and deploy the room service Package the sample with a `meshagent.yaml` file and a container image that MeshAgent can run. For the general deployment flow, see [Service YAML](../services/deployment/deploy_services). This example uses a MeshAgent runtime image plus a lightweight code image. The default YAML points at the public `python-docs-examples` image so you can run the docs example without building your own image first. Project structure: ```bash theme={null} your-project/ ├── Dockerfile # Shared by all samples ├── observability/ │ ├── observability.py │ └── meshagent.yaml # Config specific to this sample └── another_sample/ # Other samples follow same pattern ├── another_sample.py └── meshagent.yaml ``` If you are building a single tool, you only need the `observability/` folder. ### Step 1a: Build a Docker image Create a scratch Dockerfile and copy the files you want to run: ```dockerfile Dockerfile theme={null} FROM scratch COPY . / ``` Build and push the image: ```bash bash theme={null} docker buildx build . \ -t "//:" \ --platform linux/amd64 \ --push ``` ### Step 1b: Define the service Create a `meshagent.yaml` file that references: * Runtime image: The MeshAgent Python SDK image with all dependencies * Code mount: Your code-only image mounted at /src * Command path: Points to your sample's specific location * Participant token: Injects `MESHAGENT_TOKEN` for the room-connected toolkit process ```yaml Yaml theme={null} kind: Service version: v1 metadata: name: otel-example description: "An example weather tool with otel instrumentation" container: image: "us-central1-docker.pkg.dev/meshagent-public/images/python-sdk:{SERVER_VERSION}-esgz" command: python /src/observability/observability.py environment: - name: MESHAGENT_TOKEN token: identity: weather-toolkit role: agent storage: images: # Replace this image tag with your own code-only image if you build one. - image: "us-central1-docker.pkg.dev/meshagent-public/images/python-docs-examples:{SERVER_VERSION}" path: /src read_only: true ``` Path mapping: * Your code image contains `/observability/observability.py` * It's mounted at `/src` in the runtime container * The command runs `python /src/observability/observability.py` The default YAML in the docs uses `us-central1-docker.pkg.dev/meshagent-public/images/python-docs-examples` so you can test this example immediately without building your own image first. Replace this with your own image tag when deploying your code. ### Step 1c: Deploy the service From the directory that contains `meshagent.yaml`: ```bash theme={null} meshagent service create --file "meshagent.yaml" --room=gettingstarted ``` ### Step 2: Invoke the tool Once the service is deployed, invoke the tool from MeshAgent Studio or the CLI. You can also invoke the tool using the MeshAgent CLI: ```bash bash theme={null} meshagent room agents invoke-tool \ --room=gettingstarted \ --toolkit=weather-toolkit \ --tool=get_weather \ --arguments='{"city":"Costa Mesa","units":"imperial"}' ``` ## View telemetry In [MeshAgent Studio](https://studio.meshagent.com), you can inspect the telemetry from this example in both the **Session** view and the **Developer Console**. After you invoke the weather tool, the **Traces** tab should show a tree like: ``` execute.weather-toolkit.get_weather ├─ validate_input ├─ fetch_weather_api └─ parse_response ``` Logs and metrics appear under their respective tabs. ## Next Steps * [Observability](./overview): understand the built-in telemetry model and where to inspect it in MeshAgent Studio * [Agents](../agents/overview): understand how agents work in MeshAgent and start building your first one * [Tools and Toolkits](../agents/tools/tools_and_toolkits): learn how tools are discovered, shared, and called inside a MeshAgent room * [Service YAML](../services/deployment/deploy_services): write service manifests for instrumented agents and tools # Observability Source: https://docs.meshagent.com/observability/overview Understand what MeshAgent captures automatically, where to inspect it, and how to add custom telemetry in your own services. MeshAgent uses [OpenTelemetry](https://opentelemetry.io/) for traces, logs, and metrics. Observability is built into MeshAgent. When a room is active, MeshAgent records the runtime activity for that session and exposes it in MeshAgent Studio. You do not need to set up your own telemetry pipeline just to get basic visibility into what happened in a room. ## What you get automatically Out of the box, MeshAgent gives you: * **Logs, traces, and metrics** for room activity, agents, tool calls, and service execution * **Session data** for each room run, including room lifecycle events and recorded runtime activity * **Project-level usage views** for cost, activity, and latency summaries in MeshAgent Studio ## Where to inspect it ### Developer Console Inside a room in [MeshAgent Studio](../interfaces/meshagent_studio), the **Developer Console** gives you the live view while the room is running. That is where you inspect: * logs * traces * metrics * related runtime surfaces such as containers and services ### Session Viewer Use the **Session** view when you want to inspect one completed or active room run in a more focused way. Sessions preserve the telemetry and events for that runtime period, which makes them the right place to debug what happened in a specific run. For session-level details, see [Sessions](../room_api/sessions). ### Usage Use **Usage** in MeshAgent Studio when you want the project-level view across rooms and sessions, such as cost, activity, and latency summaries. ### Developer logs Developer logs are the room's structured live log stream. They are part of the room runtime rather than generic OTEL instrumentation. Use developer logs when you want to: * emit structured debug events from your own code * subscribe to live logs from a room * inspect room-specific debug output from the CLI or SDK The main entry points are: ```bash bash theme={null} meshagent room developer --room myroom ``` And from the Room API: ```python Python theme={null} await room.developer.log(type="info", data={"message": "hello"}) ``` For the full API, see [Developer API](../room_api/developer). ## Add telemetry in your own service You do not need `otel_config()` to see MeshAgent-managed room and session telemetry in Studio. Use it when you want telemetry from your own Python code to show up there too. If you are building a custom Python service or room client and want your own logs, traces, and metrics to appear alongside MeshAgent's built-in telemetry, call `otel_config()` once at startup: ```python Python theme={null} from meshagent.otel import otel_config otel_config(service_name="my-service") ``` When your code runs inside MeshAgent, deployed services and room runtimes receive `OTEL_ENDPOINT`, `MESHAGENT_PROJECT_ID`, `MESHAGENT_ROOM`, and `MESHAGENT_SESSION_ID`. `otel_config()` uses those values so your service telemetry is exported with the right project, room, and session tags. If you call `otel_config()` outside MeshAgent, it still configures logging, but traces and metrics are only exported if you provide an `OTEL_ENDPOINT` yourself. To change the log level: ```python Python theme={null} otel_config(service_name="my-service", level="DEBUG") ``` ## What gets tagged automatically When you use `otel_config()`, MeshAgent tags telemetry so it lands in the right room and aggregates cleanly at the project level. | Tag | Description | | -------------- | ------------------------------------ | | `project` | The current project ID | | `room` | The current room name | | `session` | The active session ID | | `service.name` | The name you pass to `otel_config()` | ## Next Steps * [Custom Logs, Traces, and Metrics](./custom_telemetry): add your own spans, logs, and counters inside a custom Python service * [Developer API](../room_api/developer): emit and stream structured room developer logs * [Sessions](../room_api/sessions): inspect session-level history and telemetry for a room run # API Keys Source: https://docs.meshagent.com/project_admin/api_keys Create and manage project-scoped credentials for automation and backend services. API keys are project-scoped credentials for backend services, CI, and automation that call MeshAgent APIs. Use them when a service or script needs to act on behalf of the project. Do not put them in end-user clients or use them as the user's sign-in credential. People using MeshAgent Studio or Powerboards sign in with MeshAgent directly. If you are building your own app on top of MeshAgent, use the API key on your backend, create an [OAuth client](./oauth) for user sign-in when needed, and issue [participant tokens](../rest_api/participant_tokens) to the client. ## Create a key You can create API keys in [MeshAgent Studio](../interfaces/meshagent_studio) or with the CLI. The secret value is only shown once. ### MeshAgent Studio 1. Open your project in MeshAgent Studio. 2. Go to **Access Management**. 3. Open a service account's **API Keys** menu. 4. Create a new key and save the secret value. ### MeshAgent CLI If you want to create a key from the terminal and activate it for local CLI use at the same time: ```bash theme={null} meshagent service-account api-key create my-service-key \ --service-account default \ --description "Used by the deploy pipeline" \ --activate ``` `--activate` saves the new key in your local CLI project settings so commands that use an API key can pick it up automatically. To activate an existing key later, use: ```bash theme={null} meshagent service-account api-key activate ``` ## Rotate or remove keys List the keys for a service account in the active project: ```bash theme={null} meshagent service-account api-key list --service-account default ``` Print the locally activated key id, or emit it as a shell export snippet: ```bash theme={null} meshagent service-account api-key get meshagent service-account api-key env ``` Delete a key you no longer need: ```bash theme={null} meshagent service-account api-key delete --service-account default ``` ## Best practices * **Rotate regularly** and delete unused keys. * **Store keys securely** in a secret manager or CI vault. * **Avoid sharing keys** across multiple services. ## Related docs * [OAuth Clients](./oauth) * [REST API Overview](../rest_api/overview) # Billing and Usage Source: https://docs.meshagent.com/project_admin/billing Manage project balance, auto-recharge, subscriptions, and usage. Billing and usage are project-scoped in MeshAgent. The main UI for them lives in MeshAgent Accounts, and MeshAgent Studio or Powerboards can link you into that same project billing surface. ## What you can manage * **Balance and credits** for the project. * **Auto-recharge** so the project does not stop when credits run low, with an optional monthly auto-recharge budget. * **Subscription and payment method** for the project account. * **Usage reports** so you can see how the project is consuming MeshAgent resources. If a project uses [MeshAgent LLM Proxy](../agents/routing/llm_proxy), its routed provider usage and the separate `llm_proxy_surcharge` line item show up in the same project billing and usage views. ## How MeshAgent Accounts fits in MeshAgent Accounts is the account and project-management surface for membership, billing, and usage. Even though you access it through an account-level interface, the actual billing settings and usage reports are still tied to a specific project. ## Who can access it * **Project admins** manage billing settings such as balance, credits, and auto-recharge. * **Developers** can view project usage. ## Where to manage it * Use MeshAgent Accounts for the primary billing and usage UI. * Use [MeshAgent Studio](../interfaces/meshagent_studio) or Powerboards when they link you into the same project billing surface. * Use the [REST API](../rest_api/overview) if you need to automate balance, usage, or checkout flows. ## Recommended practices * Add billing before you deploy production workloads. * Enable auto-recharge for production environments. * Set a monthly auto-recharge budget if you need a hard cap on automatic top-ups. * Review usage after new launches, model changes, or large service rollouts. ## Related docs * [MeshAgent Accounts](../interfaces/accounts) * [MeshAgent Studio](../interfaces/meshagent_studio) * [REST API Overview](../rest_api/overview) # Custom Domains Source: https://docs.meshagent.com/project_admin/custom_domains Authorize a domain, configure DNS, and assign it to MeshAgent routes. Custom Domains let a project use domains it owns for MeshAgent routes. A project can own multiple Custom Domain resources, and each resource can authorize either one hostname or a one-label wildcard. Custom Domains are separate from routes. A route still has exactly one `domain` field: ```yaml theme={null} version: v1 kind: Route metadata: name: docs domain: docs.example.com backend: room: name: docs paths: - path: / pathType: prefix targetPort: 8080 ``` There is no Custom Domain ID on the route. When a route is created or updated, MeshAgent matches its domain against an available Custom Domain in the same project and checks that the caller can use that resource. ## Exact and wildcard resources An exact resource such as `docs.example.com` authorizes only that hostname. A wildcard resource such as `*.example.com` authorizes one label below `example.com`, including `docs.example.com`, but not `example.com` or `api.docs.example.com`. The domain is the resource identifier and cannot be changed after creation. Delete the resource and create another one to use a different domain. MeshAgent rejects overlapping exact and wildcard resources so route authorization remains unambiguous. ## Create a Custom Domain ```bash theme={null} meshagent custom-domain create docs.example.com --project-id PROJECT_ID meshagent custom-domain get docs.example.com --project-id PROJECT_ID ``` The create and get responses contain the DNS authorization record. Add that record at your DNS provider exactly as returned. Certificate Manager uses the record to prove control of the domain. Keep the authorization CNAME in place so Google can renew the certificate. It must be the only record at its returned DNS name; do not add a TXT, A, or other record at that same validation name. For wildcard certificates, MeshAgent returns the authorization record under the parent domain as required by Certificate Manager. Do not point the application hostname at the MeshAgent Gateway until the response reports `available: true`. After the certificate is available, create the application DNS record returned by MeshAgent. It points the hostname at the dedicated Custom Domain Gateway and does not affect MeshAgent's stock route domains. Copy the returned routing records as a set: a deployment returns either one CNAME target or its A/AAAA address targets, never a CNAME alongside address records. ```bash theme={null} meshagent custom-domain list --project-id PROJECT_ID meshagent custom-domain delete docs.example.com --project-id PROJECT_ID ``` A Custom Domain cannot be deleted while a route uses the exact hostname or a hostname covered by its wildcard. ## Lifecycle and availability The API exposes the reconciled state rather than performing Google Cloud operations in the request path. A resource moves through these phases: * `pending_dns`: the DNS authorization record has not propagated yet. * `provisioning_certificate`: Google is issuing the managed certificate. * `provisioning_map_entry`: the certificate is being attached to the Gateway certificate map. * `available`: the certificate map entry is active and the domain can be assigned to a route. * `degraded`: provisioning previously succeeded but Google now reports an unhealthy resource. * `failed`: reconciliation failed; inspect `conditions` for the reason. * `deleting`: MeshAgent is deleting the map entry, certificate, and DNS authorization. `available` is true only when Certificate Manager reports an active certificate and serving map entry. DNS and certificate issuance can take time; clients should poll `get` with normal backoff. ## Permissions Custom Domains have direct `viewer`, `user`, and `admin` roles. Their effective permissions are: * `accessible`: list or view the resource. * `can_use`: assign a matching domain to a route. * `can_manage`: create access grants or delete the resource. * `can_inventory`: list all Custom Domains in the project. Project roles provide project-wide access: * `custom_domain_creator` * `custom_domain_inventory` * `custom_domain_manager` Creating a route requires normal route permissions and `can_use` on the matching Custom Domain. Updating a route performs the same check. Built-in MeshAgent route domains continue to use the existing route permissions only. ## IAP and cookies IAP continues to use the fixed MeshAgent API callback domain, so OAuth providers do not need a callback registration for every custom hostname. After authentication, MeshAgent transfers a short-lived token to the route's `/.meshagent/auth` endpoint and installs a secure, host-only cookie for that concrete hostname. Sessions are bound to the normalized route hostname. A session created for one custom hostname cannot be replayed on another hostname, including a sibling covered by the same wildcard. Production redirects must use HTTPS and must resolve to an active route. MeshAgent strips its IAP cookie before proxying a request to the application. ## REST API Custom Domain resources are addressed by their URL-encoded domain: ```text theme={null} POST /accounts/projects/{project_id}/custom-domains GET /accounts/projects/{project_id}/custom-domains GET /accounts/projects/{project_id}/custom-domains/{domain} DELETE /accounts/projects/{project_id}/custom-domains/{domain} ``` The domain is immutable, so there is no update endpoint for changing it. # Feeds Source: https://docs.meshagent.com/project_admin/feeds Create project feeds that validate JSON and fan out structured data into room storage. Feeds are project-level JSON distribution channels. Use them when you want to publish structured data once and have MeshAgent deliver it into room storage in one or more rooms. A feed is not a queue and it does not execute work inside a room. In MeshAgent, the feed is the project-side source of messages, and feed subscriptions define which rooms and storage paths receive those messages. ## How feeds work * Create a feed at the project level with a name, visibility, and optional message schema. * Add one or more subscriptions. Each subscription points to one room and one storage path prefix such as `feeds/orders/`. * Publish JSON messages to the feed one at a time or as a batch. * MeshAgent fans those messages out to every subscription and writes them into room storage as `.jsonl` files. * Delivery is batched for performance. A message can take up to about a minute to appear in room storage. The key distinction is that a feed does not deliver directly into room chat or a room queue. It writes structured files into room storage so agents, services, or operators in that room can consume them there. ## What a subscription does A feed subscription is the delivery rule for one room. * It connects one feed to one room. * It writes into one storage path prefix inside that room. * One feed can have multiple subscriptions, which lets you publish once and land the same data in multiple rooms. * The room and path are fixed after creation. If you want a different destination, recreate the subscription. Use `/` if you want the room root. For normal usage, pick a dedicated prefix such as `feeds/orders/` or `imports/events/` so feed output stays easy to inspect. ## When to use feeds Use feeds when you want to: * distribute structured JSON events into room storage * import external datasets or event streams into a room * fan the same data out to multiple rooms without writing your own delivery code * keep project-managed ingestion separate from room-local consumption Typical examples include syncing business events into ops rooms, importing records for an agent to process later, or delivering the same event stream into multiple rooms that each run their own analysis. ## When not to use feeds Use the nearby MeshAgent feature that matches the kind of delivery you need: | Need | Use | | --------------------------------------------------------- | ------------------------------------------------------------------- | | Land structured JSON files in room storage | **Feeds** | | Enqueue work for agents or workers to process immediately | [Queues](../room_api/queue) or [Scheduled Tasks](./scheduled_tasks) | | Route inbound email into a room | [Mailboxes](./mailboxes) | | Accept HTTP traffic into a room | [Routes](./routes) | If the consumer expects a queue message, use a queue. If the consumer expects files in room storage, use a feed. ## Create a feed You can manage feeds from [MeshAgent Studio](../interfaces/meshagent_studio), the CLI, or the SDKs. In Studio: * Open the project's **Feeds** page to create and manage feeds for the project. * Open **Feeds...** from a room menu when you want to see visible feeds for that room and manage that room's subscriptions. From the CLI, create the feed first: ```bash theme={null} meshagent feed create \ --name orders \ --description "Order events for room imports" \ --visibility project \ --message-schema-file order-event.schema.json ``` Then attach a room subscription: ```bash theme={null} meshagent subscription create \ --feed-id FEED_ID \ --room ops-room \ --path feeds/orders/ ``` Choose visibility carefully when you create the feed: * `public`: anyone who can see the feed can subscribe a room to it * `project`: any project member can read it and attach room subscriptions * `private`: only project developers can read it or manage subscriptions Visibility is a creation-time choice. In Studio and the public SDK surface, you do not change it later. ## Validate messages with a schema A feed can define an optional JSON schema for the messages it accepts. * If you leave the schema empty, the feed accepts any valid JSON value. * If you add a schema, MeshAgent validates every published message before delivery. * If a message does not match, the publish call fails and nothing is delivered for that message. This is useful when multiple tools or services publish into the same feed and you want a single contract for what is allowed to enter room storage. ## Publish messages Publish one JSON message: ```bash theme={null} meshagent feed send FEED_ID \ --message '{"id":123,"status":"paid"}' ``` Publish a batch from a JSONL file: ```bash theme={null} meshagent feed send-batch FEED_ID \ --jsonl-file orders.jsonl ``` Each line in the JSONL file is treated as one message. MeshAgent then batches feed delivery into `.jsonl` files in room storage. Paused feeds reject publishes and subscription changes. This gives you a clean way to stop new data from landing while you review or reconfigure downstream consumers. ## Use feeds from the SDKs The SDKs mirror the same lifecycle as Studio and the CLI: create the feed, add subscriptions, then publish messages. ```python Python theme={null} feed = await client.create_feed( project_id=project_id, name="orders", description="Order events for room imports", visibility="project", ) await client.create_feed_subscription( project_id=project_id, feed_id=feed.id, room="ops-room", path="feeds/orders/", filename_datetime_format="YYYY/MM/DD/hh_mm_ssZ", ) await client.publish_feed_message( project_id=project_id, feed_id=feed.id, message={"id": 123, "status": "paid"}, ) ``` ```typescript TypeScript theme={null} const feed = await client.createFeed({ projectId, name: "orders", description: "Order events for room imports", visibility: "project", }); await client.createFeedSubscription({ projectId, feedId: feed.id, room: "ops-room", path: "feeds/orders/", filenameDatetimeFormat: "YYYY/MM/DD/hh_mm_ssZ", }); await client.publishFeedMessage({ projectId, feedId: feed.id, message: { id: 123, status: "paid" }, }); ``` Set `filename_datetime_format` / `filenameDatetimeFormat` when you want the Cloud Storage subscription to bucket files by date. Slashes in the format become folders. Omit it to use the default `YYYY-MM-DDThh_mm_ssZ` filename prefix. ## Permissions * Developers create, update, delete, pause, resume, and publish feeds. * Feed visibility controls who can read a feed and who can attach room subscriptions to it. * Creating or changing a subscription still requires room-level permission on the target room. * Project members only see `public` and `project` feeds in shared feed listings. ## Related pages * [Projects](./projects) * [MeshAgent Studio](../interfaces/meshagent_studio) * [Queue API](../room_api/queue) * [Mailboxes](./mailboxes) * [Routes](./routes) # IAM Roles and Permissions Source: https://docs.meshagent.com/project_admin/iam_roles_and_permissions Every MeshAgent IAM principal, resource, role, and room API scope permission. MeshAgent IAM controls access to project resources. It answers four questions: * **Who** is requesting access: a user, group, agent, service account, or userset. * **What** they are accessing: a project, room, repository, feed, secret, service account, or other project resource. * **Which role** they have on that resource. * **Which room API scope** a participant token carries after access is granted. Use the smallest role or scope that lets the subject do its job. ## Principals | Principal type | Description | | ----------------- | ---------------------------------------------------------------------- | | `user` | A human project member. | | `group` | A group of users. Group access applies through the group's members. | | `agent` | A managed agent principal. | | `service_account` | A non-human identity used by services, jobs, API keys, and automation. | | `userset` | A reference to another resource relation, such as all project members. | ## Resources | Resource type | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `project` | The top-level project boundary. Project roles can grant project-wide create, inventory, manage, billing, LLM proxy, and group-management access. | | `room` | A room and its room-scoped APIs. | | `agent` | A managed agent resource. Managed agent resource policies are not set through the generic IAM policy API; agent run-as and project agent roles control this surface. | | `group` | A group and its membership. | | `repository` | A project image repository. | | `feed` | A feed and its publish/subscribe operations. | | `secret` | A user secret that can be proxied to a service account. | | `service_account` | A service account and the credentials or run-as permissions attached to it. | ## Project Roles Project roles apply at the project level. `owner` is assigned to the project owner. `admin` inherits owner-level administrative capabilities. `developer` inherits a focused operational subset. Direct, narrower roles can also be granted independently. | Role | Controls | What it allows | | ----------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `owner` | Project ownership | Owns the project and implicitly has project admin access. | | `member` | Project membership | Lets the subject act as a project member and be targeted by project-member access. | | `agent` | Project agent identity | Marks an agent as belonging to the project so it can be targeted by project-agent access. | | `service_account` | Project service account identity | Marks a service account as belonging to the project so it can be targeted by project service-account access. | | `admin` | Full project administration | Grants administrative project access and all project roles that are not core membership roles. | | `developer` | Operational project access | Grants developer access, including inventory/manage access for rooms, agents, repositories, feeds, service inventory, mailbox inventory, route inventory, scheduled task inventory, feed subscription inventory, LLM logger inventory, usage reporting, service account creation/inventory, and participant token creation. | | `room_creator` | Room creation | Create rooms. | | `room_inventory` | Room inventory | List and inspect room inventory across the project. | | `room_manager` | Room management | Manage rooms across the project. | | `session_inventory` | Session inventory | Inspect project session inventory. | | `agent_creator` | Managed agent creation | Create managed agents. | | `agent_inventory` | Managed agent inventory | List and inspect managed agent inventory. | | `agent_manager` | Managed agent management | Manage managed agents. | | `repository_creator` | Repository creation | Create project repositories. | | `repository_inventory` | Repository inventory | List and inspect repositories. | | `repository_manager` | Repository management | Manage repositories. | | `feed_creator` | Feed creation | Create feeds. | | `feed_inventory` | Feed inventory | List and inspect feeds. | | `feed_manager` | Feed management | Manage feeds. | | `oauth_client_creator` | OAuth client creation | Create project OAuth clients. | | `oauth_client_inventory` | OAuth client inventory | List and inspect project OAuth clients. | | `oauth_client_manager` | OAuth client management | Manage project OAuth clients. | | `api_key_creator` | API key creation | Create API keys. | | `api_key_inventory` | API key inventory | List and inspect API keys. | | `api_key_manager` | API key management | Manage API keys. | | `service_creator` | Service creation | Create deployed services. | | `service_inventory` | Service inventory | List and inspect deployed services. | | `service_manager` | Service management | Manage deployed services. | | `service_account_creator` | Service account creation | Create service accounts. | | `service_account_inventory` | Service account inventory | List and inspect service accounts. | | `service_account_manager` | Service account management | Manage service accounts. | | `participant_token_creator` | Participant token impersonation | Allow a service account to request a participant token for another user or service account by email. The target subject's room or agent permissions still apply. | | `mailbox_creator` | Mailbox creation | Create mailboxes. | | `mailbox_inventory` | Mailbox inventory | List and inspect mailboxes. | | `mailbox_manager` | Mailbox management | Manage mailboxes. | | `route_creator` | Route creation | Create routes. | | `route_inventory` | Route inventory | List and inspect routes. | | `route_manager` | Route management | Manage routes. | | `scheduled_task_creator` | Scheduled task creation | Create scheduled tasks. | | `scheduled_task_inventory` | Scheduled task inventory | List and inspect scheduled tasks. | | `scheduled_task_manager` | Scheduled task management | Manage scheduled tasks. | | `feed_subscription_creator` | Feed subscription creation | Create feed subscriptions. | | `feed_subscription_inventory` | Feed subscription inventory | List and inspect feed subscriptions. | | `feed_subscription_manager` | Feed subscription management | Manage feed subscriptions. | | `llm_logger_creator` | LLM logger creation | Create LLM loggers. | | `llm_logger_inventory` | LLM logger inventory | List and inspect LLM loggers. | | `llm_logger_manager` | LLM logger management | Manage LLM loggers. | | `llm_proxy_user` | Project LLM proxy use | Use the project LLM proxy and related OAuth proxy surfaces. | | `usage_reporter` | Usage reporting | Report or query project usage. | | `billing_manager` | Billing | Manage project billing. | | `group_manager` | Groups | Manage project groups. | Project membership APIs accept a `roles` list. The server normalizes project membership to include `member` and expands inherited `admin` and `developer` roles. Older member records and Studio convenience settings map to roles like this: | Setting | Expanded role effect | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `is_admin` | Grants `admin` plus every non-core creator, inventory, manager, billing, usage, group, and LLM proxy role. | | `is_developer` | Grants `developer`, room/agent/repository/feed manager roles, developer inventory roles, `service_account_creator`, `service_account_inventory`, `participant_token_creator`, and `usage_reporter`. The `developer` relation also qualifies for LLM proxy use in access checks. | | `can_create_rooms` | Grants `room_creator`, `mailbox_creator`, `route_creator`, and `scheduled_task_creator`. | | `can_create_agents` | Grants `agent_creator`. | | `can_use_llm_proxy` | Grants the direct `llm_proxy_user` role. | ## Room, Agent, and Repository Roles These roles apply to resource policies for rooms and repositories. They also describe the effective role set used for room and agent access decisions. | Role | Controls | What it allows | | ----------- | ---------------------------- | --------------------------------------------------------------------------------- | | `viewer` | Read-only resource access | View or connect to the resource with limited API scope. | | `operator` | Standard resource operation | Operate the resource with the standard user API scope. | | `developer` | Developer resource operation | Operate the resource with the agent-default API scope and developer capabilities. | | `admin` | Resource administration | Manage the resource and receive full room API scope where applicable. | | `list` | Resource discoverability | Include the resource in listings without granting full resource use by itself. | For rooms, `viewer`, `operator`, `developer`, and `admin` map to room API scopes: | Resource role | Room API scope | | ------------- | --------------------------------------------------------------------- | | `viewer` | Livekit access, read-only messaging list access, and service listing. | | `operator` | `ApiScope.user_default()`. | | `developer` | `ApiScope.agent_default(tunnels=True)` with admin config disabled. | | `admin` | `ApiScope.full()`. | ## Group Roles | Role | Controls | What it allows | | --------- | ---------------- | ---------------------------------------------------------------------------------------------------- | | `member` | Group membership | Makes the subject a member of the group. Group membership can be used anywhere the group has access. | | `manager` | Group management | Manage the group and its membership. Project `group_manager` also grants group-management access. | ## Feed Roles | Role | Controls | What it allows | | ------------ | -------------------- | -------------------------------------------------------------------------- | | `reader` | Feed read access | Read feed items. | | `subscriber` | Feed subscriptions | Subscribe to the feed and read feed items. | | `publisher` | Feed publishing | Publish feed items and read feed items. | | `manager` | Feed management | Manage the feed, publish, subscribe, and read. | | `list` | Feed discoverability | Include the feed in listings without granting publish or manage by itself. | ## Secret Roles | Role | Controls | What it allows | | ----------- | -------------------- | ------------------------------------------------------------------- | | `use_proxy` | User secret proxying | Allows a service account to use the proxied value of a user secret. | ## Service Account Roles | Role | Controls | What it allows | | ------------------- | --------------------------------- | ------------------------------------------------------ | | `list` | Service account listing | List or discover the service account. | | `run_service_as` | Service run identity | Run a service or managed agent as the service account. | | `secret_accessor` | Service account secret access | Access service account secret versions. | | `secret_manager` | Service account secret management | Manage service account secrets. | | `secret_list` | Service account secret listing | List service account secrets. | | `use_proxy_secrets` | Proxy secret use | Use proxied secrets attached to the service account. | ## OAuth Scopes OAuth scopes are token scopes, not OpenFGA resource roles. MeshAgent accepts the current scope names below for OAuth access tokens. Project and room wildcard scopes (`project/*`, `room/*`) still identify the project or room boundary for token checks. | Scope group | Scopes | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Profile | `profile:read`, `profile:write` | | Project and room boundary | `project/*`, `room/*` | | Users | `users:create`, `users:read`, `users:update`, `users:delete` | | Projects | `projects:read`, `projects:update`, `projects:iam.read`, `projects:iam.write`, `projects:billing.read`, `projects:billing.write` | | Rooms | `rooms:create`, `rooms:read`, `rooms:connect`, `rooms:update`, `rooms:delete` | | Managed agents | `agents:create`, `agents:read`, `agents:update`, `agents:delete`, `agents:run`, `agents:sessions.read` | | Mailboxes | `mailboxes:create`, `mailboxes:read`, `mailboxes:update`, `mailboxes:delete` | | Routes | `routes:create`, `routes:read`, `routes:update`, `routes:delete` | | Scheduled tasks | `scheduledTasks:create`, `scheduledTasks:read`, `scheduledTasks:update`, `scheduledTasks:delete` | | Services | `services:create`, `services:read`, `services:update`, `services:delete` | | Repositories | `repositories:create`, `repositories:read`, `repositories:update`, `repositories:delete` | | API keys | `apiKeys:create`, `apiKeys:read`, `apiKeys:delete` | | Service accounts | `serviceAccounts:create`, `serviceAccounts:read`, `serviceAccounts:update`, `serviceAccounts:delete` | | OAuth clients | `oauthClients:create`, `oauthClients:read`, `oauthClients:update`, `oauthClients:delete` | | LLM proxy and usage | `llm:invoke`, `llm:usage.read`, `llm:logs.read`, `llm:logs.write` | | Secrets | `secrets:read`, `secrets:write`, `secrets:delete`, `secrets:grant`, `secrets:proxy` | Current tokens also accept compatibility aliases used by older clients, such as `profile`, `create_rooms`, `connect_room`, `managed_agents`, `llm_proxy`, `developer`, and `admin`, when they map to the current scope names. ## Effective Permissions Effective permissions are the checks MeshAgent evaluates after combining direct resource roles with inherited project roles. You do not assign these directly; you grant the roles that satisfy them. | Permission | Applies to | Satisfied by | What it controls | | -------------------------- | -------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------- | | `room.can_use` | Rooms | `viewer`, `operator`, `developer`, or `admin` on the room | Whether the subject can use the room. | | `room.accessible` | Rooms | `list` or `room.can_use` | Whether the room is visible or otherwise accessible to the subject. | | `room.can_inventory` | Rooms | Project `room_inventory` | Whether the subject can inspect room inventory. | | `room.can_debug` | Rooms | Room `developer`, room `admin`, or project `room_manager` | Whether the subject can use room debugging surfaces. | | `room.can_manage` | Rooms | Room `admin` or project `room_manager` | Whether the subject can manage the room. | | `agent.can_use` | Managed agents | `viewer`, `operator`, `developer`, or `admin` on the agent | Whether the subject can use the agent. | | `agent.accessible` | Managed agents | `list` or `agent.can_use` | Whether the agent is visible or otherwise accessible to the subject. | | `agent.can_inventory` | Managed agents | Project `agent_inventory` | Whether the subject can inspect agent inventory. | | `agent.can_manage` | Managed agents | Agent `admin` or project `agent_manager` | Whether the subject can manage the agent. | | `repository.can_use` | Repositories | `viewer`, `operator`, `developer`, or `admin` on the repository | Whether the subject can use the repository. | | `repository.accessible` | Repositories | `list` or `repository.can_use` | Whether the repository is visible or otherwise accessible to the subject. | | `repository.can_inventory` | Repositories | Project `repository_inventory` | Whether the subject can inspect repository inventory. | | `repository.can_manage` | Repositories | Repository `admin` or project `repository_manager` | Whether the subject can manage the repository. | | `feed.can_read` | Feeds | `reader`, `subscriber`, `publisher`, or `manager` on the feed | Whether the subject can read feed items. | | `feed.accessible` | Feeds | `list` or `feed.can_read` | Whether the feed is visible or otherwise accessible to the subject. | | `feed.can_subscribe` | Feeds | Feed `subscriber` or `manager` | Whether the subject can subscribe to the feed. | | `feed.can_publish` | Feeds | Feed `publisher` or `manager` | Whether the subject can publish to the feed. | | `feed.can_inventory` | Feeds | Project `feed_inventory` | Whether the subject can inspect feed inventory. | | `feed.can_manage` | Feeds | Feed `manager` or project `feed_manager` | Whether the subject can manage the feed. | ## Room API Scope Permissions Room API scopes are embedded in participant tokens. They are not project roles. They control what a connected participant can call inside a room. If a grant object is absent, that API surface is denied. When a grant object exists, `None` in an allowlist generally means unrestricted access within that grant, and a boolean set to `false` disables that operation. ### `livekit` | Permission | Controls | What it does | | ------------------------ | ------------------------ | ----------------------------------------------------------------------------- | | `livekit.breakout_rooms` | Breakout room membership | `None` allows any breakout room. A list allows only the named breakout rooms. | ### `queues` | Permission | Controls | What it does | | ---------------- | ----------------- | ---------------------------------------------------------------------------- | | `queues.send` | Queue publishing | `None` allows sending to any queue. A list allows only the named queues. | | `queues.receive` | Queue consumption | `None` allows receiving from any queue. A list allows only the named queues. | | `queues.list` | Queue listing | Allows listing queues when `true`. | ### `messaging` | Permission | Controls | What it does | | --------------------- | ---------------------- | -------------------------------------------------- | | `messaging.broadcast` | Broadcast messages | Allows broadcasting messages to room participants. | | `messaging.list` | Message listing | Allows listing messages. | | `messaging.send` | Direct message sending | Allows sending messages. | ### `dataset` | Permission | Controls | What it does | | ---------------------------- | ------------------------- | ----------------------------------------------------------------------- | | `dataset.list_tables` | Dataset table listing | Allows listing dataset tables. | | `dataset.tables[].name` | Table selection | Names the table covered by the grant. | | `dataset.tables[].namespace` | Table namespace selection | Restricts the table grant to a namespace. `None` matches any namespace. | | `dataset.tables[].read` | Table reads | Allows reading matching tables. | | `dataset.tables[].write` | Table writes | Allows writing matching tables. | | `dataset.tables[].alter` | Table schema changes | Allows altering matching tables. | If `dataset.tables` is `None`, the participant may read, write, and alter every dataset table allowed by the grant. ### `sqlite` | Permission | Controls | What it does | | --------------------------------------- | ---------------------------- | -------------------------------------------------------------------------- | | `sqlite.create_database` | Database creation | Allows creating SQLite databases. | | `sqlite.list_databases` | Database listing | Allows listing SQLite databases. | | `sqlite.databases[].name` | Database selection | Names the database covered by the grant. | | `sqlite.databases[].namespace` | Database namespace selection | Restricts the database grant to a namespace. `None` matches any namespace. | | `sqlite.databases[].create_table` | Table creation | Allows creating tables in the matching database. | | `sqlite.databases[].drop` | Database deletion | Allows dropping the matching database. | | `sqlite.databases[].inspect` | Database inspection | Allows inspecting the matching database. | | `sqlite.databases[].list_tables` | Table listing | Allows listing tables in the matching database. | | `sqlite.databases[].execute` | SQL execution | Allows executing SQL against the matching database. | | `sqlite.databases[].tables[].database` | Table database selection | Names the database for a table-specific grant. | | `sqlite.databases[].tables[].table` | Table selection | Names the table covered by the table-specific grant. | | `sqlite.databases[].tables[].namespace` | Table namespace selection | Restricts the table grant to a namespace. `None` matches any namespace. | | `sqlite.databases[].tables[].read` | Table reads | Allows reading matching tables. | | `sqlite.databases[].tables[].write` | Table writes | Allows writing matching tables. | | `sqlite.databases[].tables[].alter` | Table schema changes | Allows altering matching tables. | If `sqlite.databases` is `None`, the participant may use all SQLite databases allowed by the grant. If a matching database grant has `tables: None`, table read, write, and alter access applies to all tables in that database. ### `memory` | Permission | Controls | What it does | | ---------------------------------------- | -------------------------- | ------------------------------------------------------------------------ | | `memory.list` | Memory listing | Allows listing memories. | | `memory.memories[].name` | Memory selection | Names the memory covered by the grant. | | `memory.memories[].namespace` | Memory namespace selection | Restricts the memory grant to a namespace. `None` matches any namespace. | | `memory.memories[].permissions.create` | Memory creation | Allows creating the matching memory. | | `memory.memories[].permissions.drop` | Memory deletion | Allows dropping the matching memory. | | `memory.memories[].permissions.inspect` | Memory inspection | Allows inspecting the matching memory. | | `memory.memories[].permissions.query` | Memory querying | Allows querying the matching memory. | | `memory.memories[].permissions.upsert` | Memory upserts | Allows upserting into the matching memory. | | `memory.memories[].permissions.ingest` | Memory ingestion | Allows ingesting content into the matching memory. | | `memory.memories[].permissions.recall` | Memory recall | Allows recall operations on the matching memory. | | `memory.memories[].permissions.optimize` | Memory optimization | Allows optimizing the matching memory. | If `memory.memories` is `None`, the participant may use all memories allowed by the grant. ### `sync` | Permission | Controls | What it does | | ------------------------ | ------------------- | ----------------------------------------------------------------- | | `sync.paths[].path` | Sync path selection | Allows matching paths. A path may end with `*` to match a prefix. | | `sync.paths[].read_only` | Sync write access | When `true`, matching paths can be read but not written. | If `sync.paths` is `None`, the participant may read and write all sync paths allowed by the grant. ### `storage` | Permission | Controls | What it does | | --------------------------- | ---------------------- | -------------------------------------------------------- | | `storage.paths[].path` | Storage path selection | Allows paths that start with the configured prefix. | | `storage.paths[].read_only` | Storage write access | When `true`, matching paths can be read but not written. | If `storage.paths` is `None`, the participant may read and write all storage paths allowed by the grant. ### `containers` | Permission | Controls | What it does | | --------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `containers.use_containers` | Container API use | Enables container operations when `true`. | | `containers.logs` | Container logs | Allows reading container logs when `true`. | | `containers.pull` | Image pull allowlist | `None` allows pulling any image tag. A list allows exact tags or prefixes ending in `*`. | | `containers.run` | Image run allowlist | `None` allows running any image tag. A list allows exact tags or prefixes ending in `*`. | | `containers.registry.list` | Registry repository listing | `None` allows listing repositories implied by pull, run, or write access. A list allows exact repositories or prefixes ending in `*`. | | `containers.registry.pull` | Registry pull access | `None` allows pulling any repository. A list allows exact repositories or prefixes ending in `*`. | | `containers.registry.run` | Registry run access | `None` allows running any repository. A list allows exact repositories or prefixes ending in `*`. | | `containers.registry.write` | Registry write access | `None` allows writing any repository. A list allows exact repositories or prefixes ending in `*`. | If `containers.registry` is absent, registry list, pull, run, and write checks allow any repository covered by the container grant. ### `developer` | Permission | Controls | What it does | | ---------------- | -------------- | -------------------------------------------- | | `developer.logs` | Developer logs | Allows developer log forwarding when `true`. | ### `agents` | Permission | Controls | What it does | | --------------------------------- | ---------------------------- | -------------------------------------------------------------------------- | | `agents.register_agent` | Agent registration | Allows registering agents. | | `agents.register_public_toolkit` | Public toolkit registration | Allows registering public toolkits. | | `agents.register_private_toolkit` | Private toolkit registration | Allows registering private toolkits. | | `agents.call` | Agent calls | Allows invoking the Agents API. | | `agents.use_agents` | Agent use | Allows using agents. | | `agents.use_tools` | Tool use | Allows using tools. | | `agents.allowed_toolkits` | Toolkit allowlist | `None` allows all toolkits. A list restricts access to the named toolkits. | ### `llm` | Permission | Controls | What it does | | ------------ | --------------- | --------------------------------------------------------------------------------------------------------- | | `llm.models` | Model allowlist | `None` allows any provider/model. A list allows exact `provider/model` entries or prefixes ending in `*`. | ### `admin` | Permission | Controls | What it does | | -------------- | ------------------------ | -------------------------------------------------------------- | | `admin.config` | Room admin configuration | Allows using the room admin configuration surface when `true`. | ### `secrets` | Permission | Controls | What it does | | ---------- | --------------------- | --------------------------------------------------------------------------------------- | | `secrets` | Secret grant presence | Enables room API routes that require the secrets grant. The grant has no nested fields. | ### `tunnels` | Permission | Controls | What it does | | --------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `tunnels.ports` | Tunnel port allowlist | `None` or an empty list allows any port. A non-empty list allows only the listed ports. If `tunnels` is absent, tunnels are denied. | ### `services` | Permission | Controls | What it does | | --------------- | --------------- | ------------------------------------------------ | | `services.list` | Service listing | Allows listing services in the room when `true`. | ## Built-in Room API Scope Presets | Preset | Grants | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ApiScope.user_default()` | Livekit, queues, messaging, dataset, SQLite, memory, sync, storage, containers, developer logs, agents, and service listing. It excludes LLM, admin config, secrets, and tunnels. | | `ApiScope.agent_default()` | Same core access as `user_default()` plus LLM. It excludes admin config, secrets, and tunnels unless called as `ApiScope.agent_default(tunnels=True)`. | | `ApiScope.full()` | Livekit, queues, messaging, dataset, SQLite, memory, sync, storage, containers, developer logs, agents, LLM, admin config, tunnels, and service listing. | ## Managing IAM Use MeshAgent Studio for day-to-day member management. Use the CLI or SDKs when provisioning access from automation. ```bash theme={null} meshagent iam policy --project-id --resource-type room --resource-id meshagent iam grant --project-id --resource-type room --resource-id \ --subject-type user --subject-id --role viewer meshagent iam revoke --project-id --resource-type room --resource-id \ --subject-type user --subject-id --role viewer ``` ## Related Guides * [Project Roles and Access](./project_roles) * [API Keys](./api_keys) * [Participant Tokens](../rest_api/participant_tokens) * [API Scopes](../rest_api/api_scopes) # Integrations Source: https://docs.meshagent.com/project_admin/integrations Configure project-level model routing, telemetry export, and other shared project settings. Integrations are shared project settings that rooms and services in the project can use. Use them when you want to set provider credentials and base URLs once at the project level, export telemetry from MeshAgent, or configure advanced project-level routing and admission behavior. If you plan to use [MeshAgent LLM Proxy](../agents/routing/llm_proxy), you do not need to start here. By default MeshAgent provides OpenAI and Anthropic access through MeshAgent-managed routing. Open **Integrations** when you want to switch the project to your own OpenAI or Anthropic credentials or override the upstream base URLs. ## What you can configure * **LLM provider settings**: project-level OpenAI and Anthropic API keys and optional base URLs used by [MeshAgent LLM Proxy](../agents/routing/llm_proxy), coding agents, and other compatible clients * **Telemetry**: OTEL export settings and an optional OTEL filter endpoint used for observability export * **Room admission controller**: an advanced external endpoint, when your deployment supports it, that can intercept room connection attempts and customize how admission is handled ## Where to manage integrations Use [MeshAgent Studio](../interfaces/meshagent_studio) to manage integrations. Most projects only need the LLM provider settings or telemetry settings. The room admission controller is an advanced deployment feature. For LLM usage, there are two common cases: * stay on MeshAgent-managed routing, which is the default * add your own OpenAI or Anthropic credentials here if you want the project to route through your own provider accounts instead ## Related docs * [Projects](./projects) * [MeshAgent LLM Proxy](../agents/routing/llm_proxy) * [Observability](../observability/overview) * [Custom Logs, Traces, and Metrics](../observability/custom_telemetry) # Mailboxes Source: https://docs.meshagent.com/project_admin/mailboxes Create and manage project mailboxes that route email into rooms and queues. Mailboxes are project-level email addresses that route inbound mail into rooms. They belong at the project level because the address belongs to the project, even though the work is delivered to a queue in a specific room. Use mailboxes when an agent listens on a `mail:` channel, or when you want inbound email to land in a queue that something in the room already consumes. ## Create a mailbox ```bash theme={null} meshagent mailbox create \ --address support@mail.meshagent.com \ --room customer-support \ --queue support-inbox ``` This creates a project mailbox and routes messages sent to `support@mail.meshagent.com` into the `support-inbox` queue in the `customer-support` room. ## Inspect and manage mailboxes ```bash theme={null} meshagent mailbox list meshagent mailbox get support@mail.meshagent.com meshagent mailbox update support@mail.meshagent.com --queue escalations meshagent mailbox delete support@mail.meshagent.com ``` ## Inspect outbound delivery status When Mailgun delivery tracking is enabled for the deployment, inspect each recipient's current status and provider event timeline: ```bash theme={null} meshagent mailbox deliveries support@mail.meshagent.com meshagent mailbox delivery support@mail.meshagent.com DELIVERY_ID meshagent mailbox delivery-events support@mail.meshagent.com DELIVERY_ID ``` The delivery list is newest submission first. A submission with multiple recipients has one delivery row per recipient because their outcomes and retry timelines can differ. Use `--status`, `--recipient`, or `--message-id` to narrow the list, and use `--output json` when calling the commands from a script: ```bash theme={null} meshagent mailbox deliveries support@mail.meshagent.com \ --status deferred \ --recipient example.com \ --output json meshagent mailbox delivery-events support@mail.meshagent.com DELIVERY_ID \ --count 100 \ --offset 0 \ --output json ``` ### Delivery statuses and events A delivery is the current rollup for one recipient. Its `status` is one of: | Status | Meaning | | ----------- | --------------------------------------------------------- | | `accepted` | The provider accepted the message for delivery. | | `deferred` | A delivery attempt failed temporarily and may be retried. | | `delivered` | The provider reported successful delivery. | | `failed` | The provider reported a permanent delivery failure. | The delivery also contains the latest provider details, including `attempt_count`, SMTP response codes, failure reason and description, MX host, and TLS and certificate-verification results when the provider supplies them. Delivery events are the chronological history behind that current status. The API normalizes provider notifications into these event types: | Event type | Resulting delivery status | | ------------------ | ------------------------- | | `accepted` | `accepted` | | `temporary_failed` | `deferred` | | `delivered` | `delivered` | | `permanent_failed` | `failed` | Each event includes `occurred_at` and `received_at`, its resulting `status`, and the provider and provider event ID. When available, it also includes the attempt number, SMTP and enhanced SMTP codes, reason, description, MX host, TLS use, and certificate-verification result. Events are returned oldest first, ordered by `occurred_at` and then event ID. In Studio, open the mailbox options menu and select **Deliveries...**. Select a delivery row to open its event timeline. ## Permissions * To create, update, or delete a mailbox for a room, you need permission to administer that room. * To list mailboxes across the whole project, you need developer access. * To read delivery status as a user, you need the OAuth scope `mailboxes:read` and the project `mailbox_inventory` relation. Room membership and room read access do not grant delivery visibility. Project API keys retain project-wide access. ## Where to manage mailboxes * Use [MeshAgent Studio](../interfaces/meshagent_studio) for the main UI flow. * Use the CLI when you want quick setup or scripting. * Use the [REST API](../rest_api/overview) when you need programmatic mailbox management. ## Related pages * [Feeds](./feeds) * [Process Agents Overview](../agents/process/overview) * [Queue API](../room_api/queue) * [Quickstart](../introduction/cli_quickstart) * [REST API](../rest_api/overview) # OAuth Clients Source: https://docs.meshagent.com/project_admin/oauth Create project-owned OAuth clients for your app and connect them to participant-token issuance. OAuth clients are the project-level auth configuration for your own application. Use them when you want users to sign in to your app through MeshAgent, then connect to rooms with the right participant tokens and room grants. Project OAuth client management is controlled by the project OAuth-client roles: `oauth_client_creator`, `oauth_client_inventory`, and `oauth_client_manager`. Project admins receive those roles. Do not use OAuth clients for backend automation or CI. Use [API Keys](./api_keys) for that. You do not need an OAuth client for MeshAgent Studio, Powerboards, or normal CLI sign-in. Those flows use MeshAgent's built-in auth. ## How OAuth clients work The flow is: 1. Create an OAuth client for the project. 2. Send the user through that OAuth flow from your app. 3. After sign-in, your backend decides which rooms the user should access. 4. Your backend mints [participant tokens](../rest_api/participant_tokens) for those rooms. 5. Your app connects to the room with that token. The OAuth client handles user sign-in. The participant token handles room access. ## Set up an OAuth client Use [MeshAgent Studio](../interfaces/meshagent_studio) for the main UI flow. 1. Open **OAuth Clients** in your project. 2. Create a new client. 3. Enter a **name** for the app. 4. Add one or more **redirect URIs**. 5. Choose the **grant types** and **response types** your app uses. 6. Set the **scopes** your app should request. 7. Save the client and copy the **client ID** and **client secret**. The client secret is only shown when the client is created. Store it in your backend secret manager before you close the dialog. ## What the fields mean * **Name**: a label for the app in MeshAgent Studio * **Redirect URIs**: the callback URLs MeshAgent can send users back to after sign-in * **Grant types**: the OAuth flows your app is allowed to use, such as `authorization_code`, `refresh_token`, or `client_credentials` * **Response types**: the response formats your app expects from the OAuth flow, such as `code`, `token`, or `id_token` * **Scopes**: the OAuth scopes returned in tokens for this client, such as `profile:read`, `rooms:connect`, `llm:invoke`, or `secrets:proxy` For project-level LLM proxy access, include the `llm:invoke` scope. OAuth-authenticated requests to the MeshAgent OpenAI or Anthropic proxy also require `Meshagent-Project-Id: ` and a user whose project role satisfies `llm_proxy_user`, such as a developer, admin, or member with direct LLM proxy access. If you use `authorization_code`, you need at least one redirect URI. ## Typical setup For a typical app with a backend: * use `authorization_code` * add `refresh_token` if you want long-lived sign-in sessions * add your callback URL as a redirect URI * request the scopes your app actually needs After the user signs in, keep using your backend for room access. The backend should mint the [participant tokens](../rest_api/participant_tokens) your client uses to join rooms. ## REST API and SDKs Use the [REST API](../rest_api/overview) or SDKs when you want to provision clients programmatically. OAuth clients live under the project: * `POST /accounts/projects/{project_id}/oauth/clients` * `GET /accounts/projects/{project_id}/oauth/clients` * `PUT /accounts/projects/{project_id}/oauth/clients/{client_id}` * `DELETE /accounts/projects/{project_id}/oauth/clients/{client_id}` ## External OAuth registrations External OAuth registrations are separate from project OAuth clients. Use OAuth clients when your app needs users to sign in through MeshAgent. Use external OAuth registrations when MeshAgent needs to hold project- or room-scoped integration configuration for an external OAuth provider. External OAuth registrations live under the project or a room: * `POST /accounts/projects/{project_id}/external-oauth` * `GET /accounts/projects/{project_id}/external-oauth` * `PUT /accounts/projects/{project_id}/external-oauth/{registration_id}` * `DELETE /accounts/projects/{project_id}/external-oauth/{registration_id}` * `POST /accounts/projects/{project_id}/rooms/{room_name}/external-oauth` * `GET /accounts/projects/{project_id}/rooms/{room_name}/external-oauth` * `PUT /accounts/projects/{project_id}/rooms/{room_name}/external-oauth/{registration_id}` * `DELETE /accounts/projects/{project_id}/rooms/{room_name}/external-oauth/{registration_id}` ## Related docs * [Projects](./projects) * [API Keys](./api_keys) * [Participant Tokens](../rest_api/participant_tokens) * [API Scopes](../rest_api/api_scopes) * [MeshAgent Studio](../interfaces/meshagent_studio) # Project Roles and Access Source: https://docs.meshagent.com/project_admin/project_roles Understand project roles, room creation permissions, and how project-level access differs from room grants. Project roles control who can administer and operate a MeshAgent project. This is separate from room access. A person can have a project role and still need room access to work in a specific room, and someone can have room access without broad project administration rights. ## Two layers of access MeshAgent has two related but different permission layers: * **Project roles** decide who can administer and operate project-level resources. * **Room grants** decide who can access a specific room and which Room APIs they can use there. That distinction matters: * project roles answer "what can this person manage across the project?" * room grants answer "what can this person or service do inside this room?" For room-specific permissions, see [REST API](../rest_api/overview), [Participant Tokens](../rest_api/participant_tokens), and [API Scopes](../rest_api/api_scopes). ## Common project roles MeshAgent has a default **Member** role, plus stronger project membership presets such as **Room Creator**, **Developer**, and **Admin**. This page is ordered from least access to most access. ### Member Member is the default project collaborator role. Use this when someone should be part of the project without extra project-wide privileges such as developer access, admin access, room-creation privileges, or LLM proxy/OAuth management access. ### Room Creator Room Creator is a limited project role for collaborators who create room-centered project resources. Use this when someone should be able to: * create new rooms * create mailboxes, routes, and scheduled tasks that attach work to rooms * organize work into separate rooms But should not automatically manage the broader project surface such as billing, secrets, or member administration. ### Agent Creator Agent Creator is a focused project role for collaborators who need to create managed agent identities. Use this when someone should be able to create agents without giving them broader developer or admin access. ### Developer Developers are for people building and operating workloads without giving them full project administration. Use this role when someone needs to: * build and test in project rooms * inspect deployed services and runtime state * inspect operational resources such as mailboxes, routes, scheduled tasks, feed subscriptions, and LLM loggers * work in MeshAgent Studio and the CLI without managing the whole project ### LLM Proxy User LLM Proxy User is a focused project permission for collaborators who need project-level OpenAI or Anthropic routing without broader developer access. Use this when someone needs to: * call the project LLM proxy with OAuth access tokens But should not automatically get the rest of the developer project surface. ### Admin Admins have full project-level control. Use this role when someone needs to: * manage members and role assignments * edit project settings * manage secrets, billing, domains, and other project-wide resources * deploy and manage services across the project ## How project roles map to the API In the admin API and SDKs, project membership is controlled with a `roles` list. The server normalizes that list to include `member` and expands inherited roles for `admin` and `developer`. Common role entries include: * `admin` * `developer` * `room_creator` * `agent_creator` * `llm_proxy_user` Some older project member records and Studio settings still surface convenience booleans. They map to roles like this: | Setting | IAM role effect | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `is_admin` | Grants `admin` plus project-wide creator, inventory, manager, billing, usage, group, and LLM proxy roles. | | `is_developer` | Grants `developer`, room/agent/repository/feed manager roles, inventory roles for operational resources such as services, routes, mailboxes, scheduled tasks, feed subscriptions, and LLM loggers, service-account creation and inventory, participant-token creation, and usage reporting. The `developer` relation also qualifies for LLM proxy use in access checks. | | `can_create_rooms` | Grants `room_creator`, `mailbox_creator`, `route_creator`, and `scheduled_task_creator`. | | `can_create_agents` | Grants `agent_creator`. | | `can_use_llm_proxy` | Grants the direct `llm_proxy_user` role. | If you are managing access programmatically, use the project user-management endpoints or SDK helpers that add and update project users. ## How room grants and tokens fit in Project roles and room access are related, but they are not the same thing. * **Project role** decides what someone can manage across the project. * **Room grant** decides what someone can do inside a specific room. * **Participant token** is the signed credential MeshAgent issues for an active room connection. For room access, the important relationship is: 1. A room grant stores the room-specific permissions. 2. When MeshAgent creates a room connection for that person or service, it signs a participant token. 3. That participant token carries the room-level API permissions used during the session. For deployed services, the same idea applies through the service token configuration in the service spec: that token defines what the running service can do in the room. So if you are asking "what can this participant actually do in the room right now?", the answer lives in the room grant or service token configuration, and in the participant token MeshAgent signed from it, not in the project role by itself. ## Practical mental model Use this rule of thumb: * If the question is about **members, billing, domains, secrets, API keys, or project-wide services**, think **project role**. * If the question is about **joining a room, using Room APIs, or limiting what a participant can do inside a room**, think **room grant** and **participant token scope**. This is why a collaborator might need both: * a project role that lets them create rooms * a room grant that lets them access a specific room and use its APIs ## Where to manage roles * **MeshAgent Studio**: use the Members tab for day-to-day role assignment. * **REST API / SDKs**: use the project user-management endpoints such as `POST /accounts/projects/:id/users` and `PUT /accounts/projects/:id/users/:user_id`, or the matching SDK helpers, when provisioning or syncing access from your own systems. ## Related guides * [MeshAgent Studio](../interfaces/meshagent_studio) * [REST API](../rest_api/overview) * [Participant Tokens](../rest_api/participant_tokens) * [API Scopes](../rest_api/api_scopes) # Projects Source: https://docs.meshagent.com/project_admin/projects Create projects, choose the active project in the CLI, and understand where project-level settings live. Projects are the top-level workspace in MeshAgent. A project owns your [rooms](../room_api/overview), [deployed services](../services/deployment/deploy_services), [API keys](./api_keys), [OAuth clients](./oauth), [integrations](./integrations), [routes](./routes), [mailboxes](./mailboxes), [feeds](./feeds), [scheduled tasks](./scheduled_tasks), [billing and usage](./billing), and [membership](./project_roles). First run `meshagent setup` to sign in, or continue with the current account if you are already signed in, then choose or create a project and activate that project from the CLI. If Codex or Claude are installed, setup can also configure them to use MeshAgent for the active project, reuse or update existing MeshAgent integrations, or remove them later. For the full command surface, see [MeshAgent CLI](../reference/meshagent_cli_help). By default MeshAgent provides OpenAI and Anthropic access for the project through MeshAgent-managed routing. Use [Integrations](./integrations) only when you want to switch the project to your own provider accounts or override the upstream base URLs. ```bash theme={null} meshagent setup ``` Use [MeshAgent Accounts](../interfaces/accounts) for membership, billing, and usage. Use [MeshAgent Studio](../interfaces/meshagent_studio) to work inside a project. Both surfaces, along with the CLI, operate on the same underlying project. ## Manage projects from the CLI Use `meshagent project` when you want to create, list, or activate projects from the terminal. Create a project: ```bash theme={null} meshagent project create my-project ``` List the projects you can access: ```bash theme={null} meshagent project list ``` Switch the active project: ```bash theme={null} meshagent project activate PROJECT_ID ``` Use interactive selection when you do not want to paste the ID: ```bash theme={null} meshagent project activate -i ``` Once a project is active, commands for [rooms](../room_api/overview), [services](../services/deployment/deploy_services), [API keys](./api_keys), [routes](./routes), [mailboxes](./mailboxes), [feeds](./feeds), and [scheduled tasks](./scheduled_tasks) use that project by default. ## What lives at the project level * [Project Roles and Access](./project_roles): members, roles, and room-creation permissions * [API Keys](./api_keys): project-scoped credentials for automation and backend services * [OAuth Clients](./oauth): sign users in to your own app with project-owned OAuth clients * [Integrations](./integrations): project-level model routing, telemetry, and related shared settings * [Billing and Usage](./billing): project credits, usage, and recharge settings * [Routes](./routes): map domains to published ports or content in rooms * [Mailboxes](./mailboxes): route email into room queues * [Feeds](./feeds): publish JSON once and deliver it into room storage subscriptions * [Scheduled Tasks](./scheduled_tasks): enqueue recurring work on a schedule Secrets are managed through user-owned and service-account-owned APIs covered in [Secrets and Credentials](../secrets/overview). Project-wide service deployment is covered in [Deploy & Manage](../services/deployment/deploy_services). Sessions and room services are covered with [Rooms](../room_api/sessions) and service deployment docs because they are tied to a room runtime rather than project administration alone. ## Related docs * [MeshAgent Accounts](../interfaces/accounts) * [MeshAgent Studio](../interfaces/meshagent_studio) * [Feeds](./feeds) * [CLI Quickstart](../introduction/cli_quickstart) * [MeshAgent CLI](../reference/meshagent_cli_help) * [Secrets and Credentials](../secrets/overview) * [Sessions](../room_api/sessions) # Registries Source: https://docs.meshagent.com/project_admin/registries Create and manage project-owned image repositories for MeshAgent build and deploy workflows. Registries are the project-owned repositories where MeshAgent stores OCI images for your services. Use them when you want to build, publish, and deploy containerized services inside MeshAgent without depending on a separate registry such as Docker Hub, Azure Container Registry, or Google Artifact Registry. MeshAgent can still work with other registry paths, but project registries give you the MeshAgent-native path when you want image storage and deployment in one place. ## How registries work Each repository belongs to a project and holds the image tags for one service or image family. Tags in the project registry use this shape: ```text theme={null} registry.meshagent.com//: ``` A build may run from your local files or inside one room, but when you publish it to a `registry.meshagent.com/...` tag, the resulting image lives in the project registry. That means other rooms in the same project can deploy from the same published image tag. The repository namespace belongs to the project, not to one room. ## Create a repository Create a repository when you want a stable image name that you plan to build and publish more than once, such as a service, worker, or app. In most projects, you keep one repository per service or image family, then publish new tags into it over time. Create the repository before pushing tags into it: ```bash bash theme={null} meshagent registry create \ --name apps/support-agent \ --description "Images for the support agent service" ``` The repository name is an OCI-style repository path inside the active project. ## Inspect and manage repositories List repositories in the active project: ```bash bash theme={null} meshagent registry list ``` Show one repository: ```bash bash theme={null} meshagent registry get REPOSITORY_ID ``` Update the name or description: ```bash bash theme={null} meshagent registry update REPOSITORY_ID \ --name apps/support-agent \ --description "Room service images for support workflows" ``` Delete a repository: ```bash bash theme={null} meshagent registry delete REPOSITORY_ID ``` ## Use the repository with `meshagent build` Once the repository exists, publish images into it with `meshagent build`: ```bash bash theme={null} meshagent build ./support-agent \ --room quickstart \ --tag registry.meshagent.com/myproject/apps/support-agent:dev ``` `meshagent build` validates that: * the project key in the tag matches the selected project * the target repository exists in that project The build can run from your local files or inside a room, but the published image tag points at the project registry repository. If the repository does not exist yet, create it with `meshagent registry create` first. ## Related docs * [Build and Deploy Images](../services/containers/meshagent_image) * [Service YAML](../services/deployment/deploy_services) * [Projects](./projects) # Routes Source: https://docs.meshagent.com/project_admin/routes Manage project routes that map domains and paths to room services, room content, or managed agents. Routes map a domain to room HTTP services, files in room storage, or a managed agent websocket. Use them when you want a stable URL for something inside a room, such as a web app, static website, or HTTP integration. For dynamic applications, a route can proxy to a published service port. For static sites, a route can serve a room storage subpath directly without running a web server. Routes can front either a fully public site or a private app protected by MeshAgent. For browser apps, MeshAgent can act as an identity-aware proxy in front of your service: it authenticates the user, checks that they are allowed into the room, and only then forwards the request to your app. For deployment basics, see [Service YAML](../services/deployment/deploy_services). Routes are managed from the [MeshAgent CLI](../reference/meshagent_cli_help). ## How routes work * A route selects a room or managed agent backend. * Each room route path targets either a published service port with `targetPort` or room storage with `targetContent`. * When a request arrives, MeshAgent chooses the longest matching path and applies that target's security and response options. * Service targets are proxied to the published port. Content targets are read directly from room storage. ## Create a route Use a MeshAgent-managed domain such as `*.meshagent.app`: 1. Deploy a service that exposes an HTTP endpoint and marks its port as published. 2. Create a route: ```console theme={null} meshagent route create --room my-room --port 5002 --domain my-app.meshagent.app ``` 3. The route is ready as soon as it is created. You can also create or update a route from a RouteSpec file: ```yaml theme={null} kind: Route version: v1 metadata: name: my-app annotations: {} domain: my-app.meshagent.app backend: room: name: my-room paths: - path: / pathType: prefix targetPort: 5002 unavailable: errors/unavailable.html ``` For a service route, `unavailable` names a file in the room storage root to return when the room, published service, container, or tunnel is unavailable. The fallback response has status `503`. A leading `/` is accepted but remains storage-relative, so `/errors/unavailable.html` does not address the host filesystem. Application responses, including an intentional `503` returned by the service itself, are passed through unchanged. ```console theme={null} meshagent route create -f route.yaml meshagent route update my-app.meshagent.app -f route.yaml ``` Managed agent routes use an agent backend and expose the agent websocket on the route domain: ```yaml theme={null} kind: Route version: v1 metadata: name: my-agent annotations: {} domain: my-agent.meshagent.app backend: agent: name: my-agent ``` ## Serve room content directly Use `targetContent` when a site already exists in room storage and does not need an application server. `subpath` is relative to the room storage root; the matched public route path is removed before the remaining request path is appended. For a single content path, create the route directly from the CLI: ```console theme={null} meshagent route create \ --domain docs.meshagent.app \ --room docs-room \ --content-path websites/docs \ --index \ --compression brotli \ --cors '[{"allowedOrigins":["https://app.example.com"]}]' ``` Use `--path /docs` to mount the content below a public URL path, `--iap` to require identity-aware access, and `meshagent route update` with the same options to change an existing route. `--room-path` is an alias for `--content-path`. ```yaml theme={null} kind: Route version: v1 metadata: name: docs annotations: {} domain: docs.meshagent.app backend: room: name: docs-room paths: - path: / pathType: prefix targetContent: subpath: websites/docs notFound: errors/404.html index: true iap: false compression: brotli cors: - allowedOrigins: - https://app.example.com allowedMethods: [GET, HEAD] allowedHeaders: [Authorization] exposeHeaders: [Content-Length] maxAgeSeconds: 3600 allowCredentials: false ``` This exposes `websites/docs/logo.svg` as `/logo.svg`. With `index: true`, requests for the route root and directories serve `index.html`, such as `websites/docs/index.html` and `websites/docs/guide/index.html`. When a requested object does not exist, `notFound` names a fallback file relative to the same `targetContent.subpath`. In the example, a missing object serves `websites/docs/errors/404.html` with status `404`. A leading `/` is accepted but still resolves beneath `websites/docs`; it never changes the storage root. If the fallback file is also missing, the normal not-found response is returned. Content routes support `GET`, `HEAD`, and CORS preflight `OPTIONS` requests. CORS rules use the familiar object-storage controls for allowed origins, methods, and headers, exposed response headers, preflight cache age, and credentials. Credentialed CORS rules must list explicit origins rather than `*`. Web serving requires MeshAgent's built-in GCS or local-filesystem room storage provider. Other room storage implementations are rejected with `unsupported room storage type: X for web serving` rather than being accessed through a running room. `compression` accepts `brotli`, `gzip`, or `none` and defaults to `brotli`. Compression is negotiated with the request's `Accept-Encoding` header; clients that do not advertise the selected encoding receive the original content. Set `iap: true` to protect the content with MeshAgent's identity-aware proxy. The router authenticates the IAP session and checks room site access before reading the file. CORS preflight responses do not expose file content and do not require an IAP cookie. A route can mix service and content targets on different paths. Each individual path must set exactly one of `targetPort` or `targetContent`. ## Mark the port as published In your service config, the HTTP port must be marked as published: ```yaml theme={null} ports: - num: 5002 type: http published: true ``` ## Public and private published ports `published: true` makes a port routable from a route. `public` controls whether that routed URL is open to the internet or protected by MeshAgent: * `public: true`: MeshAgent forwards requests without requiring room authentication. * `public: false`: MeshAgent requires the caller to authenticate before the request can reach the app. * If you omit `public`, the port is treated as private. For API clients and server-to-server callers, a private published port expects a participant token: ```http theme={null} Authorization: Bearer ``` That token must be valid for the room. If the caller does not have access to the room, MeshAgent rejects the request before it reaches your app. ## Integrated security for browser apps For browser-based apps, use cookie validation so MeshAgent behaves like an identity-aware proxy in front of your route. This is the easiest way to publish a private app without making the app itself handle MeshAgent tokens directly. ```yaml theme={null} ports: - num: 5002 type: http published: true public: false liveness: /healthz annotations: meshagent.request.validation.method: cookie ``` You can set `meshagent.request.validation.method: cookie` on the port or on a specific endpoint. Endpoint annotations override port annotations. With that configuration, the request flow looks like this: 1. A user visits the routed URL. 2. If they do not already have a valid MeshAgent IAP session for that route, MeshAgent redirects the browser to sign in. 3. After sign-in, MeshAgent stores a secure, HTTP-only session cookie and retries the request through the route. 4. On each request, MeshAgent validates that the session still maps to a participant token for the target room. 5. If the user is not allowed in the room, the request is rejected before it reaches your app. This gives you a stable URL with MeshAgent-managed authentication and room-level authorization in front of the service. For normal browser navigation, unauthenticated `GET` requests are redirected into the login flow automatically. Non-`GET` requests without a valid session are rejected until the browser has signed in. ## Headers your app receives When a request passes through cookie-based IAP, MeshAgent removes the internal `__meshagent_iap` cookie before forwarding the request to your app and adds trusted identity headers: | Header | Meaning | | ----------------------- | ------------------------------------------------------------------------------------------------------- | | `X-MESHAGENT-USER` | The participant token `name`, typically the signed-in user's email or display identity. | | `X-MESHAGENT-API-SCOPE` | The participant token API permissions, serialized as JSON. If the token has no API grant, this is `{}`. | These headers are intended for the destination app to consume. MeshAgent also strips any client-supplied `X-MESHAGENT-USER` or `X-MESHAGENT-API-SCOPE` headers before forwarding the request, so callers cannot spoof them without actually going through MeshAgent IAP. ## Queue-backed routes Routes are not limited to proxying traffic into an HTTP app. They can also turn incoming HTTP requests into queue messages for agents or workers inside the room. This is useful when you want: * a stable public URL * no always-on HTTP app inside the room * an internal queue that workers can process asynchronously When `meshagent.request.queue` is configured on the matched port or endpoint, MeshAgent enqueues the request body instead of proxying the request to a destination app. ```yaml theme={null} ports: - num: 5002 type: http published: true public: false annotations: meshagent.request.queue: inbound-events meshagent.request.validation.method: bearer ``` With that configuration: 1. A request arrives at the route. 2. MeshAgent validates the caller using the configured route auth method. 3. If validation succeeds, MeshAgent publishes the request body to the queue. 4. MeshAgent returns `202 Accepted`. Today the queued message payload is: ```json theme={null} {"body":""} ``` ### Required annotations | Annotation | Purpose | | ------------------------------------- | --------------------------------------------------------------------------------------- | | `meshagent.request.queue` | Queue name to publish into. | | `meshagent.request.validation.method` | Optional request validation method. Supported values are `bearer`, `jwt`, and `cookie`. | You can place these annotations on the port or on a specific endpoint. Endpoint annotations override port annotations. ### Secret-backed validation The validation secret is not copied into the route itself. Instead, MeshAgent reads it from room secrets at request time and uses it to verify the incoming webhook or signed request before anything is placed on the queue. This keeps the shared secret inside the room security boundary while still letting you publish an external URL. Supported validation methods currently include: * `github` * `salesforce` * `sentry` * `slack` * `shopify` * `stripe` * `telegram` * `twilio` * `whatsapp` * `zendesk` ### What to store in the room secret Store the provider's original shared secret value in the room secret. Do not store: * the incoming signature header value * a computed HMAC or digest * a JSON wrapper object unless the provider explicitly gives you a plain secret inside it Use the raw secret string or key that the provider tells you to use for request verification. | Method | Secret value to store in the room | Provider docs | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `github` | The webhook secret token you configured for that GitHub webhook. | [GitHub: Validating webhook deliveries](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries) | | `slack` | Your Slack app's signing secret. | [Slack: Verifying requests from Slack](https://api.slack.com/docs/verifying-requests-from-slack) | | `stripe` | The webhook endpoint's signing secret. This is not a Stripe API key. | [Stripe: Receive events with an HTTPS server](https://docs.stripe.com/webhooks/test) | | `shopify` | For Shopify app webhooks, your app client secret. | [Shopify: Deliver webhooks through HTTPS](https://shopify.dev/docs/apps/build/webhooks/subscribe/https), [Shopify: About client credentials](https://shopify.dev/docs/apps/build/authentication-authorization/client-secrets) | | `telegram` | The Telegram webhook secret token you pass to `setWebhook` as `secret_token`. | [Telegram Bot API: setWebhook](https://core.telegram.org/bots/api#setwebhook) | | `twilio` | Your Twilio Auth Token used for request validation. | [Twilio: Security](https://www.twilio.com/docs/usage/security), [Twilio: REST API Auth Token](https://www.twilio.com/docs/iam/api/authtoken) | | `whatsapp` | Your Meta app secret used for `X-Hub-Signature-256` validation. | [WhatsApp Cloud API: Set up webhooks](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks) | | `zendesk` | The webhook signing secret key from the Zendesk webhook configuration. | [Zendesk: Verifying webhook authenticity](https://developer.zendesk.com/documentation/event-connectors/webhooks/verifying) | | `sentry` | The Sentry service hook `secret` value for that hook. | [Sentry: Register a New Service Hook](https://docs.sentry.io/api/projects/register-a-new-service-hook/), [Sentry: Retrieve a Service Hook](https://docs.sentry.io/api/projects/retrieve-a-service-hook/) | | `salesforce` | The signing key or shared secret for the Salesforce webhook product that is sending the request. Common cases are Marketing Cloud ENS callback signature keys and Data Cloud generated signing keys. | [Salesforce Marketing Cloud ENS: Notification Signing](https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/ens-notification-signing.html), [Salesforce Data Cloud: Generate a Secret Key for Signature Validation](https://developer.salesforce.com/docs/data/data-cloud-ref/guide/c360a-api-generate-secret-key-for-signature-validation.htm), [Salesforce Data Cloud: Payload Signature](https://developer.salesforce.com/docs/data/data-cloud-ref/guide/c360a-api-payload-signature.htm) | Queue-backed validated routes must remain non-public. They are intended for authenticated or signature-validated ingress handled by MeshAgent, not open anonymous forwarding. ## Liveness and startup behavior `liveness` is the HTTP path MeshAgent uses to decide when a published port is actually ready to serve traffic. ```yaml theme={null} ports: - num: 5002 type: http published: true liveness: /healthz ``` When a request hits a route and MeshAgent cannot connect to the target port yet, it checks the `liveness` URL and waits for it to return `2xx`. Once the service is live, MeshAgent retries the original request. This matters during startup, cold starts, and restarts: * With a liveness URL, MeshAgent can wait for the app to finish booting instead of immediately failing the first request. * Without a liveness URL, an early request is more likely to fail with a bad gateway while the process is still starting. You should give published HTTP ports a liveness URL that is: * Cheap to evaluate. * Available without external user auth. * Wired to real readiness, not just process start. A good pattern is `/healthz` or `/ready` returning `200` only after the app is ready to serve the same traffic the route will send. ## Manage routes ```bash theme={null} meshagent route list meshagent route get my-app.meshagent.app meshagent route update my-app.meshagent.app --port 5003 meshagent route delete my-app.meshagent.app ``` The default `route list` table includes each public path, service port or room content path, `index`, `iap`, `compression`, and CORS rules. Use `meshagent route list --output json` or `meshagent route get DOMAIN` for the complete RouteSpec, including routes with multiple path targets. To create or update a route, you need permission to administer the target room. ## Related docs * [Feeds](./feeds) * [Projects](./projects) * [Service YAML](../services/deployment/deploy_services) * [MeshAgent Image](../services/containers/meshagent_image) * [Participant Tokens](../rest_api/participant_tokens) # Scheduled Tasks Source: https://docs.meshagent.com/project_admin/scheduled_tasks Create project-level scheduled tasks that enqueue work into room queues or start containers. Scheduled tasks are project-level triggers that either enqueue work into room queues or start containers on a schedule. A scheduled task uses a `ScheduledTaskSpec` file. The spec chooses exactly one target: `queue` or `container`. The room is selected when the task is created, not inside the spec. ## Create a scheduled task ```bash theme={null} cat > support-summary-task.yaml <<'YAML' version: v1 kind: ScheduledTask schedule: 30 17 * * * queue: name: support-jobs payload: prompt: Generate the daily support summary. YAML meshagent scheduled-task add \ --room support \ --file support-summary-task.yaml ``` This creates a scheduled task in the active project that enqueues work into the `support-jobs` queue in the `support` room. The payload is a JSON object. For MeshAgent queue consumers, that can include the same structured `prompt`, `content`, and `path` fields supported by `meshagent room queue send`. Example: ```bash theme={null} cat > hourly-support-task.yaml <<'YAML' version: v1 kind: ScheduledTask schedule: 0 * * * * queue: name: support-jobs payload: path: dataset://threads/support/{YYYY}/{MM}/{DD}/{HH}/summary prompt: - type: file url: room:///prompts/hourly-summary.md - type: text text: Generate the hourly support summary. YAML meshagent scheduled-task add \ --room support \ --file hourly-support-task.yaml ``` To start a container instead of writing to a queue, use `container`: ```bash theme={null} cat > container-task.yaml <<'YAML' version: v1 kind: ScheduledTask schedule: 0 * * * * container: image: alpine:latest command: echo scheduled YAML meshagent scheduled-task add \ --room support \ --file container-task.yaml ``` ## Inspect and manage scheduled tasks List tasks: ```bash theme={null} meshagent scheduled-task list meshagent scheduled-task list --room support ``` Update a task: ```bash theme={null} meshagent scheduled-task update TASK_ID \ --file support-summary-task.yaml ``` List runs for a task: ```bash theme={null} meshagent scheduled-task runs TASK_ID ``` Delete a task: ```bash theme={null} meshagent scheduled-task delete TASK_ID ``` ## Where to manage them * Use [MeshAgent Studio](../interfaces/meshagent_studio) when you want the main UI flow. * Use the CLI when you want quick setup or automation. * Use the [REST API](../rest_api/overview) when you need programmatic provisioning. Schedules must be at least 15 minutes apart. If you want a recurring turn owned by one agent inside a service manifest, use `agents[].heartbeat` instead of a separate scheduled task. ## Related docs * [Queues and Scheduled Tasks](../agents/queues_and_scheduled_tasks) * [Queue API](../room_api/queue) * [Projects](./projects) # Machine Setup Guide Source: https://docs.meshagent.com/reference/machine_setup ## Python Development Environment Setup In this guide you will set up your machine to use the MeshAgent Python SDK. Note that **MeshAgent requires Python 3.13**. We recommend using **uv**, a modern Python tool that: * Installs the correct Python version automatically * Creates and manages virtual environments * Installs dependencies consistently across platforms ## Step 1: Install uv ```bash curl theme={null} curl -LsSf https://astral.sh/uv/install.sh | sh # verify installation uv --version ``` ## Step 2: Create a project directory Create a folder where you’ll run the MeshAgent examples: ```bash bash theme={null} mkdir meshagent-getting-started && cd meshagent-getting-started ``` If you are using GitHub, clone your repository instead and `cd` into it. ## Step 3: Initialize the project, create a virtual environment, and install MeshAgent ```bash bash theme={null} # Pin Python 3.13 for the project and create standard project files uv init --python 3.13 # Create a virtual environment and download Python 3.13 if not already installed on your machine uv venv --python 3.13 # Install MeshAgent uv add "meshagent[all]" ``` > ### How uv commands fit together > > * `uv init` initializes the project and records the required Python version > * `uv venv` ensures that Python version is available and creates the virtual environment > * `uv add` installs dependencies into the virtual environment ## Step 4: Running commands and activating your virtual environment With `uv`, you can either activate the virtual environment and run commands normally, or run commands through `uv` using `uv run`, which automatically uses the project’s virtual environment without activation. ### Option A: Activate the virtual environment (recommended for frequent CLI use) ```bash macOS/Linux theme={null} source .venv/bin/activate ``` ```bash Windows theme={null} .venv\Scripts\activate ``` You’ll know the environment is active when you see `(.venv)` at the start of your terminal prompt. With the environment activated you can run commands directly: ```bash bash theme={null} meshagent setup python your_script.py ``` ### Option B: Use `uv run` (no env activation required) If you prefer not to activate the virtual environment, prefix commands with `uv run`: ```bash bash theme={null} uv run meshagent setup uv run python your_script.py ``` ## Keeping your environment up to date To upgrade MeshAgent and other dependencies to their latest compatible versions, run: ```bash bash theme={null} uv lock --upgrade uv sync ``` > ### `uv lock` vs `uv sync` > > * `uv lock` updates the dependency versions recorded for the project > * `uv sync` installs the versions recorded in the lockfile into your virtual environment ## Next Steps You're ready to continue with the [Quickstart](../introduction/cli_quickstart) guide. ### Troubleshooting Command not found (`meshagent`, `python`): * Make sure the virtual environment is activated and you are in the correct project directory * Or use `uv run meshagent` or \`uv run pyhton…\`\`\` Permission issues: * On macOS/Linux, you might need to restart your terminal after installing uv, or run `source ~/.bashrc` or `source ~/.zshrc`. # MeshAgent CLI Commands Source: https://docs.meshagent.com/reference/meshagent_cli_help # `meshagent` **Usage**: ```console theme={null} $ meshagent [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `version`: Print the version * `setup`: Perform initial login and project activation. * `auth`: Authenticate to meshagent * `project`: Manage or activate your meshagent projects * `service-account`: Manage service accounts for your project * `secret`: Manage user and service account secrets * `iam`: Manage IAM policies for project resources * `config`: Read MeshAgent deployment configuration * `doctor`: Inspect the current directory for... * `create`: Create a minimal deployable project. * `session`: Inspect recent sessions and events * `ask`: Send a one-shot LLM prompt. * `launch`: Launch supported CLI apps through MeshAgent. * `token`: Generate a participant token (JWT) from a... * `service`: Manage services for your project * `mcp`: Bridge MCP servers into MeshAgent rooms * `rooms`: Create, list, and manage rooms in a project * `volumes`: Manage durable storage volumes for a room * `agent`: Create, list, and manage managed agents in... * `mailbox`: Manage mailboxes for your project * `feed`: Manage feeds for your project * `subscription`: Manage feed subscriptions for your project * `route`: Manage routes for your project * `custom-domain`: Manage custom domains for project routes * `registry`: Manage registries for your project * `build`: Build a container image inside a room. * `deploy`: Create or update a room service from an... * `scheduled-task`: Manage scheduled tasks for your project * `meeting-transcriber`: Join a meeting transcriber to a room * `port`: Forward a container port to localhost * `voicebot`: Join a voicebot to a room * `process`: Run process-backed agents * `room`: Operate within a room * `llm`: Local LLM proxy utilities ## `meshagent version` Print the version **Usage**: ```console theme={null} $ meshagent version [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. ## `meshagent setup` Perform initial login and project activation. **Usage**: ```console theme={null} $ meshagent setup [OPTIONS] ``` **Options**: * `--api-url TEXT`: Persist this API URL on the saved profile and use it for setup login. * `--help`: Show this message and exit. ## `meshagent auth` Authenticate to meshagent **Usage**: ```console theme={null} $ meshagent auth [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `login` * `logout` * `switch` * `whoami` * `token` ### `meshagent auth login` **Usage**: ```console theme={null} $ meshagent auth login [OPTIONS] ``` **Options**: * `--api-url TEXT`: Persist this API URL on the saved profile and use it for this login. * `--help`: Show this message and exit. ### `meshagent auth logout` **Usage**: ```console theme={null} $ meshagent auth logout [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. ### `meshagent auth switch` **Usage**: ```console theme={null} $ meshagent auth switch [OPTIONS] [PROFILE] ``` **Arguments**: * `[PROFILE]`: Saved profile user id or email. If omitted, saved profiles are listed or an interactive picker is shown in a TTY. **Options**: * `--help`: Show this message and exit. ### `meshagent auth whoami` **Usage**: ```console theme={null} $ meshagent auth whoami [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. ### `meshagent auth token` **Usage**: ```console theme={null} $ meshagent auth token [OPTIONS] ``` **Options**: * `--help`: Show this message and exit. ## `meshagent project` Manage or activate your meshagent projects **Usage**: ```console theme={null} $ meshagent project [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a new MeshAgent project. * `list`: List projects and mark the currently... * `get`: Get a MeshAgent project. * `set-room-roles`: Set authoritative project room-role... * `reset-room-roles`: Remove the project room-role override and... * `activate`: Set the active project for subsequent CLI... ### `meshagent project create` Create a new MeshAgent project. **Usage**: ```console theme={null} $ meshagent project create [OPTIONS] NAME ``` **Arguments**: * `NAME`: \[required] **Options**: * `--help`: Show this message and exit. ### `meshagent project list` List projects and mark the currently active one. **Usage**: ```console theme={null} $ meshagent project list [OPTIONS] ``` **Options**: * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent project get` Get a MeshAgent project. **Usage**: ```console theme={null} $ meshagent project get [OPTIONS] PROJECT ``` **Arguments**: * `PROJECT`: Project id or key to get \[required] **Options**: * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent project set-room-roles` Set authoritative project room-role mappings from a YAML spec. **Usage**: ```console theme={null} $ meshagent project set-room-roles [OPTIONS] FILE ``` **Arguments**: * `FILE`: RoomRoles YAML spec \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent project reset-room-roles` Remove the project room-role override and restore built-in defaults. **Usage**: ```console theme={null} $ meshagent project reset-room-roles [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent project activate` Set the active project for subsequent CLI commands. **Usage**: ```console theme={null} $ meshagent project activate [OPTIONS] [PROJECT_ID] ``` **Arguments**: * `[PROJECT_ID]`: Project id or key. If omitted, an interactive picker is shown in a TTY. **Options**: * `-i, --interactive`: Interactively select or create a project. Uses the TUI in a TTY. * `--help`: Show this message and exit. ## `meshagent service-account` Manage service accounts for your project **Usage**: ```console theme={null} $ meshagent service-account [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `api-key`: Manage API keys * `list`: List service accounts for a project. * `get`: Get a service account. * `create`: Create a service account for a project. * `update`: Update a service account. * `delete`: Delete a service account. ### `meshagent service-account api-key` Manage API keys **Usage**: ```console theme={null} $ meshagent service-account api-key [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. **Commands**: * `list`: List API keys for a service account. * `create`: Create an API key for a service account. * `delete`: Delete an API key. * `get`: Get the activated API key for a project. * `env`: Print the activated API key as a shell... * `activate`: Set the default API key for a project in... #### `meshagent service-account api-key list` List API keys for a service account. **Usage**: ```console theme={null} $ meshagent service-account api-key list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--service-account TEXT`: service account id or name that owns the API keys \[required] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent service-account api-key create` Create an API key for a service account. **Usage**: ```console theme={null} $ meshagent service-account api-key create [OPTIONS] NAME ``` **Arguments**: * `NAME`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--service-account TEXT`: service account id or name that will own the API key \[required] * `--description TEXT`: a description for the API key * `--activate / --no-activate`: use this key by default for commands that accept an API key \[default: no-activate] * `--silent / --no-silent`: do not print API key \[default: no-silent] * `--help`: Show this message and exit. #### `meshagent service-account api-key delete` Delete an API key. **Usage**: ```console theme={null} $ meshagent service-account api-key delete [OPTIONS] ID ``` **Arguments**: * `ID`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--service-account TEXT`: service account id or name that owns the API key \[required] * `--help`: Show this message and exit. #### `meshagent service-account api-key get` Get the activated API key for a project. **Usage**: ```console theme={null} $ meshagent service-account api-key get [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent service-account api-key env` Print the activated API key as a shell export snippet. **Usage**: ```console theme={null} $ meshagent service-account api-key env [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent service-account api-key activate` Set the default API key for a project in local CLI settings. **Usage**: ```console theme={null} $ meshagent service-account api-key activate [OPTIONS] KEY ``` **Arguments**: * `KEY`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent service-account list` List service accounts for a project. **Usage**: ```console theme={null} $ meshagent service-account list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent service-account get` Get a service account. **Usage**: ```console theme={null} $ meshagent service-account get [OPTIONS] SERVICE_ACCOUNT ``` **Arguments**: * `SERVICE_ACCOUNT`: service account id or name \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent service-account create` Create a service account for a project. **Usage**: ```console theme={null} $ meshagent service-account create [OPTIONS] NAME ``` **Arguments**: * `NAME`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--display-name TEXT`: display name for the service account * `--description TEXT`: description for the service account * `--metadata TEXT`: metadata JSON object * `--annotations TEXT`: annotations JSON object * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent service-account update` Update a service account. **Usage**: ```console theme={null} $ meshagent service-account update [OPTIONS] SERVICE_ACCOUNT ``` **Arguments**: * `SERVICE_ACCOUNT`: service account id or name \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--name TEXT`: new service account name * `--display-name TEXT`: display name for the service account * `--description TEXT`: description for the service account * `--metadata TEXT`: metadata JSON object * `--annotations TEXT`: annotations JSON object * `--help`: Show this message and exit. ### `meshagent service-account delete` Delete a service account. **Usage**: ```console theme={null} $ meshagent service-account delete [OPTIONS] SERVICE_ACCOUNT ``` **Arguments**: * `SERVICE_ACCOUNT`: service account id or name \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent secret` Manage user and service account secrets **Usage**: ```console theme={null} $ meshagent secret [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List secrets for a subject. * `search`: Search secrets for a subject. * `get`: Get a secret for a subject. * `create`: Create a secret for a subject. * `update`: Update a secret for a subject. * `delete`: Delete a secret for a subject. * `versions`: List versions for a secret. * `add-version`: Add a new version to a secret. * `access`: Access the contents of a secret version. * `delete-version`: Delete a secret version. * `grants`: List proxy access grants for one of your... * `grant-proxy`: Grant a service account proxy access to... * `revoke-proxy`: Revoke a service account proxy access... * `pull-secrets`: List pull secrets for a service account. * `add-pull-secret`: Add a pull secret to a service account. * `remove-pull-secret`: Remove a pull secret from a service account. ### `meshagent secret list` List secrets for a subject. **Usage**: ```console theme={null} $ meshagent secret list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--page-size INTEGER`: page size \[default: 100] * `--filter TEXT`: text filter * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret search` Search secrets for a subject. **Usage**: ```console theme={null} $ meshagent secret search [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--filter TEXT`: text filter * `--name TEXT`: secret name * `--type TEXT`: secret type * `--http-only / --not-http-only`: http-only flag * `--metadata TEXT`: metadata JSON object * `--annotations TEXT`: annotations JSON object * `--provider TEXT`: standard provider annotation * `--service TEXT`: standard service annotation * `--account TEXT`: standard account annotation * `--username TEXT`: standard username annotation * `--email TEXT`: standard email annotation * `--url TEXT`: standard url annotation * `--oauth-provider TEXT`: standard OAuth provider annotation * `--oauth-scopes TEXT`: standard OAuth scopes annotation * `--page-size INTEGER`: page size \[default: 100] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret get` Get a secret for a subject. **Usage**: ```console theme={null} $ meshagent secret get [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--include-value`: include the current secret value * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret create` Create a secret for a subject. **Usage**: ```console theme={null} $ meshagent secret create [OPTIONS] NAME ``` **Arguments**: * `NAME`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--type TEXT`: secret type \[default: opaque] * `--http-only`: make the secret proxy-only * `--metadata TEXT`: metadata JSON object * `--annotations TEXT`: annotations JSON object * `--value TEXT`: initial secret value * `--value-file PATH`: file containing secret value * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret update` Update a secret for a subject. **Usage**: ```console theme={null} $ meshagent secret update [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--name TEXT`: new name * `--type TEXT`: new type * `--http-only / --not-http-only`: http-only flag * `--metadata TEXT`: metadata JSON object * `--annotations TEXT`: annotations JSON object * `--help`: Show this message and exit. ### `meshagent secret delete` Delete a secret for a subject. **Usage**: ```console theme={null} $ meshagent secret delete [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--help`: Show this message and exit. ### `meshagent secret versions` List versions for a secret. **Usage**: ```console theme={null} $ meshagent secret versions [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret add-version` Add a new version to a secret. **Usage**: ```console theme={null} $ meshagent secret add-version [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--value TEXT`: new secret value * `--value-file PATH`: file containing secret value * `--set-current / --no-set-current`: set as current version \[default: set-current] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret access` Access the contents of a secret version. **Usage**: ```console theme={null} $ meshagent secret access [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--version TEXT`: secret version id; defaults to the current version * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret delete-version` Delete a secret version. **Usage**: ```console theme={null} $ meshagent secret delete-version [OPTIONS] SECRET_ID VERSION_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] * `VERSION_ID`: secret version id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: secret owner: "me" or a service account email, id, key, or name \[default: me] * `--help`: Show this message and exit. ### `meshagent secret grants` List proxy access grants for one of your secrets. **Usage**: ```console theme={null} $ meshagent secret grants [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret grant-proxy` Grant a service account proxy access to one of your secrets. **Usage**: ```console theme={null} $ meshagent secret grant-proxy [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: service account email, id, key, or name \[required] * `--help`: Show this message and exit. ### `meshagent secret revoke-proxy` Revoke a service account proxy access grant from one of your secrets. **Usage**: ```console theme={null} $ meshagent secret revoke-proxy [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: service account email, id, key, or name \[required] * `--help`: Show this message and exit. ### `meshagent secret pull-secrets` List pull secrets for a service account. **Usage**: ```console theme={null} $ meshagent secret pull-secrets [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: service account email, id, key, or name \[required] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent secret add-pull-secret` Add a pull secret to a service account. **Usage**: ```console theme={null} $ meshagent secret add-pull-secret [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: service account email, id, key, or name \[required] * `--help`: Show this message and exit. ### `meshagent secret remove-pull-secret` Remove a pull secret from a service account. **Usage**: ```console theme={null} $ meshagent secret remove-pull-secret [OPTIONS] SECRET_ID ``` **Arguments**: * `SECRET_ID`: secret id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--subject TEXT`: service account email, id, key, or name \[required] * `--help`: Show this message and exit. ## `meshagent iam` Manage IAM policies for project resources **Usage**: ```console theme={null} $ meshagent iam [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `policy`: List a resource IAM policy. * `grant`: Grant roles on a resource. * `revoke`: Revoke all direct roles for a subject. ### `meshagent iam policy` List a resource IAM policy. **Usage**: ```console theme={null} $ meshagent iam policy [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--resource-type TEXT`: resource type \[required] * `--resource-id TEXT`: resource id \[required] * `--page-size INTEGER`: OpenFGA read page size \[default: 50] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent iam grant` Grant roles on a resource. **Usage**: ```console theme={null} $ meshagent iam grant [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--resource-type TEXT`: resource type \[required] * `--resource-id TEXT`: resource id \[required] * `--subject-type TEXT`: subject type \[required] * `--subject-id TEXT`: subject id \[required] * `--role TEXT`: role to grant; repeat or comma-separate \[required] * `--subject-object-type TEXT`: userset object type * `--subject-relation TEXT`: userset relation * `--invite-redirect-url TEXT`: invite redirect URL for users * `--help`: Show this message and exit. ### `meshagent iam revoke` Revoke all direct roles for a subject. **Usage**: ```console theme={null} $ meshagent iam revoke [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--resource-type TEXT`: resource type \[required] * `--resource-id TEXT`: resource id \[required] * `--subject-type TEXT`: subject type \[required] * `--subject-id TEXT`: subject id \[required] * `--subject-object-type TEXT`: userset object type * `--subject-relation TEXT`: userset relation * `--help`: Show this message and exit. ## `meshagent config` Read MeshAgent deployment configuration **Usage**: ```console theme={null} $ meshagent config [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `get`: Print one deployment config value. ### `meshagent config get` Print one deployment config value. **Usage**: ```console theme={null} $ meshagent config get [OPTIONS] PATH ``` **Arguments**: * `PATH`: Config path to read, for example domains.pages \[required] **Options**: * `--help`: Show this message and exit. ## `meshagent doctor` Inspect the current directory for MeshAgent deployment gaps. **Usage**: ```console theme={null} $ meshagent doctor [OPTIONS] [PATH] ``` **Arguments**: * `[PATH]` **Options**: * `--fix`: Create obvious missing project files such as Dockerfile or pyproject.toml. * `--help`: Show this message and exit. ## `meshagent create` Create a minimal deployable project. **Usage**: ```console theme={null} $ meshagent create [OPTIONS] [PATH] ``` **Arguments**: * `[PATH]` **Options**: * `-l, --language TEXT`: Template language for non-interactive use. Supported: python, javascript, typescript, react, dotnet, dart/flutter. * `--focus TEXT`: Project focus for non-interactive use. Use stable IDs: webserver (Web App), backend-agent (Agent Toolkit), chatbot (OpenAI Chatbot), chatbot-anthropic (Anthropic Chatbot), chatbot-ui (Agent UI), room-chat (Room Chat), room-workspace (Room Workspace), or contact-form (Contact Form), task-queue-dashboard (Task Queue Dashboard), telegram-channel (Telegram Channel), slack-channel (Slack Channel), twilio-channel (Twilio Channel), or whatsapp-channel (WhatsApp Channel). * `--interactive / --no-interactive`: Run or bypass the interactive template picker. Defaults to interactive when attached to a TTY and language or focus is missing. * `--help`: Show this message and exit. ## `meshagent session` Inspect recent sessions and events **Usage**: ```console theme={null} $ meshagent session [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List recent sessions * `get`: Get events for a session * `kill`: Forcefully kill a running session instance * `logs`: List logs for a session * `metrics`: List metrics for a session * `traces`: List trace spans for a session as a tree ### `meshagent session list` List recent sessions **Usage**: ```console theme={null} $ meshagent session list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--limit INTEGER RANGE`: Maximum sessions to return (server max 1000) \[default: 25; x>=1] * `--room TEXT`: Only include sessions for the given room name * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent session get` Get events for a session **Usage**: ```console theme={null} $ meshagent session get [OPTIONS] SESSION_ID ``` **Arguments**: * `SESSION_ID`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent session kill` Forcefully kill a running session instance **Usage**: ```console theme={null} $ meshagent session kill [OPTIONS] SESSION_ID ``` **Arguments**: * `SESSION_ID`: Session id to kill \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-y, --yes`: Skip the confirmation prompt * `--help`: Show this message and exit. ### `meshagent session logs` List logs for a session **Usage**: ```console theme={null} $ meshagent session logs [OPTIONS] [SESSION_ARG] ``` **Arguments**: * `[SESSION_ARG]`: Session id to inspect **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--session-id TEXT`: Session id to inspect * `--room TEXT`: Use the most recent session for this room * `-o, --output TEXT`: output format \[default: table] * `--attrs`: Include log and resource attributes * `--help`: Show this message and exit. ### `meshagent session metrics` List metrics for a session **Usage**: ```console theme={null} $ meshagent session metrics [OPTIONS] [SESSION_ARG] ``` **Arguments**: * `[SESSION_ARG]`: Session id to inspect **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--session-id TEXT`: Session id to inspect * `--room TEXT`: Use the most recent session for this room * `-o, --output TEXT`: output format \[default: table] * `--attrs`: Include metric attributes * `--buckets`: Include histogram bucket counts * `--help`: Show this message and exit. ### `meshagent session traces` List trace spans for a session as a tree **Usage**: ```console theme={null} $ meshagent session traces [OPTIONS] [SESSION_ARG] ``` **Arguments**: * `[SESSION_ARG]`: Session id to inspect **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--session-id TEXT`: Session id to inspect * `--room TEXT`: Use the most recent session for this room * `--trace-id TEXT`: Only include spans from this trace * `--name TEXT`: Only include spans whose name contains this text * `--min-duration TEXT`: Only include spans at or above this duration, e.g. 500ms or 2s * `--attrs`: Include span attributes * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ## `meshagent ask` Send a one-shot LLM prompt. **Usage**: ```console theme={null} $ meshagent ask [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-m, --message TEXT`: Prompt to send to the LLM * `--format TEXT`: Output format for non-interactive responses. \[default: markdown] * `--model TEXT`: Name of the LLM model to use \[default: gpt-5.6-sol] * `--preamble-rule / --no-preamble-rule`: Include the default rule asking the model to send concise pre-tool preambles. \[default: preamble-rule] * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. ## `meshagent launch` Launch supported CLI apps through MeshAgent. **Usage**: ```console theme={null} $ meshagent launch [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. **Commands**: * `codex`: Launch Codex through MeshAgent for the... * `claude`: Launch Claude through MeshAgent for the... ### `meshagent launch codex` Launch Codex through MeshAgent for the active project. **Usage**: ```console theme={null} $ meshagent launch codex [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. * `--api-url TEXT`: Override the MeshAgent API URL for this Codex launch. * `--help`: Show this message and exit. ### `meshagent launch claude` Launch Claude through MeshAgent for the active project. **Usage**: ```console theme={null} $ meshagent launch claude [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. * `--api-url TEXT`: Override the MeshAgent API URL for this Claude launch. * `--help`: Show this message and exit. ## `meshagent token` Generate a participant token (JWT) from a spec **Usage**: ```console theme={null} $ meshagent token [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: File path to a file * `-i, --input TEXT`: File path to a token spec \[required] * `--key TEXT`: an api key to sign the token with * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. ## `meshagent service` Manage services for your project **Usage**: ```console theme={null} $ meshagent service [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `spec`: Render a service or template YAML spec... * `create`: Create a service attached to the project. * `update`: Create a service attached to the project. * `validate`: Validate a service spec from a YAML file. * `create-template`: Create a service from a ServiceTemplate spec. * `update-template`: Update a service using a ServiceTemplate... * `validate-template`: Validate a service template from a YAML file. * `render-template`: Render a service template with variables... * `run`: Run a local command and register it as a... * `enable`: Enable a service so it can start and run. * `disable`: Disable a service, stopping it and... * `get`: Get a service for the project. * `list`: List all services for the project. * `delete`: Delete a service. ### `meshagent service spec` Render a service or template YAML spec without creating a service. **Usage**: ```console theme={null} $ meshagent service spec [OPTIONS] ``` **Options**: * `-f, --file TEXT`: File path to a service definition. Beginner fallback: point this at a meshagent.yaml when the app has no Dockerfile. For a public HTTP route, set container.private: false and metadata.annotations.meshagent.service.id in the file. * `--url TEXT`: URL to a service definition * `--mcp TEXT`: MCP server URL. Auto-discovers metadata and generates a service spec without creating it. * `--format [service|template]`: Output format. 'service' emits Service YAML. 'template' emits ServiceTemplate YAML. \[default: service] * `--service-id TEXT`: Optional override for meshagent.service.id in metadata annotations. * `--help`: Show this message and exit. ### `meshagent service create` Create a service attached to the project. Beginner fallback when an app does not have a Dockerfile: write a minimal meshagent.yaml, set the HTTP port to published/public, set container.private: false for a public route, and include metadata.annotations.meshagent.service.id so a route can target the created service. **Usage**: ```console theme={null} $ meshagent service create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-f, --file TEXT`: File path to a service definition * `--url TEXT`: URL to a service definition * `--mcp TEXT`: MCP server URL. Auto-discovers OAuth metadata and creates an external MCP service configured with discovered OAuth endpoints. * `--room TEXT`: Room name * `--global`: Create the service globally instead of in a room * `--service-id TEXT`: Optional override for meshagent.service.id in metadata annotations. * `--force`: Ignore an existing service with the same meshagent.service.id. * `--replace`: Replace an existing service with the same meshagent.service.id. * `--help`: Show this message and exit. ### `meshagent service update` Create a service attached to the project. **Usage**: ```console theme={null} $ meshagent service update [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT` * `-f, --file TEXT`: File path to a service definition * `--url TEXT`: URL to a service definition * `--mcp TEXT`: MCP server URL. Auto-discovers OAuth metadata and builds an external MCP service configured with discovered OAuth endpoints. * `--create / --no-create`: create the service if it does not exist \[default: no-create] * `--room TEXT`: Room name * `--global`: Update the global service instead of a room service * `--service-id TEXT`: Optional override for meshagent.service.id in metadata annotations. * `--force`: Ignore an existing service with the same meshagent.service.id. * `--replace`: Replace an existing service with the same meshagent.service.id. * `--help`: Show this message and exit. ### `meshagent service validate` Validate a service spec from a YAML file. **Usage**: ```console theme={null} $ meshagent service validate [OPTIONS] ``` **Options**: * `-f, --file TEXT`: File path to a service definition \[required] * `--help`: Show this message and exit. ### `meshagent service create-template` Create a service from a ServiceTemplate spec. **Usage**: ```console theme={null} $ meshagent service create-template [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-f, --file TEXT`: File path to a service template * `--url TEXT`: URL to a service template * `--values-file TEXT`: File path to template values * `-v, --value TEXT`: Template value override (key=value) * `--room TEXT`: Room name * `--global`: Create the service globally instead of in a room * `--force`: Ignore an existing service with the same meshagent.service.id. * `--replace`: Replace an existing service with the same meshagent.service.id. * `--help`: Show this message and exit. ### `meshagent service update-template` Update a service using a ServiceTemplate spec. **Usage**: ```console theme={null} $ meshagent service update-template [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT` * `-f, --file TEXT`: File path to a service template * `--url TEXT`: URL to a service template * `--values-file TEXT`: File path to template values * `-v, --value TEXT`: Template value override (key=value) * `--create / --no-create`: create the service if it does not exist \[default: no-create] * `--room TEXT`: Room name * `--global`: Update the global service instead of a room service * `--force`: Ignore an existing service with the same meshagent.service.id. * `--replace`: Replace an existing service with the same meshagent.service.id. * `--help`: Show this message and exit. ### `meshagent service validate-template` Validate a service template from a YAML file. **Usage**: ```console theme={null} $ meshagent service validate-template [OPTIONS] ``` **Options**: * `-f, --file TEXT`: File path to a service template * `--url TEXT`: URL to a service template * `--values-file TEXT`: File path to template values * `-v, --value TEXT`: Template value override (key=value) * `--help`: Show this message and exit. ### `meshagent service render-template` Render a service template with variables and print the rendered YAML. **Usage**: ```console theme={null} $ meshagent service render-template [OPTIONS] ``` **Options**: * `-f, --file TEXT`: File path to a service template * `--url TEXT`: URL to a service template * `--values-file TEXT`: File path to template values * `-v, --value TEXT`: Template value override (key=value) * `--help`: Show this message and exit. ### `meshagent service run` Run a local command and register it as a temporary room service. **Usage**: ```console theme={null} $ meshagent service run [OPTIONS] COMMAND ``` **Arguments**: * `COMMAND`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-p, --port INTEGER`: a port number to run the agent on (will set MESHAGENT\_PORT environment variable when launching the service) * `--room TEXT`: Room name * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ### `meshagent service enable` Enable a service so it can start and run. **Usage**: ```console theme={null} $ meshagent service enable [OPTIONS] SERVICE_ID ``` **Arguments**: * `SERVICE_ID`: Service UUID or metadata name to enable \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--help`: Show this message and exit. ### `meshagent service disable` Disable a service, stopping it and preventing future starts. **Usage**: ```console theme={null} $ meshagent service disable [OPTIONS] SERVICE_ID ``` **Arguments**: * `SERVICE_ID`: Service UUID or metadata name to disable \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--help`: Show this message and exit. ### `meshagent service get` Get a service for the project. **Usage**: ```console theme={null} $ meshagent service get [OPTIONS] SERVICE_ID ``` **Arguments**: * `SERVICE_ID`: Service UUID or metadata name to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--help`: Show this message and exit. ### `meshagent service list` List all services for the project. **Usage**: ```console theme={null} $ meshagent service list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--room TEXT`: Room name * `--help`: Show this message and exit. ### `meshagent service delete` Delete a service. **Usage**: ```console theme={null} $ meshagent service delete [OPTIONS] SERVICE_ID ``` **Arguments**: * `SERVICE_ID`: ID of the service to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--help`: Show this message and exit. ## `meshagent mcp` Bridge MCP servers into MeshAgent rooms **Usage**: ```console theme={null} $ meshagent mcp [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `sse`: Connect an MCP server over SSE and... * `http`: Connect an MCP server over streamable HTTP... * `stdio`: Run an MCP server over stdio and register... * `http-proxy`: Expose a stdio MCP server over streamable... * `sse-proxy`: Expose a stdio MCP server over SSE * `stdio-service`: Run a stdio MCP server as an HTTP service ### `meshagent mcp sse` Connect an MCP server over SSE and register it as a toolkit **Usage**: ```console theme={null} $ meshagent mcp sse [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--name TEXT`: Participant name \[default: cli] * `--role TEXT`: \[default: tool] * `--url TEXT`: SSE URL for the MCP server \[required] * `-H, --header TEXT`: Request header (KEY:VALUE). Repeat for multiple headers * `--toolkit-name TEXT`: Toolkit name to register in the room (default: mcp) * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ### `meshagent mcp http` Connect an MCP server over streamable HTTP and register it as a toolkit **Usage**: ```console theme={null} $ meshagent mcp http [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--name TEXT`: Participant name \[default: cli] * `--role TEXT`: \[default: tool] * `--url TEXT`: Streamable HTTP URL for the MCP server \[required] * `-H, --header TEXT`: Request header (KEY:VALUE). Repeat for multiple headers * `--toolkit-name TEXT`: Toolkit name to register in the room (default: mcp) * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ### `meshagent mcp stdio` Run an MCP server over stdio and register it as a toolkit **Usage**: ```console theme={null} $ meshagent mcp stdio [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--name TEXT`: Participant name \[default: cli] * `--role TEXT`: \[default: tool] * `--command TEXT`: Command to start an MCP server over stdio (quoted string) \[required] * `--toolkit-name TEXT`: Toolkit name to register in the room (default: mcp) * `-e, --env TEXT`: KEY=VALUE * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ### `meshagent mcp http-proxy` Expose a stdio MCP server over streamable HTTP **Usage**: ```console theme={null} $ meshagent mcp http-proxy [OPTIONS] ``` **Options**: * `--command TEXT`: Command to start the MCP server (stdio transport) \[required] * `--host TEXT`: Host to bind the proxy server on * `--port INTEGER`: Port to bind the proxy server on * `--path TEXT`: HTTP path to mount the proxy server at * `--name TEXT`: Display name for the proxy server * `-e, --env TEXT`: KEY=VALUE * `--help`: Show this message and exit. ### `meshagent mcp sse-proxy` Expose a stdio MCP server over SSE **Usage**: ```console theme={null} $ meshagent mcp sse-proxy [OPTIONS] ``` **Options**: * `--command TEXT`: Command to start the MCP server (stdio transport) \[required] * `--host TEXT`: Host to bind the proxy server on * `--port INTEGER`: Port to bind the proxy server on * `--path TEXT`: SSE path to mount the proxy at * `--name TEXT`: Display name for the proxy server * `-e, --env TEXT`: KEY=VALUE * `--help`: Show this message and exit. ### `meshagent mcp stdio-service` Run a stdio MCP server as an HTTP service **Usage**: ```console theme={null} $ meshagent mcp stdio-service [OPTIONS] ``` **Options**: * `--command TEXT`: Command to start an MCP server over stdio (quoted string) \[required] * `--host TEXT`: Host to bind the service on * `--port INTEGER`: Port to bind the service on * `--webhook-secret TEXT`: Optional webhook secret for authenticating requests * `--path TEXT`: HTTP path to mount the service at * `--toolkit-name TEXT`: Toolkit name to expose (default: mcp) * `-e, --env TEXT`: KEY=VALUE * `--help`: Show this message and exit. ## `meshagent rooms` Create, list, and manage rooms in a project **Usage**: ```console theme={null} $ meshagent rooms [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a room in the project. * `delete`: Delete a room by ID (or by name if --name... * `update`: Update a room's name or enabled state (ID... * `list`: List rooms in the project. * `get`: Get a single room by name or ID. * `status`: Show whether a room currently has an... * `events`: List recent room lifecycle history across... ### `meshagent rooms create` Create a room in the project. **Usage**: ```console theme={null} $ meshagent rooms create [OPTIONS] [NAME] ``` **Arguments**: * `[NAME]`: Room name **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--owner / --no-owner`: Add the active user as the room owner. \[default: owner] * `--if-not-exists / --no-if-not-exists`: Do not error if the room already exists \[default: no-if-not-exists] * `--metadata TEXT`: Optional JSON object for room metadata * `--annotations TEXT`: Optional JSON object for room annotations, e.g. \{"meshagent.storage.class":"ephemeral"} * `--help`: Show this message and exit. ### `meshagent rooms delete` Delete a room by ID (or by name if --name is supplied). **Usage**: ```console theme={null} $ meshagent rooms delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT`: Room ID (preferred) * `--name TEXT` * `--help`: Show this message and exit. ### `meshagent rooms update` Update a room's name or enabled state (ID is preferred; name will be resolved to ID if needed). **Usage**: ```console theme={null} $ meshagent rooms update [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT`: Room ID (preferred) * `--name TEXT` * `--new-name TEXT`: New room name * `--enabled / --disabled`: Enable or disable the room * `--annotations TEXT`: Optional JSON object for room annotations, e.g. \{"meshagent.storage.class":"ephemeral"} * `--help`: Show this message and exit. ### `meshagent rooms list` List rooms in the project. **Usage**: ```console theme={null} $ meshagent rooms list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--count INTEGER RANGE`: Max rooms to return \[default: 100; 1\<=x\<=500] * `--offset INTEGER RANGE`: Offset for pagination \[default: 0; x>=0] * `--order-by TEXT`: Order rooms by name; only "room\_name" is supported \[default: room\_name] * `--filter TEXT`: Lowercase contains filter for room names * `--all`: Show all rooms in the project instead of only rooms you can access * `--help`: Show this message and exit. ### `meshagent rooms get` Get a single room by name or ID. **Usage**: ```console theme={null} $ meshagent rooms get [OPTIONS] [ROOM] ``` **Arguments**: * `[ROOM]`: Room name or ID **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent rooms status` Show whether a room currently has an allocated room server. **Usage**: ```console theme={null} $ meshagent rooms status [OPTIONS] ROOM ``` **Arguments**: * `ROOM`: Room name or ID \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent rooms events` List recent room lifecycle history across all sessions. **Usage**: ```console theme={null} $ meshagent rooms events [OPTIONS] ROOM ``` **Arguments**: * `ROOM`: Room name or ID \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--count, --limit INTEGER RANGE`: Max events to return \[default: 100; 1\<=x\<=500] * `--help`: Show this message and exit. ## `meshagent volumes` Manage durable storage volumes for a room **Usage**: ```console theme={null} $ meshagent volumes [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list` * `create` * `delete` * `expand` ### `meshagent volumes list` **Usage**: ```console theme={null} $ meshagent volumes list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent volumes create` **Usage**: ```console theme={null} $ meshagent volumes create [OPTIONS] NAME ``` **Arguments**: * `NAME`: Volume name \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--description TEXT`: Volume description * `--metadata TEXT`: Volume metadata JSON object * `--annotations TEXT`: Volume annotations JSON object * `--type TEXT`: Storage type: standard, juice, or zerofs * `--max-size INTEGER`: Maximum volume size in MB (JuiceFS and ZeroFS only) * `--help`: Show this message and exit. ### `meshagent volumes delete` **Usage**: ```console theme={null} $ meshagent volumes delete [OPTIONS] VOLUME ``` **Arguments**: * `VOLUME`: Volume ID or name \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent volumes expand` **Usage**: ```console theme={null} $ meshagent volumes expand [OPTIONS] VOLUME ``` **Arguments**: * `VOLUME`: Volume ID or name \[required] **Options**: * `--max-size INTEGER`: New maximum volume size in MB \[required] * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent agent` Create, list, and manage managed agents in a project **Usage**: ```console theme={null} $ meshagent agent [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a managed agent in the project. * `delete`: Delete a managed agent from the project. * `update`: Update a managed agent configuration. * `list`: List managed agents in the project. * `get`: Get a managed agent configuration. * `use`: Use a managed agent over its websocket... ### `meshagent agent create` Create a managed agent in the project. **Usage**: ```console theme={null} $ meshagent agent create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-c, --configuration TEXT`: ManagedAgentSpec JSON \[required] * `--thread-isolation [global|participant]`: Thread isolation mode for the managed agent * `--if-not-exists / --no-if-not-exists`: Do not error if the agent already exists \[default: no-if-not-exists] * `--help`: Show this message and exit. ### `meshagent agent delete` Delete a managed agent from the project. **Usage**: ```console theme={null} $ meshagent agent delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT`: Agent ID (preferred) * `--name TEXT`: Agent name * `--help`: Show this message and exit. ### `meshagent agent update` Update a managed agent configuration. **Usage**: ```console theme={null} $ meshagent agent update [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--id TEXT`: Agent ID (preferred) * `--name TEXT`: Current agent name * `-c, --configuration TEXT`: ManagedAgentSpec JSON \[required] * `--thread-isolation [global|participant]`: Thread isolation mode for the managed agent * `--help`: Show this message and exit. ### `meshagent agent list` List managed agents in the project. **Usage**: ```console theme={null} $ meshagent agent list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--count INTEGER RANGE`: Max agents to return \[default: 100; 1\<=x\<=500] * `--offset INTEGER RANGE`: Offset for pagination \[default: 0; x>=0] * `--order-by TEXT`: Order agents by name; only "agent\_name" is supported \[default: agent\_name] * `--filter TEXT`: Lowercase contains filter for agent names * `--help`: Show this message and exit. ### `meshagent agent get` Get a managed agent configuration. **Usage**: ```console theme={null} $ meshagent agent get [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--name TEXT`: Agent name \[required] * `--help`: Show this message and exit. ### `meshagent agent use` Use a managed agent over its websocket connection. **Usage**: ```console theme={null} $ meshagent agent use [OPTIONS] [AGENT] ``` **Arguments**: * `[AGENT]`: Agent name **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--name TEXT`: Agent name * `--thread-id TEXT`: Thread id to open * `--load`: Replay persisted thread messages when opening * `--since-turn TEXT`: Replay persisted thread messages starting with this turn id * `-m, --message TEXT`: Send one message without opening the TUI * `-o, --output [text|json]`: Output format for one-shot messages \[default: text] * `--help`: Show this message and exit. ## `meshagent mailbox` Manage mailboxes for your project **Usage**: ```console theme={null} $ meshagent mailbox [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a mailbox attached to the project. * `update`: Update a mailbox routing configuration. * `get`: Get mailbox details. * `deliveries`: List outbound deliveries for a mailbox,... * `delivery`: Get the current status and SMTP details... * `delivery-events`: List a delivery's events in chronological... * `list`: List mailboxes for the project. * `delete`: Delete a mailbox. ### `meshagent mailbox create` Create a mailbox attached to the project. **Usage**: ```console theme={null} $ meshagent mailbox create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-a, --address TEXT`: Mailbox email address (unique per project) \[required] * `--room TEXT`: Room name * `-q, --queue TEXT`: Queue name to deliver inbound messages to \[required] * `--public`: Queue name to deliver inbound messages to * `-n, --annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent mailbox update` Update a mailbox routing configuration. **Usage**: ```console theme={null} $ meshagent mailbox update [OPTIONS] ADDRESS ``` **Arguments**: * `ADDRESS`: Mailbox email address to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-r, --room TEXT`: Room name to route inbound mail into * `-q, --queue TEXT`: Queue name to deliver inbound messages to * `--public`: Queue name to deliver inbound messages to * `-n, --annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent mailbox get` Get mailbox details. **Usage**: ```console theme={null} $ meshagent mailbox get [OPTIONS] ADDRESS ``` **Arguments**: * `ADDRESS`: Mailbox address to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent mailbox deliveries` List outbound deliveries for a mailbox, newest submission first. **Usage**: ```console theme={null} $ meshagent mailbox deliveries [OPTIONS] ADDRESS ``` **Arguments**: * `ADDRESS`: Mailbox address \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--status [accepted|deferred|delivered|failed]`: Filter by current delivery status * `--recipient TEXT`: Recipient contains filter * `--message-id TEXT`: Exact Message-ID filter * `--count INTEGER RANGE`: Maximum rows to return \[default: 100; x>=1] * `--offset INTEGER RANGE`: Row offset for pagination \[default: 0; x>=0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent mailbox delivery` Get the current status and SMTP details for a delivery. **Usage**: ```console theme={null} $ meshagent mailbox delivery [OPTIONS] ADDRESS DELIVERY_ID ``` **Arguments**: * `ADDRESS`: Mailbox address \[required] * `DELIVERY_ID`: Delivery ID \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent mailbox delivery-events` List a delivery's events in chronological order. **Usage**: ```console theme={null} $ meshagent mailbox delivery-events [OPTIONS] ADDRESS DELIVERY_ID ``` **Arguments**: * `ADDRESS`: Mailbox address \[required] * `DELIVERY_ID`: Delivery ID \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--count INTEGER RANGE`: Maximum rows to return \[default: 100; x>=1] * `--offset INTEGER RANGE`: Row offset for pagination \[default: 0; x>=0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent mailbox list` List mailboxes for the project. **Usage**: ```console theme={null} $ meshagent mailbox list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--filter TEXT`: Lowercase contains filter * `--count INTEGER RANGE`: Maximum number of mailboxes to return \[default: 100; x>=1] * `--offset INTEGER RANGE`: Row offset for pagination \[default: 0; x>=0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent mailbox delete` Delete a mailbox. **Usage**: ```console theme={null} $ meshagent mailbox delete [OPTIONS] ADDRESS ``` **Arguments**: * `ADDRESS`: Mailbox address to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent feed` Manage feeds for your project **Usage**: ```console theme={null} $ meshagent feed [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a feed. * `update`: Update a feed. * `get`: Get feed details. * `list`: List feeds for the project. * `delete`: Delete a feed. * `send`: Publish a single JSON message to a feed. * `send-batch`: Publish a JSONL file to a feed. ### `meshagent feed create` Create a feed. **Usage**: ```console theme={null} $ meshagent feed create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-n, --name TEXT`: Feed name \[required] * `-d, --description TEXT`: Feed description * `--visibility TEXT`: Feed visibility \[default: private] * `--paused`: Create the feed in a paused state * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--message-schema TEXT`: JSON schema as inline JSON * `--message-schema-file PATH`: Path to a JSON schema file * `--help`: Show this message and exit. ### `meshagent feed update` Update a feed. **Usage**: ```console theme={null} $ meshagent feed update [OPTIONS] FEED_ID ``` **Arguments**: * `FEED_ID`: Feed id to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-n, --name TEXT`: Feed name * `-d, --description TEXT`: Feed description * `--paused`: Pause the feed * `--resume`: Resume a paused feed * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--message-schema TEXT`: JSON schema as inline JSON * `--message-schema-file PATH`: Path to a JSON schema file * `--clear-message-schema`: Remove the existing message schema * `--help`: Show this message and exit. ### `meshagent feed get` Get feed details. **Usage**: ```console theme={null} $ meshagent feed get [OPTIONS] FEED_ID ``` **Arguments**: * `FEED_ID`: Feed id to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent feed list` List feeds for the project. **Usage**: ```console theme={null} $ meshagent feed list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name to filter feeds by * `--filter TEXT`: Lowercase contains filter * `--count INTEGER`: Maximum number of feeds to return \[default: 100] * `--offset INTEGER`: Row offset for pagination \[default: 0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent feed delete` Delete a feed. **Usage**: ```console theme={null} $ meshagent feed delete [OPTIONS] FEED_ID ``` **Arguments**: * `FEED_ID`: Feed id to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent feed send` Publish a single JSON message to a feed. **Usage**: ```console theme={null} $ meshagent feed send [OPTIONS] FEED_ID ``` **Arguments**: * `FEED_ID`: Feed id to publish to \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--message TEXT`: Inline JSON message * `--message-file PATH`: Path to a JSON file * `--help`: Show this message and exit. ### `meshagent feed send-batch` Publish a JSONL file to a feed. **Usage**: ```console theme={null} $ meshagent feed send-batch [OPTIONS] FEED_ID ``` **Arguments**: * `FEED_ID`: Feed id to publish to \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--jsonl-file PATH`: Path to a JSONL file \[required] * `--help`: Show this message and exit. ## `meshagent subscription` Manage feed subscriptions for your project **Usage**: ```console theme={null} $ meshagent subscription [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a feed subscription. * `update`: Update a feed subscription. * `get`: Get feed subscription details. * `list`: List subscriptions for a feed. * `delete`: Delete a feed subscription. ### `meshagent subscription create` Create a feed subscription. **Usage**: ```console theme={null} $ meshagent subscription create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--feed-id TEXT`: Feed id \[required] * `--room TEXT`: Room name \[required] * `--path TEXT`: Storage path prefix \[required] * `--filename-datetime-format TEXT`: GCP Cloud Storage filename datetime format. Use slashes to bucket files, for example YYYY/MM/DD/hh\_mm\_ssZ. * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent subscription update` Update a feed subscription. **Usage**: ```console theme={null} $ meshagent subscription update [OPTIONS] SUBSCRIPTION_ID ``` **Arguments**: * `SUBSCRIPTION_ID`: Subscription id to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--feed-id TEXT`: Feed id \[required] * `--filename-datetime-format TEXT`: GCP Cloud Storage filename datetime format. Pass an empty string to restore the default. * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent subscription get` Get feed subscription details. **Usage**: ```console theme={null} $ meshagent subscription get [OPTIONS] SUBSCRIPTION_ID ``` **Arguments**: * `SUBSCRIPTION_ID`: Subscription id to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--feed-id TEXT`: Feed id \[required] * `--help`: Show this message and exit. ### `meshagent subscription list` List subscriptions for a feed. **Usage**: ```console theme={null} $ meshagent subscription list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--feed-id TEXT`: Feed id \[required] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent subscription delete` Delete a feed subscription. **Usage**: ```console theme={null} $ meshagent subscription delete [OPTIONS] SUBSCRIPTION_ID ``` **Arguments**: * `SUBSCRIPTION_ID`: Subscription id to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--feed-id TEXT`: Feed id \[required] * `--help`: Show this message and exit. ## `meshagent route` Manage routes for your project **Usage**: ```console theme={null} $ meshagent route [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a route attached to the project. * `update`: Update a route configuration. * `get`: Get route details. * `list`: List routes for the project. * `delete`: Delete a route. ### `meshagent route create` Create a route attached to the project. Use a short, DNS-safe domain name that matches the suffix accepted by your environment. When routing to a room service, include the meshagent.service.id annotation so the route targets the created service. **Usage**: ```console theme={null} $ meshagent route create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-d, --domain TEXT`: Domain name to route (unique per project). Keep it short and DNS-safe; long room-name-derived domains may be rejected. * `-f, --file TEXT`: Path to a RouteSpec YAML or JSON file * `--room TEXT`: Room name * `-p, --port TEXT`: Published port to route to * `--path TEXT`: Public URL path to expose \[default: /] * `--content-path, --room-path TEXT`: Room storage subpath to serve directly * `--cors TEXT`: CORS rules as a JSON array * `--index / --no-index`: Serve index.html for directories * `--iap / --no-iap`: Require identity-aware proxy access * `--compression TEXT`: brotli, gzip, or none * `-n, --annotations TEXT`: annotations in json format \{"name":"value"}. When routing to a room service, include meshagent.service.id. * `--help`: Show this message and exit. ### `meshagent route update` Update a route configuration. **Usage**: ```console theme={null} $ meshagent route update [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Domain name to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-f, --file TEXT`: Path to a RouteSpec YAML or JSON file * `-r, --room TEXT`: Room name to route traffic into * `-p, --port TEXT`: Published port to route to * `--path TEXT`: Public URL path to expose * `--content-path, --room-path TEXT`: Room storage subpath to serve directly * `--cors TEXT`: CORS rules as a JSON array * `--index / --no-index`: Serve index.html for directories * `--iap / --no-iap`: Require identity-aware proxy access * `--compression TEXT`: brotli, gzip, or none * `-n, --annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent route get` Get route details. **Usage**: ```console theme={null} $ meshagent route get [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Domain name to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent route list` List routes for the project. **Usage**: ```console theme={null} $ meshagent route list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name * `--filter TEXT`: Lowercase contains filter * `--count INTEGER`: Maximum number of routes to return \[default: 100] * `--offset INTEGER`: Row offset for pagination \[default: 0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent route delete` Delete a route. **Usage**: ```console theme={null} $ meshagent route delete [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Domain name to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent custom-domain` Manage custom domains for project routes **Usage**: ```console theme={null} $ meshagent custom-domain [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Register an immutable custom domain and... * `get`: Show availability and the DNS records that... * `list`: List registered custom domains and... * `delete`: Delete a custom domain after all covered... ### `meshagent custom-domain create` Register an immutable custom domain and begin certificate provisioning. **Usage**: ```console theme={null} $ meshagent custom-domain create [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Exact domain or wildcard such as \*.example.com \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent custom-domain get` Show availability and the DNS records that must be published. **Usage**: ```console theme={null} $ meshagent custom-domain get [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Exact registered domain \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent custom-domain list` List registered custom domains and certificate availability. **Usage**: ```console theme={null} $ meshagent custom-domain list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--filter TEXT`: Lowercase contains filter * `--count INTEGER`: Maximum number of domains to return \[default: 100] * `--view [my|all]`: List directly accessible domains or all domains \[default: my] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent custom-domain delete` Delete a custom domain after all covered routes have been removed. **Usage**: ```console theme={null} $ meshagent custom-domain delete [OPTIONS] DOMAIN ``` **Arguments**: * `DOMAIN`: Exact registered domain \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent registry` Manage registries for your project **Usage**: ```console theme={null} $ meshagent registry [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `create`: Create a project registry repository. * `update`: Update a project registry repository. * `get`: Get registry details. * `list`: List registries for the project. * `delete`: Delete a project registry repository by id... ### `meshagent registry create` Create a project registry repository. **Usage**: ```console theme={null} $ meshagent registry create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-n, --name TEXT`: Repository path in the public registry, for example 'apps/demo' \[required] * `-d, --description TEXT`: Human-readable description * `-a, --annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent registry update` Update a project registry repository. **Usage**: ```console theme={null} $ meshagent registry update [OPTIONS] REPOSITORY_ID ``` **Arguments**: * `REPOSITORY_ID`: Repository id to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-n, --name TEXT`: Updated repository path * `-d, --description TEXT`: Updated description * `-a, --annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. ### `meshagent registry get` Get registry details. **Usage**: ```console theme={null} $ meshagent registry get [OPTIONS] REPOSITORY_ID ``` **Arguments**: * `REPOSITORY_ID`: Repository id to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent registry list` List registries for the project. **Usage**: ```console theme={null} $ meshagent registry list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent registry delete` Delete a project registry repository by id or name. **Usage**: ```console theme={null} $ meshagent registry delete [OPTIONS] [REPOSITORY] ``` **Arguments**: * `[REPOSITORY]`: Repository id or name to delete **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--name TEXT`: Repository name to delete * `--help`: Show this message and exit. ## `meshagent build` Build a container image inside a room. **Usage**: ```console theme={null} $ meshagent build [OPTIONS] PATH ``` **Arguments**: * `PATH`: Local directory to use as the Docker build context. \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. * `--room TEXT`: Existing room name. * `-t, --tag TEXT`: Image tag to build. Supports \:\, \/\:\, or \/\/\:\. Shorthand forms resolve against the configured MeshAgent registry. \[required] * `-f, --file TEXT`: Dockerfile path relative to PATH. * `--builder-name TEXT`: Optional reusable builder name for streamed local builds. * `--private / --public`: Whether the build container is private to the participant \[default: public] * `--optimize / --no-optimize`: Whether to optimize room image outputs with Nydus before publishing. Enabled by default. \[default: optimize] * `--cred TEXT`: Docker creds (username,password) or (registry,username,password) * `--latest`: Also publish the built image as :latest in the same repository. * `--help`: Show this message and exit. ## `meshagent deploy` Create or update a room service from an image, optionally building it first. The target room must already exist. If .meshagent/deploy.yaml exists, deploy prompts for template values in TUI mode and saves them to .meshagent/values.yaml. Use `meshagent deploy describe` to inspect the local deploy spec. Happy path for a Dockerfile app: run 'meshagent deploy PATH --room \ --tag \ --public --domain \'. Use 'meshagent config get domains.pages' to find the pages domain for --domain. If PATH does not include a Dockerfile yet, create a minimal Dockerfile in the app directory first or create one elsewhere in PATH and pass it with --file. **Usage**: ```console theme={null} $ meshagent deploy [OPTIONS] [PATH] ``` **Arguments**: * `[PATH]`: Local directory to use as the Docker build context before deploy. **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. * `--room TEXT`: Existing room name. * `-t, --tag TEXT`: Image tag to deploy, e.g. repo/name:tag. When used with PATH, shorthand \:\ and \/\:\ resolve against the configured MeshAgent registry. \[required] * `-f, --file TEXT`: Dockerfile path relative to PATH. Only used with PATH. * `--optimize / --no-optimize`: Whether to optimize room image outputs with Nydus during the build stage. Enabled by default. Only used with PATH. \[default: optimize] * `--cred TEXT`: Docker creds (username,password) or (registry,username,password) * `--builder-name TEXT`: Optional reusable builder name for streamed local pack builds. * `--latest`: Also publish the built PATH image as :latest in the same repository. Only used with PATH. * `--domain TEXT`: Create or update a room route for the deployed service and return a public URL. Use this with --public when you need an external URL from deploy. Use 'meshagent config get domains.pages' to find the pages domain for --domain. Requires exactly one published service port. * `--email TEXT`: Create or update a public mailbox for the deployed service. When a local deploy template has an email variable, that value is used unless --email is passed. * `--values TEXT`: YAML file containing deploy template values. Can be passed multiple times; later files override earlier files. * `--set TEXT`: Set a deploy template value as KEY=VALUE. Can be passed multiple times. * `--extra-port TEXT`: Add an extra route path to DOMAIN as TARGET:/path. TARGET can be PORT, SERVICE, or SERVICE:PORT. Can be passed multiple times. The target must already be published by a room service. * `--validation-mode TEXT`: Request validation annotation mode for private published service ports: default, cookie, or none. \[default: default] * `--template TEXT`: Allowed values: agent, none. agent: MeshAgent mounts room storage at /data, sets MESHAGENT\_TOKEN, OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, GROK\_API\_KEY, and XAI\_API\_KEY to a container-scoped MeshAgent token. agent also sets SMTP\_PASSWORD to that token, SMTP\_USERNAME to the container name, SMTP\_PORT to 587, SMTP\_HOSTNAME from MESHAGENT\_MAIL\_DOMAIN when available, plus OPENAI\_BASE\_URL, ANTHROPIC\_BASE\_URL, GROK\_BASE\_URL, XAI\_BASE\_URL, MESHAGENT\_API\_URL, MESHAGENT\_ROOM\_URL, MESHAGENT\_ROOM, MESHAGENT\_PROJECT\_ID, MESHAGENT\_SESSION\_ID, OTEL\_ENDPOINT, OTEL\_PYTHON\_LOG\_LEVEL, and MESHAGENT\_MAIL\_DOMAIN from the room runtime when available. Manual env values win. none: MeshAgent applies no template defaults. \[default: agent] * `--liveness TEXT`: HTTP path to use for service liveness checks. Defaults to / for new or missing HTTP liveness paths. * `--room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--image-mount TEXT`: Mount image as \=\\[:ro|rw] * `-e, --env TEXT`: Set environment variable as KEY=VALUE * `--env-secret TEXT`: Set environment variable from a service account secret as NAME=SECRET\_ID * `--identity TEXT`: Identity name to use for --meshagent-token. Defaults to the current token identity or the derived service name. * `--run-as TEXT`: Service account email the deployed container runs as. Required when using --env-secret. * `--meshagent-token TEXT`: Inject MESHAGENT\_TOKEN using userDefault, agentDefault, full, or a JSON ApiScope object. * `--private / --public`: Whether published service ports should stay private or be public when they are created or updated. Defaults to private. \[default: private] * `--wait / --no-wait`: Wait for the deployed service to start, stream container logs, and verify the route liveness URL when --domain is provided. \[default: wait] * `--help`: Show this message and exit. ## `meshagent scheduled-task` Manage scheduled tasks for your project **Usage**: ```console theme={null} $ meshagent scheduled-task [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `add`: Add a scheduled task. * `list`: List scheduled tasks. * `update`: Update a scheduled task. * `runs`: List runs for a scheduled task. * `delete`: Delete a scheduled task. ### `meshagent scheduled-task add` Add a scheduled task. **Usage**: ```console theme={null} $ meshagent scheduled-task add [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-r, --room TEXT`: Room name * `-f, --file TEXT`: Path to a ScheduledTaskSpec YAML file \[required] * `--help`: Show this message and exit. ### `meshagent scheduled-task list` List scheduled tasks. **Usage**: ```console theme={null} $ meshagent scheduled-task list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-r, --room TEXT`: Filter by room name * `--id, --task-id TEXT`: Filter by scheduled task id * `--active`: Filter to active tasks only * `--inactive`: Filter to inactive tasks only * `--filter TEXT`: Lowercase contains filter * `--count INTEGER`: Maximum number of tasks to return \[default: 100] * `--offset INTEGER`: Row offset for pagination \[default: 0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent scheduled-task update` Update a scheduled task. **Usage**: ```console theme={null} $ meshagent scheduled-task update [OPTIONS] TASK_ID ``` **Arguments**: * `TASK_ID`: Scheduled task id to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-f, --file TEXT`: Path to a replacement ScheduledTaskSpec YAML file \[required] * `--help`: Show this message and exit. ### `meshagent scheduled-task runs` List runs for a scheduled task. **Usage**: ```console theme={null} $ meshagent scheduled-task runs [OPTIONS] TASK_ID ``` **Arguments**: * `TASK_ID`: Scheduled task id \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--count INTEGER`: Maximum number of runs to return \[default: 100] * `--offset INTEGER`: Row offset for pagination \[default: 0] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent scheduled-task delete` Delete a scheduled task. **Usage**: ```console theme={null} $ meshagent scheduled-task delete [OPTIONS] TASK_ID ``` **Arguments**: * `TASK_ID`: Scheduled task id to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ## `meshagent meeting-transcriber` Join a meeting transcriber to a room **Usage**: ```console theme={null} $ meshagent meeting-transcriber [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `join`: Join a room and run the meeting... * `service` ### `meshagent meeting-transcriber join` Join a room and run the meeting transcriber agent. **Usage**: ```console theme={null} $ meshagent meeting-transcriber join [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--agent-name TEXT`: Name of the agent * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ### `meshagent meeting-transcriber service` **Usage**: ```console theme={null} $ meshagent meeting-transcriber service [OPTIONS] ``` **Options**: * `--agent-name TEXT`: Name of the agent \[required] * `--host TEXT`: Host to bind the service on * `--port INTEGER`: Port to bind the service on * `--path TEXT`: HTTP path to mount the service at \[default: /agent] * `--help`: Show this message and exit. ## `meshagent port` Forward a container port to localhost **Usage**: ```console theme={null} $ meshagent port [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-r, --room TEXT`: Room name containing the target container \[required] * `-n, --name TEXT`: Container name to port-forward into * `-c, --container-id TEXT`: Container ID to port-forward into * `-p, --port TEXT`: Port mapping in the form LOCAL:REMOTE \[required] * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. ## `meshagent voicebot` Join a voicebot to a room **Usage**: ```console theme={null} $ meshagent voicebot [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `join`: Join a room and run a voicebot agent. * `service` * `spec`: Generate a service spec for deploying a... * `deploy`: Deploy a voicebot service to a project or... ### `meshagent voicebot join` Join a room and run a voicebot agent. **Usage**: ```console theme={null} $ meshagent voicebot join [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--agent-name TEXT`: Name of the agent to call * `--token-from-env TEXT`: Name of environment variable containing a MeshAgent token * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `-rs, --require-schema TEXT`: the name or url of a required schema * `--auto-greet-message TEXT`: Message to send automatically when the bot joins * `--auto-greet-prompt TEXT`: Prompt to generate an auto-greet message * `--voice TEXT`: OpenAI Realtime voice preset to use * `--key TEXT`: an api key to sign the token with * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--help`: Show this message and exit. ### `meshagent voicebot service` **Usage**: ```console theme={null} $ meshagent voicebot service [OPTIONS] ``` **Options**: * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `-rs, --require-schema TEXT`: the name or url of a required schema * `--auto-greet-message TEXT`: Message to send automatically when the bot joins * `--auto-greet-prompt TEXT`: Prompt to generate an auto-greet message * `--voice TEXT`: OpenAI Realtime voice preset to use * `--host TEXT`: Host to bind the service on * `--port INTEGER`: Port to bind the service on * `--path TEXT`: HTTP path to mount the service at * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--help`: Show this message and exit. ### `meshagent voicebot spec` Generate a service spec for deploying a voicebot. **Usage**: ```console theme={null} $ meshagent voicebot spec [OPTIONS] ``` **Options**: * `--service-name TEXT`: service name * `--service-description TEXT`: service description * `--service-title TEXT`: a display name for the service * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `-rs, --require-schema TEXT`: the name or url of a required schema * `--auto-greet-message TEXT`: Message to send automatically when the bot joins * `--auto-greet-prompt TEXT`: Prompt to generate an auto-greet message * `--voice TEXT`: OpenAI Realtime voice preset to use * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--help`: Show this message and exit. ### `meshagent voicebot deploy` Deploy a voicebot service to a project or room. **Usage**: ```console theme={null} $ meshagent voicebot deploy [OPTIONS] ``` **Options**: * `--service-name TEXT`: service name * `--service-description TEXT`: service description * `--service-title TEXT`: a display name for the service * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `-rs, --require-schema TEXT`: the name or url of a required schema * `--auto-greet-message TEXT`: Message to send automatically when the bot joins * `--auto-greet-prompt TEXT`: Prompt to generate an auto-greet message * `--voice TEXT`: OpenAI Realtime voice preset to use * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: The name of a room to create the service for * `--help`: Show this message and exit. ## `meshagent process` Run process-backed agents **Usage**: ```console theme={null} $ meshagent process [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `join`: Join a room and run a process-backed agent. * `service`: Add a process-backed agent service to the... * `spec`: Generate a service spec for deploying a... * `deploy`: Deploy a process-backed agent service. * `run`: Run a process-backed agent and wait for... * `threads`: List threads for a process-backed agent. * `messages`: List messages in a process-backed agent... * `grep`: Search coalesced messages in a... * `use`: Send a one-shot or interactive message to... ### `meshagent process join` Join a room and run a process-backed agent. **Usage**: ```console theme={null} $ meshagent process join [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--agent-name TEXT`: Name of the agent to call * `--token-from-env TEXT`: Name of environment variable containing a MeshAgent token * `-r, --rule TEXT`: a system rule * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--rules-file TEXT` * `--instructions TEXT`: a path in the configured storage toolkit to a rules file that will be loaded at runtime * `--preamble-rule / --no-preamble-rule`: Include the default rule asking the model to send concise pre-tool preambles when no custom rules are configured. \[default: preamble-rule] * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `--tool-search [room|agent|none]`: Expose required toolkits through OpenAI Responses tool search. Use agent for statically configured non-OpenAI builtin tools, room for those plus annotated room toolkits, or none. \[default: none] * `-s, --schema TEXT`: the name or url of a required schema * `--model TEXT`: Name of an LLM model to make available. Can be repeated. \[default: gpt-5.6-sol] * `--backend TEXT`: Process backend to make available. Can be repeated. Supported: llm, codex, chat. * `--image-generation TEXT`: Name of an image gen model * `--computer-use / --no-computer-use`: Enable computer use \[default: no-computer-use] * `--shell / --no-shell`: Enable function shell tool calling \[default: no-shell] * `--apply-patch / --no-apply-patch`: Enable apply patch tool \[default: no-apply-patch] * `--web-search / --no-web-search`: Enable web search tool calling \[default: no-web-search] * `--web-fetch / --no-web-fetch`: Enable web fetch tool calling \[default: no-web-fetch] * `--script-tool / --no-script-tool`: Enable script tool calling \[default: no-script-tool] * `--discover-script-tools / --no-discover-script-tools`: Automatically add script tools from the room \[default: no-discover-script-tools] * `--mcp / --no-mcp`: Enable mcp tool calling \[default: no-mcp] * `--storage / --no-storage`: Enable storage toolkit \[default: no-storage] * `--storage-tool-local-path TEXT`: Mount local path as \:\\[:ro|rw] * `--storage-tool-room-path TEXT`: Mount room path as \:\\[:ro|rw] * `--shell-room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--shell-empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--shell-tool-config-mount TEXT`: Mount meshagent runtime config files read-only into \ * `--shell-image-mount TEXT`: Mount image as \=\\[:ro|rw] * `--starting-url TEXT`: Initial URL to open when starting a computer-use browser session * `--allow-goto-url`: Expose the goto URL helper tool for computer use * `--advanced-shell`: Enable the managed container toolkit with start/list/stop/run tools. * `--dataset-namespace TEXT`: Use a specific dataset namespace * `--table-read TEXT`: Enable table read tools for a specific table * `--table-write TEXT`: Enable table write tools for a specific table * `--read-only-storage`: Enable read only storage toolkit * `--time / --no-time`: Enable time/datetime tools \[default: time] * `--uuid`: Enable UUID generation tools * `--use-memory TEXT`: Use memories toolkit for \ or \/\ * `--memory-model TEXT`: Model name for memory LLM ingestion * `--document-authoring`: Enable MeshDocument authoring * `--discovery`: Enable discovery of agents and tools * `--working-dir TEXT`: The default working directory for shell commands * `--key TEXT`: an api key to sign the token with * `--llm-participant TEXT`: Delegate LLM interactions to a remote participant * `--llm-delegation [required|optional]`: Require per-turn LLM delegation or allow it when provided. \[default: optional] * `--decision-model TEXT`: Model used for thread naming and other secondary LLM decisions * `--transcription-model TEXT`: Realtime input audio transcription model. \[default: gpt-realtime-whisper] * `--voice TEXT`: Default OpenAI Realtime voice preset. * `--turn-detection [none|automatic]`: OpenAI Realtime audio turn detection mode: none or automatic. \[default: none] * `--realtime-protocol TEXT`: Realtime connection protocol to advertise for OpenAI Realtime. Pass multiple times to set an ordered preference list. * `--output-modality TEXT`: Restrict supported response output modalities to text or audio. Pass multiple times to allow multiple output modalities; omit to allow all. * `--input-audio-format TEXT`: Realtime input audio MIME type. \[default: audio/pcm] * `--input-audio-sample-rate INTEGER`: Realtime input audio sample rate. \[default: 24000] * `--input-audio-bitrate INTEGER`: Realtime input audio bitrate. * `--output-audio-format TEXT`: Realtime output audio MIME type. \[default: audio/pcm] * `--output-audio-sample-rate INTEGER`: Realtime output audio sample rate. \[default: 24000] * `--output-audio-bitrate INTEGER`: Realtime output audio bitrate. * `--host TEXT`: Host to bind the service on * `--port INTEGER`: Port to bind the service on * `--path TEXT`: HTTP path to mount the service at * `--always-reply / --no-always-reply`: Always reply * `--threading-mode [none|default-new]`: Threading mode for thread UIs. Use 'default-new' to show a new-thread composer before loading a thread. \[default: default-new] * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--context-management [auto|standalone|none]`: Context compaction mode for OpenAI Responses process agents: auto, standalone, or none. \[default: auto] * `--compaction-threshold INTEGER`: Token threshold for OpenAI Responses context compaction. * `--max-output-tokens INTEGER`: Maximum output tokens to request from OpenAI Responses models. * `--reasoning-effort TEXT`: Reasoning effort to request from OpenAI Responses models. * `--channel TEXT`: Attach a channel to the agent process. Can be repeated. Currently supported: chat, mail:EMAIL\_ADDRESS\[?reply-all=true|false], memory, queue:QUEUE\_NAME, toolkit:NAME, command:EXECUTABLE, command:\["COMMAND","ARG"], websocket:PORT, websocket://HOST:PORT. * `--websocket-auth [iap|jwt|none]`: Authentication mode for websocket channels: jwt, iap, or none. \[default: jwt] * `--skill-dir TEXT`: an agent skills directory * `--shell-image TEXT`: an image tag to use to run shell commands in * `--delegate-shell-token / --no-delegate-shell-token`: log all requests to the llm \[default: no-delegate-shell-token] * `--shell-copy-env TEXT`: Copy local env vars into shell tool env. Accepts comma-separated names and can be repeated. * `--shell-set-env TEXT`: Set env vars in shell tool env as NAME=VALUE. Can be repeated. * `--log-llm-requests / --no-log-llm-requests`: log all requests to the llm \[default: no-log-llm-requests] * `--profile`: Print OpenTelemetry span timings for process startup and turns. * `--verbose-dataset`: Persist streaming delta events to dataset thread storage for debugging * `--save-audio-input`: Persist realtime audio input chunks to dataset thread storage as binary attachments. * `--help`: Show this message and exit. ### `meshagent process service` Add a process-backed agent service to the host. **Usage**: ```console theme={null} $ meshagent process service [OPTIONS] ``` **Options**: * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `--instructions TEXT`: a path in the configured storage toolkit to a rules file that will be loaded at runtime * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `--tool-search [room|agent|none]`: Expose required toolkits through OpenAI Responses tool search. Use agent for statically configured non-OpenAI builtin tools, room for those plus annotated room toolkits, or none. \[default: none] * `-s, --schema TEXT`: the name or url of a required schema * `--model TEXT`: Name of an LLM model to make available. Can be repeated. \[default: gpt-5.6-sol] * `--backend TEXT`: Process backend to make available. Can be repeated. Supported: llm, codex, chat. * `--image-generation TEXT`: Name of an image gen model * `--shell / --no-shell`: Enable function shell tool calling \[default: no-shell] * `--apply-patch / --no-apply-patch`: Enable apply patch tool \[default: no-apply-patch] * `--computer-use / --no-computer-use`: Enable computer use \[default: no-computer-use] * `--web-search / --no-web-search`: Enable web search tool calling \[default: no-web-search] * `--web-fetch / --no-web-fetch`: Enable web fetch tool calling \[default: no-web-fetch] * `--script-tool / --no-script-tool`: Enable script tool calling \[default: no-script-tool] * `--discover-script-tools / --no-discover-script-tools`: Automatically add script tools from the room \[default: no-discover-script-tools] * `--mcp / --no-mcp`: Enable mcp tool calling \[default: no-mcp] * `--storage / --no-storage`: Enable storage toolkit \[default: no-storage] * `--storage-tool-local-path TEXT`: Mount local path as \:\\[:ro|rw] * `--storage-tool-room-path TEXT`: Mount room path as \:\\[:ro|rw] * `--shell-room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--shell-empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--shell-tool-config-mount TEXT`: Mount meshagent runtime config files read-only into \ * `--shell-image-mount TEXT`: Mount image as \=\\[:ro|rw] * `--starting-url TEXT`: Initial URL to open when starting a computer-use browser session * `--allow-goto-url`: Expose the goto URL helper tool for computer use * `--advanced-shell`: Enable the managed container toolkit with start/list/stop/run tools. * `--dataset-namespace TEXT`: Use a specific dataset namespace * `--table-read TEXT`: Enable table read tools for a specific table * `--table-write TEXT`: Enable table write tools for a specific table * `--read-only-storage`: Enable read only storage toolkit * `--time / --no-time`: Enable time/datetime tools \[default: time] * `--uuid`: Enable UUID generation tools * `--use-memory TEXT`: Use memories toolkit for \ or \/\ * `--memory-model TEXT`: Model name for memory LLM ingestion * `--working-dir TEXT`: The default working directory for shell commands * `--require-document-authoring / --no-require-document-authoring`: Enable document authoring \[default: no-require-document-authoring] * `--discovery`: Enable discovery of agents and tools * `--llm-participant TEXT`: Delegate LLM interactions to a remote participant * `--llm-delegation [required|optional]`: Require per-turn LLM delegation or allow it when provided. \[default: optional] * `--decision-model TEXT`: Model used for thread naming and other secondary LLM decisions * `--transcription-model TEXT`: Realtime input audio transcription model. \[default: gpt-realtime-whisper] * `--voice TEXT`: Default OpenAI Realtime voice preset. * `--turn-detection [none|automatic]`: OpenAI Realtime audio turn detection mode: none or automatic. \[default: none] * `--realtime-protocol TEXT`: Realtime connection protocol to advertise for OpenAI Realtime. Pass multiple times to set an ordered preference list. * `--output-modality TEXT`: Restrict supported response output modalities to text or audio. Pass multiple times to allow multiple output modalities; omit to allow all. * `--input-audio-format TEXT`: Realtime input audio MIME type. \[default: audio/pcm] * `--input-audio-sample-rate INTEGER`: Realtime input audio sample rate. \[default: 24000] * `--input-audio-bitrate INTEGER`: Realtime input audio bitrate. * `--output-audio-format TEXT`: Realtime output audio MIME type. \[default: audio/pcm] * `--output-audio-sample-rate INTEGER`: Realtime output audio sample rate. \[default: 24000] * `--output-audio-bitrate INTEGER`: Realtime output audio bitrate. * `--host TEXT`: Host to bind the service on * `--port INTEGER`: Port to bind the service on * `--path TEXT`: HTTP path to mount the service at * `--always-reply / --no-always-reply`: Always reply * `--threading-mode [none|default-new]`: Threading mode for thread UIs. Use 'default-new' to show a new-thread composer before loading a thread. \[default: default-new] * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--context-management [auto|standalone|none]`: Context compaction mode for OpenAI Responses process agents: auto, standalone, or none. \[default: auto] * `--compaction-threshold INTEGER`: Token threshold for OpenAI Responses context compaction. * `--max-output-tokens INTEGER`: Maximum output tokens to request from OpenAI Responses models. * `--reasoning-effort TEXT`: Reasoning effort to request from OpenAI Responses models. * `--channel TEXT`: Attach a channel to the agent process. Can be repeated. Currently supported: chat, mail:EMAIL\_ADDRESS\[?reply-all=true|false], memory, queue:QUEUE\_NAME, toolkit:NAME, command:EXECUTABLE, command:\["COMMAND","ARG"], websocket:PORT, websocket://HOST:PORT. * `--skill-dir TEXT`: an agent skills directory * `--shell-image TEXT`: an image tag to use to run shell commands in * `--delegate-shell-token / --no-delegate-shell-token`: log all requests to the llm \[default: no-delegate-shell-token] * `--shell-copy-env TEXT`: Copy local env vars into shell tool env. Accepts comma-separated names and can be repeated. * `--shell-set-env TEXT`: Set env vars in shell tool env as NAME=VALUE. Can be repeated. * `--log-llm-requests / --no-log-llm-requests`: log all requests to the llm \[default: no-log-llm-requests] * `--verbose-dataset`: Persist streaming delta events to dataset thread storage for debugging * `--save-audio-input`: Persist realtime audio input chunks to dataset thread storage as binary attachments. * `--help`: Show this message and exit. ### `meshagent process spec` Generate a service spec for deploying a process-backed agent. **Usage**: ```console theme={null} $ meshagent process spec [OPTIONS] ``` **Options**: * `--service-name TEXT`: service name * `--service-description TEXT`: service description * `--service-title TEXT`: a display name for the service * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `--instructions TEXT`: a path in the configured storage toolkit to a rules file that will be loaded at runtime * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `--tool-search [room|agent|none]`: Expose required toolkits through OpenAI Responses tool search. Use agent for statically configured non-OpenAI builtin tools, room for those plus annotated room toolkits, or none. \[default: none] * `-s, --schema TEXT`: the name or url of a required schema * `--model TEXT`: Name of an LLM model to make available. Can be repeated. \[default: gpt-5.6-sol] * `--backend TEXT`: Process backend to make available. Can be repeated. Supported: llm, codex, chat. * `--image-generation TEXT`: Name of an image gen model * `--shell / --no-shell`: Enable function shell tool calling \[default: no-shell] * `--apply-patch / --no-apply-patch`: Enable apply patch tool \[default: no-apply-patch] * `--computer-use / --no-computer-use`: Enable computer use \[default: no-computer-use] * `--web-search / --no-web-search`: Enable web search tool calling \[default: no-web-search] * `--web-fetch / --no-web-fetch`: Enable web fetch tool calling \[default: no-web-fetch] * `--script-tool / --no-script-tool`: Enable script tool calling \[default: no-script-tool] * `--discover-script-tools / --no-discover-script-tools`: Automatically add script tools from the room \[default: no-discover-script-tools] * `--mcp / --no-mcp`: Enable mcp tool calling \[default: no-mcp] * `--storage / --no-storage`: Enable storage toolkit \[default: no-storage] * `--storage-tool-local-path TEXT`: Mount local path as \:\\[:ro|rw] * `--storage-tool-room-path TEXT`: Mount room path as \:\\[:ro|rw] * `--shell-room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--shell-empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--shell-tool-config-mount TEXT`: Mount meshagent runtime config files read-only into \ * `--starting-url TEXT`: Initial URL to open when starting a computer-use browser session * `--allow-goto-url`: Expose the goto URL helper tool for computer use * `--advanced-shell`: Enable the managed container toolkit with start/list/stop/run tools. * `--dataset-namespace TEXT`: Use a specific dataset namespace * `--table-read TEXT`: Enable table read tools for a specific table * `--table-write TEXT`: Enable table write tools for a specific table * `--read-only-storage`: Enable read only storage toolkit * `--time / --no-time`: Enable time/datetime tools \[default: time] * `--uuid`: Enable UUID generation tools * `--use-memory TEXT`: Use memories toolkit for \ or \/\ * `--memory-model TEXT`: Model name for memory LLM ingestion * `--working-dir TEXT`: The default working directory for shell commands * `--require-document-authoring / --no-require-document-authoring`: Enable document authoring \[default: no-require-document-authoring] * `--discovery`: Enable discovery of agents and tools * `--llm-participant TEXT`: Delegate LLM interactions to a remote participant * `--llm-delegation [required|optional]`: Require per-turn LLM delegation or allow it when provided. \[default: optional] * `--decision-model TEXT`: Model used for thread naming and other secondary LLM decisions * `--transcription-model TEXT`: Realtime input audio transcription model. \[default: gpt-realtime-whisper] * `--voice TEXT`: Default OpenAI Realtime voice preset. * `--turn-detection [none|automatic]`: OpenAI Realtime audio turn detection mode: none or automatic. \[default: none] * `--realtime-protocol TEXT`: Realtime connection protocol to advertise for OpenAI Realtime. Pass multiple times to set an ordered preference list. * `--output-modality TEXT`: Restrict supported response output modalities to text or audio. Pass multiple times to allow multiple output modalities; omit to allow all. * `--input-audio-format TEXT`: Realtime input audio MIME type. \[default: audio/pcm] * `--input-audio-sample-rate INTEGER`: Realtime input audio sample rate. \[default: 24000] * `--input-audio-bitrate INTEGER`: Realtime input audio bitrate. * `--output-audio-format TEXT`: Realtime output audio MIME type. \[default: audio/pcm] * `--output-audio-sample-rate INTEGER`: Realtime output audio sample rate. \[default: 24000] * `--output-audio-bitrate INTEGER`: Realtime output audio bitrate. * `--always-reply / --no-always-reply`: Always reply * `--threading-mode [none|default-new]`: Threading mode for thread UIs. Use 'default-new' to show a new-thread composer before loading a thread. \[default: default-new] * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--context-management [auto|standalone|none]`: Context compaction mode for OpenAI Responses process agents: auto, standalone, or none. \[default: auto] * `--compaction-threshold INTEGER`: Token threshold for OpenAI Responses context compaction. * `--max-output-tokens INTEGER`: Maximum output tokens to request from OpenAI Responses models. * `--reasoning-effort TEXT`: Reasoning effort to request from OpenAI Responses models. * `--channel TEXT`: Attach a channel to the agent process. Can be repeated. Currently supported: chat, mail:EMAIL\_ADDRESS\[?reply-all=true|false], memory, queue:QUEUE\_NAME, toolkit:NAME, command:EXECUTABLE, command:\["COMMAND","ARG"], websocket:PORT, websocket://HOST:PORT. * `--skill-dir TEXT`: an agent skills directory * `--shell-image TEXT`: an image tag to use to run shell commands in * `--delegate-shell-token / --no-delegate-shell-token`: log all requests to the llm \[default: no-delegate-shell-token] * `--shell-copy-env TEXT`: Copy local env vars into shell tool env. Accepts comma-separated names and can be repeated. * `--shell-set-env TEXT`: Set env vars in shell tool env as NAME=VALUE. Can be repeated. * `--log-llm-requests / --no-log-llm-requests`: log all requests to the llm \[default: no-log-llm-requests] * `--help`: Show this message and exit. ### `meshagent process deploy` Deploy a process-backed agent service. **Usage**: ```console theme={null} $ meshagent process deploy [OPTIONS] ``` **Options**: * `--service-name TEXT`: service name * `--service-description TEXT`: service description * `--service-title TEXT`: a display name for the service * `--agent-name TEXT`: Name of the agent to call \[required] * `-r, --rule TEXT`: a system rule * `--rules-file TEXT` * `--instructions TEXT`: a path in the configured storage toolkit to a rules file that will be loaded at runtime * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `--tool-search [room|agent|none]`: Expose required toolkits through OpenAI Responses tool search. Use agent for statically configured non-OpenAI builtin tools, room for those plus annotated room toolkits, or none. \[default: none] * `-s, --schema TEXT`: the name or url of a required schema * `--model TEXT`: Name of an LLM model to make available. Can be repeated. \[default: gpt-5.6-sol] * `--backend TEXT`: Process backend to make available. Can be repeated. Supported: llm, codex, chat. * `--image-generation TEXT`: Name of an image gen model * `--shell / --no-shell`: Enable function shell tool calling \[default: no-shell] * `--apply-patch / --no-apply-patch`: Enable apply patch tool \[default: no-apply-patch] * `--computer-use / --no-computer-use`: Enable computer use \[default: no-computer-use] * `--web-search / --no-web-search`: Enable web search tool calling \[default: no-web-search] * `--web-fetch / --no-web-fetch`: Enable web fetch tool calling \[default: no-web-fetch] * `--script-tool / --no-script-tool`: Enable script tool calling \[default: no-script-tool] * `--discover-script-tools / --no-discover-script-tools`: Automatically add script tools from the room \[default: no-discover-script-tools] * `--mcp / --no-mcp`: Enable mcp tool calling \[default: no-mcp] * `--storage / --no-storage`: Enable storage toolkit \[default: no-storage] * `--storage-tool-local-path TEXT`: Mount local path as \:\\[:ro|rw] * `--storage-tool-room-path TEXT`: Mount room path as \:\\[:ro|rw] * `--shell-room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--shell-empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--shell-tool-config-mount TEXT`: Mount meshagent runtime config files read-only into \ * `--starting-url TEXT`: Initial URL to open when starting a computer-use browser session * `--allow-goto-url`: Expose the goto URL helper tool for computer use * `--advanced-shell`: Enable the managed container toolkit with start/list/stop/run tools. * `--dataset-namespace TEXT`: Use a specific dataset namespace * `--table-read TEXT`: Enable table read tools for a specific table * `--table-write TEXT`: Enable table write tools for a specific table * `--read-only-storage`: Enable read only storage toolkit * `--time / --no-time`: Enable time/datetime tools \[default: time] * `--uuid`: Enable UUID generation tools * `--use-memory TEXT`: Use memories toolkit for \ or \/\ * `--memory-model TEXT`: Model name for memory LLM ingestion * `--working-dir TEXT`: The default working directory for shell commands * `--require-document-authoring / --no-require-document-authoring`: Enable document authoring \[default: no-require-document-authoring] * `--discovery`: Enable discovery of agents and tools * `--llm-participant TEXT`: Delegate LLM interactions to a remote participant * `--llm-delegation [required|optional]`: Require per-turn LLM delegation or allow it when provided. \[default: optional] * `--decision-model TEXT`: Model used for thread naming and other secondary LLM decisions * `--transcription-model TEXT`: Realtime input audio transcription model. \[default: gpt-realtime-whisper] * `--voice TEXT`: Default OpenAI Realtime voice preset. * `--turn-detection [none|automatic]`: OpenAI Realtime audio turn detection mode: none or automatic. \[default: none] * `--realtime-protocol TEXT`: Realtime connection protocol to advertise for OpenAI Realtime. Pass multiple times to set an ordered preference list. * `--output-modality TEXT`: Restrict supported response output modalities to text or audio. Pass multiple times to allow multiple output modalities; omit to allow all. * `--input-audio-format TEXT`: Realtime input audio MIME type. \[default: audio/pcm] * `--input-audio-sample-rate INTEGER`: Realtime input audio sample rate. \[default: 24000] * `--input-audio-bitrate INTEGER`: Realtime input audio bitrate. * `--output-audio-format TEXT`: Realtime output audio MIME type. \[default: audio/pcm] * `--output-audio-sample-rate INTEGER`: Realtime output audio sample rate. \[default: 24000] * `--output-audio-bitrate INTEGER`: Realtime output audio bitrate. * `--always-reply / --no-always-reply`: Always reply * `--threading-mode [none|default-new]`: Threading mode for thread UIs. Use 'default-new' to show a new-thread composer before loading a thread. \[default: default-new] * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--context-management [auto|standalone|none]`: Context compaction mode for OpenAI Responses process agents: auto, standalone, or none. \[default: auto] * `--compaction-threshold INTEGER`: Token threshold for OpenAI Responses context compaction. * `--max-output-tokens INTEGER`: Maximum output tokens to request from OpenAI Responses models. * `--reasoning-effort TEXT`: Reasoning effort to request from OpenAI Responses models. * `--channel TEXT`: Attach a channel to the agent process. Can be repeated. Currently supported: chat, mail:EMAIL\_ADDRESS\[?reply-all=true|false], memory, queue:QUEUE\_NAME, toolkit:NAME, command:EXECUTABLE, command:\["COMMAND","ARG"], websocket:PORT, websocket://HOST:PORT. * `--skill-dir TEXT`: an agent skills directory * `--shell-image TEXT`: an image tag to use to run shell commands in * `--delegate-shell-token / --no-delegate-shell-token`: log all requests to the llm \[default: no-delegate-shell-token] * `--shell-copy-env TEXT`: Copy local env vars into shell tool env. Accepts comma-separated names and can be repeated. * `--shell-set-env TEXT`: Set env vars in shell tool env as NAME=VALUE. Can be repeated. * `--log-llm-requests / --no-log-llm-requests`: log all requests to the llm \[default: no-log-llm-requests] * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: The name of a room to create the service for * `--help`: Show this message and exit. ### `meshagent process run` Run a process-backed agent and wait for messages. **Usage**: ```console theme={null} $ meshagent process run [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--agent-name TEXT`: Name of the agent to call * `-r, --rule TEXT`: a system rule * `-rr, --room-rules TEXT`: a path to a rules file within the room that can be used to customize the agent's behavior * `--rules-file TEXT` * `--instructions TEXT`: a path in the configured storage toolkit to a rules file that will be loaded at runtime * `--preamble-rule / --no-preamble-rule`: Include the default rule asking the model to send concise pre-tool preambles when no custom rules are configured. \[default: preamble-rule] * `-rt, --require-toolkit TEXT`: the name or url of a required toolkit * `--tool-search [room|agent|none]`: Expose required toolkits through OpenAI Responses tool search. Use agent for statically configured non-OpenAI builtin tools, room for those plus annotated room toolkits, or none. \[default: none] * `-s, --schema TEXT`: the name or url of a required schema * `--model TEXT`: Name of an LLM model to make available. Can be repeated. \[default: gpt-5.6-sol] * `--backend TEXT`: Process backend to make available. Can be repeated. Supported: llm, codex, chat. * `--image-generation TEXT`: Name of an image gen model * `--computer-use / --no-computer-use`: Enable computer use \[default: no-computer-use] * `--shell / --no-shell`: Enable function shell tool calling \[default: no-shell] * `--apply-patch / --no-apply-patch`: Enable apply patch tool \[default: no-apply-patch] * `--web-search / --no-web-search`: Enable web search tool calling \[default: no-web-search] * `--web-fetch / --no-web-fetch`: Enable web fetch tool calling \[default: no-web-fetch] * `--script-tool / --no-script-tool`: Enable script tool calling \[default: no-script-tool] * `--discover-script-tools / --no-discover-script-tools`: Automatically add script tools from the room \[default: no-discover-script-tools] * `--mcp / --no-mcp`: Enable mcp tool calling \[default: no-mcp] * `--storage / --no-storage`: Enable storage toolkit \[default: no-storage] * `--storage-tool-local-path TEXT`: Mount local path as \:\\[:ro|rw] * `--storage-tool-room-path TEXT`: Mount room path as \:\\[:ro|rw] * `--shell-room-mount TEXT`: Mount room storage as \:\\[:ro|rw] * `--shell-empty-dir-mount TEXT`: Mount empty dir at \\[:ro|rw] * `--shell-tool-config-mount TEXT`: Mount meshagent runtime config files read-only into \ * `--starting-url TEXT`: Initial URL to open when starting a computer-use browser session * `--allow-goto-url`: Expose the goto URL helper tool for computer use * `--advanced-shell`: Enable the managed container toolkit with start/list/stop/run tools. * `--dataset-namespace TEXT`: Use a specific dataset namespace * `--table-read TEXT`: Enable table read tools for a specific table * `--table-write TEXT`: Enable table write tools for a specific table * `--read-only-storage`: Enable read only storage toolkit * `--time / --no-time`: Enable time/datetime tools \[default: time] * `--uuid`: Enable UUID generation tools * `--use-memory TEXT`: Use memories toolkit for \ or \/\ * `--memory-model TEXT`: Model name for memory LLM ingestion * `--document-authoring`: Enable MeshDocument authoring * `--discovery`: Enable discovery of agents and tools * `--working-dir TEXT`: The default working directory for shell commands * `--key TEXT`: an api key to sign the token with * `--llm-participant TEXT`: Delegate LLM interactions to a remote participant * `--llm-delegation [required|optional]`: Require per-turn LLM delegation or allow it when provided. \[default: optional] * `--decision-model TEXT`: Model used for thread naming and other secondary LLM decisions * `--transcription-model TEXT`: Realtime input audio transcription model. \[default: gpt-realtime-whisper] * `--voice TEXT`: Default OpenAI Realtime voice preset. * `--turn-detection [none|automatic]`: OpenAI Realtime audio turn detection mode: none or automatic. \[default: none] * `--realtime-protocol TEXT`: Realtime connection protocol to advertise for OpenAI Realtime. Pass multiple times to set an ordered preference list. * `--output-modality TEXT`: Restrict supported response output modalities to text or audio. Pass multiple times to allow multiple output modalities; omit to allow all. * `--input-audio-format TEXT`: Realtime input audio MIME type. \[default: audio/pcm] * `--input-audio-sample-rate INTEGER`: Realtime input audio sample rate. \[default: 24000] * `--input-audio-bitrate INTEGER`: Realtime input audio bitrate. * `--output-audio-format TEXT`: Realtime output audio MIME type. \[default: audio/pcm] * `--output-audio-sample-rate INTEGER`: Realtime output audio sample rate. \[default: 24000] * `--output-audio-bitrate INTEGER`: Realtime output audio bitrate. * `--always-reply / --no-always-reply`: Always reply * `--threading-mode [none|default-new]`: Threading mode for thread UIs. Use 'default-new' to show a new-thread composer before loading a thread. \[default: default-new] * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset with a room, or none with --no-room. * `--context-management [auto|standalone|none]`: Context compaction mode for OpenAI Responses process agents: auto, standalone, or none. \[default: auto] * `--compaction-threshold INTEGER`: Token threshold for OpenAI Responses context compaction. * `--max-output-tokens INTEGER`: Maximum output tokens to request from OpenAI Responses models. * `--reasoning-effort TEXT`: Reasoning effort to request from OpenAI Responses models. * `--channel TEXT`: Attach a channel to the agent process. Can be repeated. Currently supported: chat, mail:EMAIL\_ADDRESS\[?reply-all=true|false], memory, queue:QUEUE\_NAME, toolkit:NAME, command:EXECUTABLE, command:\["COMMAND","ARG"], websocket:PORT, websocket://HOST:PORT. * `--skill-dir TEXT`: an agent skills directory * `--shell-image TEXT`: an image tag to use to run shell commands in * `--delegate-shell-token / --no-delegate-shell-token`: log all requests to the llm \[default: no-delegate-shell-token] * `--shell-copy-env TEXT`: Copy local env vars into shell tool env. Accepts comma-separated names and can be repeated. * `--shell-set-env TEXT`: Set env vars in shell tool env as NAME=VALUE. Can be repeated. * `--log-llm-requests / --no-log-llm-requests`: log all requests to the llm \[default: no-log-llm-requests] * `--verbose`: Enable verbose logging and disable default log suppression * `--profile`: Print OpenTelemetry span timings for process startup and turns. * `--verbose-dataset`: Persist streaming delta events to dataset thread storage for debugging * `--save-audio-input`: Persist realtime audio input chunks to dataset thread storage as binary attachments. * `--no-room`: Run locally without connecting to a room. Fails if room-backed storage, channels, or tools are configured. * `--websocket-auth [iap|jwt|none]`: Authentication mode for websocket channels: jwt, iap, or none. \[default: jwt] * `--user TEXT`: User name for the local websocket process run client. \[default: you] * `--thread-id TEXT`: Thread id to open * `--message TEXT`: the input message to use * `--use-web-search / --no-use-web-search`: request the web search tool * `--use-image-gen / --no-use-image-gen`: request the image gen tool * `--use-storage / --no-use-storage`: request the storage tool * `--help`: Show this message and exit. ### `meshagent process threads` List threads for a process-backed agent. **Usage**: ```console theme={null} $ meshagent process threads [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--agent-name TEXT`: Name of the agent to list threads for * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--limit INTEGER`: Maximum threads to show \[default: 20] * `--offset INTEGER`: Thread list offset \[default: 0] * `-o, --output [json|table|text]`: Output format: json, table, or text. \[default: text] * `--help`: Show this message and exit. ### `meshagent process messages` List messages in a process-backed agent thread. **Usage**: ```console theme={null} $ meshagent process messages [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--agent-name TEXT`: Name of the agent to inspect * `--thread-dir TEXT`: Thread directory for agent thread files. Defaults to /agents/\/threads for process agents when threading mode is enabled. * `--thread-storage TEXT`: Thread storage backend for process agents. Can be repeated; the first value is the default. Defaults to dataset. * `--thread-id TEXT`: Thread id to inspect \[required] * `-o, --output [json|table|text]`: Output format: json, table, or text. \[default: text] * `--help`: Show this message and exit. ### `meshagent process grep` Search coalesced messages in a process-backed agent thread. **Usage**: ```console theme={null} $ meshagent process grep [OPTIONS] PATTERN ``` **Arguments**: * `PATTERN`: Regex pattern to search for \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--thread-id TEXT`: Thread id to inspect \[required] * `-o, --output [json|table|text]`: Output format: json, table, or text. \[default: text] * `--help`: Show this message and exit. ### `meshagent process use` Send a one-shot or interactive message to a running process-backed agent. **Usage**: ```console theme={null} $ meshagent process use [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--agent-name TEXT`: Name of the agent to call * `--thread-id TEXT`: Thread id to open * `--message TEXT`: the input message to use * `--websocket-url TEXT`: Connect to a process websocket channel instead of room chat. * `--websocket-auth [iap|jwt|none]`: Authentication mode for --websocket-url: jwt, iap, or none. \[default: iap] * `--user TEXT`: User name for the websocket process use client. \[default: you] * `--help`: Show this message and exit. ## `meshagent room` Operate within a room **Usage**: ```console theme={null} $ meshagent room [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `agents`: Interact with agents and toolkits in a room * `queue`: Use queues in a room * `messaging`: Send and receive messages in a room * `storage`: Manage storage for a room * `mounts`: List storage mounts currently ready in a room * `service`: Manage services inside a room * `developer`: Stream developer logs from a room * `dataset`: Manage dataset tables in a room * `sqlite`: Manage SQLite databases and tables in a room * `memory`: Manage room memories * `container`: Manage containers and images inside a room * `sync`: Inspect and update mesh documents in a room * `connect`: Connect to a room and run a local command... ### `meshagent room agents` Interact with agents and toolkits in a room **Usage**: ```console theme={null} $ meshagent room agents [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `call`: Trigger agent/tool calls in a room * `invoke-tool`: Invoke a specific tool from a toolkit * `list-toolkits`: List toolkits (and tools) available in the... #### `meshagent room agents call` Trigger agent/tool calls in a room **Usage**: ```console theme={null} $ meshagent room agents call [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `tool`: Send a call request to a tool webhook URL * `agent`: Send a call request to an agent webhook URL * `toolkit`: Send a call request to a toolkit webhook URL * `schema`: Send a call request to a schema webhook URL ##### `meshagent room agents call tool` Send a call request to a tool webhook URL **Usage**: ```console theme={null} $ meshagent room agents call tool [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--local / --no-local` * `--participant-name TEXT`: the participant name to be used by the callee * `--url TEXT`: URL the agent should call \[required] * `--arguments TEXT`: JSON string with arguments for the call \[default: \{}] * `-p, --permissions TEXT`: File path to a token definition, if not specified default agent permissions will be used * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ##### `meshagent room agents call agent` Send a call request to an agent webhook URL **Usage**: ```console theme={null} $ meshagent room agents call agent [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--local / --no-local` * `--participant-name TEXT`: the participant name to be used by the callee * `--url TEXT`: URL the agent should call \[required] * `--arguments TEXT`: JSON string with arguments for the call \[default: \{}] * `-p, --permissions TEXT`: File path to a token definition, if not specified default agent permissions will be used * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ##### `meshagent room agents call toolkit` Send a call request to a toolkit webhook URL **Usage**: ```console theme={null} $ meshagent room agents call toolkit [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--local / --no-local` * `--participant-name TEXT`: the participant name to be used by the callee * `--url TEXT`: URL the agent should call \[required] * `--arguments TEXT`: JSON string with arguments for the call \[default: \{}] * `-p, --permissions TEXT`: File path to a token definition, if not specified default agent permissions will be used * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. ##### `meshagent room agents call schema` Send a call request to a schema webhook URL **Usage**: ```console theme={null} $ meshagent room agents call schema [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: agent] * `--local / --no-local` * `--participant-name TEXT`: the participant name to be used by the callee * `--url TEXT`: URL the agent should call \[required] * `--arguments TEXT`: JSON string with arguments for the call \[default: \{}] * `-p, --permissions TEXT`: File path to a token definition, if not specified default agent permissions will be used * `--key TEXT`: an api key to sign the token with * `--help`: Show this message and exit. #### `meshagent room agents invoke-tool` Invoke a specific tool from a toolkit **Usage**: ```console theme={null} $ meshagent room agents invoke-tool [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--toolkit TEXT`: Toolkit name \[required] * `--tool TEXT`: Tool name \[required] * `--arguments TEXT`: JSON string with arguments for the tool \[required] * `--participant-id TEXT`: Optional participant ID to invoke the tool on * `--on-behalf-of-id TEXT`: Optional 'on\_behalf\_of' participant ID * `--timeout INTEGER`: How long to wait for the toolkit if the toolkit is not in the room \[default: 30] * `--help`: Show this message and exit. #### `meshagent room agents list-toolkits` List toolkits (and tools) available in the room **Usage**: ```console theme={null} $ meshagent room agents list-toolkits [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--role TEXT`: \[default: user] * `--participant-id TEXT`: Optional participant ID * `--help`: Show this message and exit. ### `meshagent room queue` Use queues in a room **Usage**: ```console theme={null} $ meshagent room queue [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List queues in a room. * `send`: Send a JSON message to a room queue. * `send-mail`: Create an email message and send it to a... * `receive`: Receive a message from a room queue. * `size`: Show the current size of a room queue. #### `meshagent room queue list` List queues in a room. **Usage**: ```console theme={null} $ meshagent room queue list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room queue send` Send a JSON message to a room queue. **Usage**: ```console theme={null} $ meshagent room queue send [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--queue TEXT`: Queue name \[required] * `--json TEXT`: a JSON message to send to the queue \[required] * `-f, --file TEXT`: File path to a JSON file * `--help`: Show this message and exit. #### `meshagent room queue send-mail` Create an email message and send it to a room queue. **Usage**: ```console theme={null} $ meshagent room queue send-mail [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--queue TEXT`: Queue name \[required] * `--subject TEXT`: Email subject \[required] * `--body TEXT`: Email body * `--from TEXT`: Sender email address \[required] * `--attachment TEXT`: Attachment file path. May be provided multiple times. * `--help`: Show this message and exit. #### `meshagent room queue receive` Receive a message from a room queue. **Usage**: ```console theme={null} $ meshagent room queue receive [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--queue TEXT`: Queue name \[required] * `--help`: Show this message and exit. #### `meshagent room queue size` Show the current size of a room queue. **Usage**: ```console theme={null} $ meshagent room queue size [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--queue TEXT`: Queue name \[required] * `--help`: Show this message and exit. ### `meshagent room messaging` Send and receive messages in a room **Usage**: ```console theme={null} $ meshagent room messaging [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List messaging-enabled participants * `send`: Send a direct message to a participant * `broadcast`: Broadcast a message to all participants #### `meshagent room messaging list` List messaging-enabled participants **Usage**: ```console theme={null} $ meshagent room messaging list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent room messaging send` Send a direct message to a participant **Usage**: ```console theme={null} $ meshagent room messaging send [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--to-participant-id TEXT`: Participant ID to send a message to \[required] * `--type TEXT`: type of the message to send \[required] * `--data TEXT`: JSON message to send \[required] * `--help`: Show this message and exit. #### `meshagent room messaging broadcast` Broadcast a message to all participants **Usage**: ```console theme={null} $ meshagent room messaging broadcast [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--data TEXT`: JSON message to broadcast \[required] * `--help`: Show this message and exit. ### `meshagent room storage` Manage storage for a room **Usage**: ```console theme={null} $ meshagent room storage [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `exists`: Check whether a path exists in room storage. * `cp`: Copy files between local paths and room... * `get`: Print file contents from local disk or... * `rm`: Remove files or directories from local... * `ls`: List files and directories locally or in... #### `meshagent room storage exists` Check whether a path exists in room storage. **Usage**: ```console theme={null} $ meshagent room storage exists [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent room storage cp` Copy files between local paths and room storage. **Usage**: ```console theme={null} $ meshagent room storage cp [OPTIONS] SOURCE_PATH DEST_PATH ``` **Arguments**: * `SOURCE_PATH`: \[required] * `DEST_PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent room storage get` Print file contents from local disk or room storage. **Usage**: ```console theme={null} $ meshagent room storage get [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--encoding TEXT`: Text encoding \[default: utf-8] * `--help`: Show this message and exit. #### `meshagent room storage rm` Remove files or directories from local disk or room storage. **Usage**: ```console theme={null} $ meshagent room storage rm [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-r`: Remove directories/folders recursively * `--help`: Show this message and exit. #### `meshagent room storage ls` List files and directories locally or in room storage. **Usage**: ```console theme={null} $ meshagent room storage ls [OPTIONS] PATH ``` **Arguments**: * `PATH`: Path to list (local or room://...) \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-r`: List subfolders/files recursively * `--help`: Show this message and exit. ### `meshagent room mounts` List storage mounts currently ready in a room **Usage**: ```console theme={null} $ meshagent room mounts [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list` #### `meshagent room mounts list` **Usage**: ```console theme={null} $ meshagent room mounts list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. ### `meshagent room service` Manage services inside a room **Usage**: ```console theme={null} $ meshagent room service [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List services running in a room * `describe`: Show service runtime state and lifecycle... * `restart`: Restart a running room service by stopping... #### `meshagent room service list` List services running in a room **Usage**: ```console theme={null} $ meshagent room service list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room service describe` Show service runtime state and lifecycle events for troubleshooting. **Usage**: ```console theme={null} $ meshagent room service describe [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--id TEXT`: Service ID to describe * `--name TEXT`: Service name to describe * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room service restart` Restart a running room service by stopping its current container. **Usage**: ```console theme={null} $ meshagent room service restart [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--id TEXT`: Service ID to restart * `--name TEXT`: Service name to restart * `--help`: Show this message and exit. ### `meshagent room developer` Stream developer logs from a room **Usage**: ```console theme={null} $ meshagent room developer [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--format [plain|json]`: Output format \[default: plain] * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. ### `meshagent room dataset` Manage dataset tables in a room **Usage**: ```console theme={null} $ meshagent room dataset [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `branch`: Manage dataset branches in a room namespace. * `table`: List dataset tables in a room. * `inspect`: Inspect a table schema in a room dataset. * `install`: Install required tables from a... * `create`: Create a room dataset table with optional... * `import`: Import a local Arrow, CSV, TSV, Parquet,... * `drop`: Drop a room dataset table. * `add-columns`: Add columns to a room dataset table. * `drop-columns`: Drop columns from a room dataset table. * `insert`: Insert records into a room dataset table. * `merge`: Upsert records into a room dataset table. * `update`: Update rows in a room dataset table. * `delete`: Delete rows from a room dataset table. * `search`: Search rows in a room dataset table. * `sql`: Execute SQL against room dataset tables. * `optimize`: Optimize a room dataset table. * `stats`: Show statistics for a room dataset table. * `version`: List versions for a room dataset table. * `restore`: Restore a room dataset table to a specific... * `index`: List indexes on a room dataset table. * `index-create`: Create an index on a room dataset table. * `index-drop`: Drop an index from a room dataset table. #### `meshagent room dataset branch` Manage dataset branches in a room namespace. **Usage**: ```console theme={null} $ meshagent room dataset branch [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. **Commands**: * `list`: List dataset branches in a room namespace. * `get`: Get a dataset branch. * `create`: Create a dataset branch. * `delete`: Delete a dataset branch. ##### `meshagent room dataset branch list` List dataset branches in a room namespace. **Usage**: ```console theme={null} $ meshagent room dataset branch list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. ##### `meshagent room dataset branch get` Get a dataset branch. **Usage**: ```console theme={null} $ meshagent room dataset branch get [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--branch TEXT`: Branch name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. ##### `meshagent room dataset branch create` Create a dataset branch. **Usage**: ```console theme={null} $ meshagent room dataset branch create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--branch TEXT`: New branch name \[required] * `--from-branch TEXT`: Source branch to branch from * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. ##### `meshagent room dataset branch delete` Delete a dataset branch. **Usage**: ```console theme={null} $ meshagent room dataset branch delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--branch TEXT`: Branch name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room dataset table` List dataset tables in a room. **Usage**: ```console theme={null} $ meshagent room dataset table [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. #### `meshagent room dataset inspect` Inspect a table schema in a room dataset. **Usage**: ```console theme={null} $ meshagent room dataset inspect [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-v, --version INTEGER`: Historical table version to read (defaults to latest on the branch) * `--json`: Output raw schema JSON * `--help`: Show this message and exit. #### `meshagent room dataset install` Install required tables from a requirements JSON file. **Usage**: ```console theme={null} $ meshagent room dataset install [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--file TEXT`: Path to requirements JSON file * `--help`: Show this message and exit. #### `meshagent room dataset create` Create a room dataset table with optional Arrow schema and seed data. **Usage**: ```console theme={null} $ meshagent room dataset create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--mode TEXT`: create | overwrite | create\_if\_not\_exists \[default: create] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-c, --columns TEXT`: Comma-separated column definitions. Example: "names vector(20) null, tags list(text), meta struct(owner text, score float)". CLI shorthand types: int, bool, date, timestamp, float, text, json, uuid, binary, vector, list, struct. Vector syntax: vector(size\[, element\_type]). List syntax: list(element\_type). Struct syntax: struct(field\_name type\[, ...]). * `--data-json TEXT`: Initial rows (JSON list) * `--data-file TEXT`: Path to JSON file with initial rows * `--help`: Show this message and exit. #### `meshagent room dataset import` Import a local Arrow, CSV, TSV, Parquet, JSON, or Excel file into a table. **Usage**: ```console theme={null} $ meshagent room dataset import [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-f, --file TEXT`: Local file to import \[required] * `--mode TEXT`: Import mode: create, replace, merge \[default: create] * `--format TEXT`: Input format: auto, json, arrow, csv, tsv, parquet, excel \[default: auto] * `--on TEXT`: Column to match when --mode merge * `--sheet TEXT`: Excel worksheet name for --format excel * `--batch-size INTEGER`: Rows per imported batch for Parquet, JSON, and Excel \[default: 8192] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. #### `meshagent room dataset drop` Drop a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset drop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--ignore-missing`: Ignore missing table * `--help`: Show this message and exit. #### `meshagent room dataset add-columns` Add columns to a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset add-columns [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-c, --columns TEXT`: Comma-separated column definitions. Example: "names vector(20) null, tags list(text), meta struct(owner text, score float)". CLI shorthand types: int, bool, date, timestamp, float, text, json, uuid, binary, vector, list, struct. Vector syntax: vector(size\[, element\_type]). List syntax: list(element\_type). Struct syntax: struct(field\_name type\[, ...]). * `--columns-json TEXT`: JSON object of new columns mapped to SQL default expressions (e.g. '\{"created\_at":"now()"}'). * `--help`: Show this message and exit. #### `meshagent room dataset drop-columns` Drop columns from a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset drop-columns [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-c, --column TEXT`: Column to drop (repeatable) * `--help`: Show this message and exit. #### `meshagent room dataset insert` Insert records into a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset insert [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--json TEXT`: JSON list of records * `-f, --file TEXT`: Path to JSON file (list of records) * `--help`: Show this message and exit. #### `meshagent room dataset merge` Upsert records into a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset merge [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--on TEXT`: Column to match for upsert \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--json TEXT`: JSON records (list) * `-f, --file TEXT`: Path to JSON file (list) * `--help`: Show this message and exit. #### `meshagent room dataset update` Update rows in a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset update [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause, e.g. "id = 1" \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--values-json TEXT`: JSON object of update values; use \{"column":\{"expression":"..."}} for expressions \[required] * `--help`: Show this message and exit. #### `meshagent room dataset delete` Delete rows from a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. #### `meshagent room dataset search` Search rows in a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset search [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-v, --version INTEGER`: Historical table version to read (defaults to latest on the branch) * `--text TEXT`: Full-text query * `--vector-json TEXT`: Vector JSON array * `--where TEXT`: SQL WHERE clause * `--where-json TEXT`: JSON object converted to equality ANDs * `--select TEXT`: Columns to select (repeatable) * `--limit INTEGER`: Max rows to return * `--offset INTEGER`: Rows to skip * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room dataset sql` Execute SQL against room dataset tables. **Usage**: ```console theme={null} $ meshagent room dataset sql [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-q, --query TEXT`: SQL query to execute \[required] * `-t, --table TEXT`: Table name to register in SQL context (repeatable) * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--tables-json TEXT`: JSON array of table refs (e.g. '\[\{"name":"users","alias":"u","namespace":\["prod"]}]') * `--tables-file TEXT`: Path/URL to JSON array of table refs (same format as --tables-json) * `--params-json TEXT`: JSON object of SQL parameters for DataFusion param binding * `--params-file TEXT`: Path/URL to JSON object of SQL parameters * `--branch TEXT`: Dataset branch name (defaults to main) * `-v, --version INTEGER`: Historical table version to read (defaults to latest on the branch) * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--format TEXT`: Output format: table, json, arrow, csv, tsv, parquet, excel \[default: table] * `-o, --output TEXT`: Write output to this file path instead of stdout * `--help`: Show this message and exit. #### `meshagent room dataset optimize` Optimize a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset optimize [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--compact-files / --no-compact-files` * `--optimize-indices / --no-optimize-indices` * `--cleanup-old-versions / --no-cleanup-old-versions` * `--target-rows-per-fragment INTEGER` * `--max-rows-per-group INTEGER` * `--max-bytes-per-file INTEGER` * `--materialize-deletions / --no-materialize-deletions` * `--materialize-deletions-threshold FLOAT` * `--defer-index-remap / --no-defer-index-remap` * `--num-threads INTEGER` * `--batch-size INTEGER` * `--compaction-mode TEXT`: Compaction mode: reencode, try\_binary\_copy, or force\_binary\_copy * `--binary-copy-read-batch-bytes INTEGER` * `--num-indices-to-merge INTEGER` * `--index-name TEXT`: Index name to optimize. Repeatable. * `--retrain / --no-retrain` * `--older-than-seconds FLOAT` * `--retain-versions INTEGER` * `--delete-unverified / --keep-unverified` * `--error-if-tagged-old-versions / --ignore-tagged-old-versions` * `--delete-rate-limit INTEGER` * `--config-json TEXT`: JSON object with optimization fields. * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room dataset stats` Show statistics for a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset stats [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-v, --version INTEGER`: Historical table version to read (defaults to latest on the branch) * `--max-rows-per-group INTEGER` * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room dataset version` List versions for a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset version [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room dataset restore` Restore a room dataset table to a specific version. **Usage**: ```console theme={null} $ meshagent room dataset restore [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-v, --version INTEGER`: Table version \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. #### `meshagent room dataset index` List indexes on a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset index [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `-v, --version INTEGER`: Historical table version to read (defaults to latest on the branch) * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room dataset index-create` Create an index on a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset index-create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `-c, --column TEXT`: Column name. Repeat this option to pass multiple columns. * `--index-type TEXT`: Lance index type, such as IVF\_PQ, IVF\_HNSW\_PQ, IVF\_HNSW\_SQ, IVF\_RQ, BTREE, BITMAP, LABEL\_LIST, NGRAM, ZONEMAP, INVERTED, FTS, BLOOMFILTER, or RTREE. * `--name TEXT`: Index name * `--metric TEXT`: Vector distance metric, such as L2, cosine, or dot * `--replace / --no-replace`: Replace existing index if it already exists * `--train / --no-train`: Train the index on existing data * `--num-partitions INTEGER` * `--target-partition-size INTEGER` * `--num-sub-vectors INTEGER` * `--num-bits INTEGER` * `--accelerator TEXT` * `--index-cache-size INTEGER` * `--shuffle-partition-batches INTEGER` * `--shuffle-partition-concurrency INTEGER` * `--ivf-centroids-file TEXT` * `--precomputed-partition-dataset TEXT` * `--filter-nan / --no-filter-nan`: Filter null or NaN vector values * `--index-uuid TEXT` * `--skip-transpose / --no-skip-transpose`: Skip vector index transposition * `--index-file-version TEXT` * `--max-level INTEGER` * `--m INTEGER` * `--ef-construction INTEGER` * `--with-position / --no-with-position`: Store token positions for text indexes * `--memory-limit INTEGER` * `--num-workers INTEGER` * `--skip-merge / --no-skip-merge`: Skip text index partition merge * `--base-tokenizer TEXT` * `--language TEXT` * `--max-token-length INTEGER` * `--lower-case / --no-lower-case`: Lowercase text index tokens * `--stem / --no-stem`: Stem text index tokens * `--remove-stop-words / --keep-stop-words`: Remove text index stop words * `--custom-stop-word TEXT`: Custom stop word. Repeat to pass multiple words. * `--ascii-folding / --no-ascii-folding`: Fold text index tokens to ASCII * `--config-json TEXT`: JSON object with Lance index configuration fields. * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. #### `meshagent room dataset index-drop` Drop an index from a room dataset table. **Usage**: ```console theme={null} $ meshagent room dataset index-drop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-t, --table TEXT`: Table name \[required] * `--name TEXT`: Index name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--branch TEXT`: Dataset branch name (defaults to main) * `--help`: Show this message and exit. ### `meshagent room sqlite` Manage SQLite databases and tables in a room **Usage**: ```console theme={null} $ meshagent room sqlite [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `database`: Manage SQLite databases in a room * `table`: List SQLite tables in a room database. * `inspect`: Inspect a SQLite table schema in a room... * `create`: Create a SQLite table with optional Arrow\... * `import`: Import a local Arrow, CSV, TSV, Parquet,... * `drop`: Drop a SQLite table. * `rename`: Rename a SQLite table. * `add-columns`: Add columns to a SQLite table. * `drop-columns`: Drop columns from a SQLite table. * `insert`: Insert records into a SQLite table. * `update`: Update rows in a SQLite table. * `delete`: Delete rows from a SQLite table. * `search`: Search rows in a SQLite table. * `count`: Count rows in a SQLite table. * `sql`: Execute SQL against a room SQLite database. #### `meshagent room sqlite database` Manage SQLite databases in a room **Usage**: ```console theme={null} $ meshagent room sqlite database [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. **Commands**: * `list`: List SQLite databases in a room namespace. * `create`: Create a SQLite database in a room. * `drop`: Drop a SQLite database in a room. * `inspect`: Inspect a SQLite database in a room. ##### `meshagent room sqlite database list` List SQLite databases in a room namespace. **Usage**: ```console theme={null} $ meshagent room sqlite database list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. ##### `meshagent room sqlite database create` Create a SQLite database in a room. **Usage**: ```console theme={null} $ meshagent room sqlite database create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `--mode TEXT`: create | overwrite | create\_if\_not\_exists \[default: create] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. ##### `meshagent room sqlite database drop` Drop a SQLite database in a room. **Usage**: ```console theme={null} $ meshagent room sqlite database drop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--ignore-missing`: Ignore missing database * `--help`: Show this message and exit. ##### `meshagent room sqlite database inspect` Inspect a SQLite database in a room. **Usage**: ```console theme={null} $ meshagent room sqlite database inspect [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent room sqlite table` List SQLite tables in a room database. **Usage**: ```console theme={null} $ meshagent room sqlite table [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite inspect` Inspect a SQLite table schema in a room database. **Usage**: ```console theme={null} $ meshagent room sqlite inspect [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--json`: Output raw schema JSON * `--help`: Show this message and exit. #### `meshagent room sqlite create` Create a SQLite table with optional Arrow schema and seed data. **Usage**: ```console theme={null} $ meshagent room sqlite create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--mode TEXT`: create | overwrite | create\_if\_not\_exists \[default: create] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `-c, --columns TEXT`: Comma-separated column definitions. Example: "names vector(20) null, tags list(text), meta struct(owner text, score float)". CLI shorthand types: int, bool, date, timestamp, float, text, json, uuid, binary, vector, list, struct. Vector syntax: vector(size\[, element\_type]). List syntax: list(element\_type). Struct syntax: struct(field\_name type\[, ...]). * `--data-json TEXT`: Initial rows (JSON list) * `--data-file TEXT`: Path to JSON file with initial rows * `--help`: Show this message and exit. #### `meshagent room sqlite import` Import a local Arrow, CSV, TSV, Parquet, JSON, or Excel file into a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite import [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-f, --file TEXT`: Local file to import \[required] * `--mode TEXT`: Import mode: create, replace \[default: create] * `--format TEXT`: Input format: auto, json, arrow, csv, tsv, parquet, excel \[default: auto] * `--sheet TEXT`: Excel worksheet name * `--batch-size INTEGER`: Rows per imported batch for Parquet, JSON, and Excel \[default: 8192] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite drop` Drop a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite drop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--ignore-missing`: Ignore missing table * `--help`: Show this message and exit. #### `meshagent room sqlite rename` Rename a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite rename [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--new-name TEXT`: New table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite add-columns` Add columns to a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite add-columns [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-c, --columns TEXT`: Comma-separated column definitions. Example: "names vector(20) null, tags list(text), meta struct(owner text, score float)". CLI shorthand types: int, bool, date, timestamp, float, text, json, uuid, binary, vector, list, struct. Vector syntax: vector(size\[, element\_type]). List syntax: list(element\_type). Struct syntax: struct(field\_name type\[, ...]). \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite drop-columns` Drop columns from a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite drop-columns [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-c, --column TEXT`: Column to drop (repeatable) * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite insert` Insert records into a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite insert [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--json TEXT`: JSON list of records * `-f, --file TEXT`: Path to JSON file (list of records) * `--help`: Show this message and exit. #### `meshagent room sqlite update` Update rows in a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite update [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause, e.g. "id = ?" \[required] * `--values-json TEXT`: JSON object of update values \[required] * `--params-json TEXT`: JSON SQL parameters * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite delete` Delete rows from a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause \[required] * `--params-json TEXT`: JSON SQL parameters * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite search` Search rows in a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite search [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause * `--where-json TEXT`: JSON object converted to equality ANDs * `--params-json TEXT`: JSON SQL parameters * `--select TEXT`: Columns to select (repeatable) * `--limit INTEGER`: Max rows to return * `--offset INTEGER`: Rows to skip * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite count` Count rows in a SQLite table. **Usage**: ```console theme={null} $ meshagent room sqlite count [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-t, --table TEXT`: Table name \[required] * `--where TEXT`: SQL WHERE clause * `--where-json TEXT`: JSON object converted to equality ANDs * `--params-json TEXT`: JSON SQL parameters * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. #### `meshagent room sqlite sql` Execute SQL against a room SQLite database. **Usage**: ```console theme={null} $ meshagent room sqlite sql [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-d, --database TEXT`: Database name \[required] * `-q, --query TEXT`: SQL query to execute \[required] * `--params-json TEXT`: JSON SQL parameters * `--params-file TEXT`: Path/URL to JSON parameters * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--format TEXT`: Output format: table, json, arrow, csv, tsv, parquet, excel \[default: table] * `-o, --output TEXT`: Write output to this file path instead of stdout * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--help`: Show this message and exit. ### `meshagent room memory` Manage room memories **Usage**: ```console theme={null} $ meshagent room memory [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List memories in a room namespace. * `create`: Create a room memory store. * `drop`: Drop a room memory store. * `inspect`: Inspect metadata and datasets for a memory. * `get`: Get metadata and datasets for a memory. * `query`: Run a SQL-like query against memory datasets. * `upsert-table`: Upsert records from JSON into memory tables. * `upsert-nodes`: Upsert entity nodes into memory. * `upsert-relationships`: Upsert relationship edges into memory. * `import`: Import entities and relationships from a... * `ingest-text`: Extract memory from input text. * `ingest-image`: Extract memory from an image. * `ingest-file`: Extract memory from local file/text content. * `ingest-from-table`: Extract memory from table rows. * `ingest-from-storage`: Extract memory from room storage paths. * `recall`: Recall entities and relationships from... * `delete-entities`: Delete entities (and related edges) from... * `delete-relationships`: Delete relationship edges from memory. * `optimize`: Optimize memory datasets. #### `meshagent room memory list` List memories in a room namespace. **Usage**: ```console theme={null} $ meshagent room memory list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory create` Create a room memory store. **Usage**: ```console theme={null} $ meshagent room memory create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--overwrite`: Overwrite existing memory * `--help`: Show this message and exit. #### `meshagent room memory drop` Drop a room memory store. **Usage**: ```console theme={null} $ meshagent room memory drop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--ignore-missing`: Ignore missing memory * `--help`: Show this message and exit. #### `meshagent room memory inspect` Inspect metadata and datasets for a memory. **Usage**: ```console theme={null} $ meshagent room memory inspect [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory get` Get metadata and datasets for a memory. **Usage**: ```console theme={null} $ meshagent room memory get [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory query` Run a SQL-like query against memory datasets. **Usage**: ```console theme={null} $ meshagent room memory query [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-s, --statement TEXT`: Statement, e.g. "MATCH (e:Entity) RETURN e.name LIMIT 10" \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory upsert-table` Upsert records from JSON into memory tables. **Usage**: ```console theme={null} $ meshagent room memory upsert-table [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-t, --table TEXT`: Table name \[required] * `--records-json TEXT`: JSON array of records * `--records-file TEXT`: Path to JSON file with records * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--merge / --no-merge`: Merge with existing records \[default: merge] * `--help`: Show this message and exit. #### `meshagent room memory upsert-nodes` Upsert entity nodes into memory. **Usage**: ```console theme={null} $ meshagent room memory upsert-nodes [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `--records-json TEXT`: JSON array of MemoryEntityRecord objects * `--records-file TEXT`: Path to JSON file with entity records * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--merge / --no-merge`: Merge with existing nodes \[default: merge] * `--help`: Show this message and exit. #### `meshagent room memory upsert-relationships` Upsert relationship edges into memory. **Usage**: ```console theme={null} $ meshagent room memory upsert-relationships [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `--records-json TEXT`: JSON array of MemoryRelationshipRecord objects * `--records-file TEXT`: Path to JSON file with relationship records * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--merge / --no-merge`: Merge with existing relationships \[default: merge] * `--help`: Show this message and exit. #### `meshagent room memory import` Import entities and relationships from a FalkorDB dump.rdb file. **Usage**: ```console theme={null} $ meshagent room memory import [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-f, --rdb-file PATH`: Path to FalkorDB dump.rdb file \[required] * `--graph-name TEXT`: FalkorDB graph key name. Auto-detected when unambiguous. * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--merge / --no-merge`: Merge with existing records \[default: merge] * `--batch-size INTEGER RANGE`: Rows per GRAPH.QUERY batch while importing \[default: 250; x>=1] * `--docker-image TEXT`: Docker image to use for temporary FalkorDB container \[default: falkordb/falkordb:latest] * `--startup-timeout-seconds FLOAT RANGE`: Max seconds to wait for FalkorDB startup \[default: 30.0; x>=1.0] * `--create-memory / --no-create-memory`: Create the target memory when missing \[default: create-memory] * `--help`: Show this message and exit. #### `meshagent room memory ingest-text` Extract memory from input text. **Usage**: ```console theme={null} $ meshagent room memory ingest-text [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `--text TEXT`: Text content to ingest * `-f, --file TEXT`: Path to UTF-8 text file * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--strategy [heuristic|llm]`: Ingest strategy: heuristic or llm \[default: heuristic] * `--llm-model TEXT`: Model name for llm strategy * `--llm-temperature FLOAT`: Temperature for llm strategy * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory ingest-image` Extract memory from an image. **Usage**: ```console theme={null} $ meshagent room memory ingest-image [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-f, --file TEXT`: Path to image file * `--caption TEXT`: Optional image caption * `--mime-type TEXT`: Image mime type * `--source TEXT`: Source identifier/path * `--annotations-json TEXT`: Optional JSON map of string annotations, e.g. \{"origin":"camera"} * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--strategy [heuristic|llm]`: Ingest strategy: heuristic or llm \[default: heuristic] * `--llm-model TEXT`: Model name for llm strategy * `--llm-temperature FLOAT`: Temperature for llm strategy * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory ingest-file` Extract memory from local file/text content. **Usage**: ```console theme={null} $ meshagent room memory ingest-file [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `--path TEXT`: File path available to the room server * `--text TEXT`: Inline text content * `--text-file TEXT`: Path to local UTF-8 text file * `--mime-type TEXT`: Optional mime type * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--strategy [heuristic|llm]`: Ingest strategy: heuristic or llm \[default: heuristic] * `--llm-model TEXT`: Model name for llm strategy * `--llm-temperature FLOAT`: Temperature for llm strategy * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory ingest-from-table` Extract memory from table rows. **Usage**: ```console theme={null} $ meshagent room memory ingest-from-table [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-t, --table TEXT`: Source table name \[required] * `--text-column TEXT`: Source text columns (repeatable) * `--table-namespace TEXT`: Namespace path segments for the source table (repeatable) * `--limit INTEGER`: Maximum source rows * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--strategy [heuristic|llm]`: Ingest strategy: heuristic or llm \[default: heuristic] * `--llm-model TEXT`: Model name for llm strategy * `--llm-temperature FLOAT`: Temperature for llm strategy * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory ingest-from-storage` Extract memory from room storage paths. **Usage**: ```console theme={null} $ meshagent room memory ingest-from-storage [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-p, --path TEXT`: Room storage path to ingest (repeatable) \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--strategy [heuristic|llm]`: Ingest strategy: heuristic or llm \[default: heuristic] * `--llm-model TEXT`: Model name for llm strategy * `--llm-temperature FLOAT`: Temperature for llm strategy * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory recall` Recall entities and relationships from memory. **Usage**: ```console theme={null} $ meshagent room memory recall [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-q, --query TEXT`: Recall query text \[required] * `--limit INTEGER`: Max entities to return \[default: 5] * `--include-relationships / --no-include-relationships`: Include related edges for recalled entities \[default: include-relationships] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory delete-entities` Delete entities (and related edges) from memory. **Usage**: ```console theme={null} $ meshagent room memory delete-entities [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-e, --entity-id TEXT`: Entity ID to delete (repeatable) \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory delete-relationships` Delete relationship edges from memory. **Usage**: ```console theme={null} $ meshagent room memory delete-relationships [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `--records-json TEXT`: JSON array of MemoryRelationshipSelector objects * `--records-file TEXT`: Path to JSON file with relationship selectors * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room memory optimize` Optimize memory datasets. **Usage**: ```console theme={null} $ meshagent room memory optimize [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-m, --name TEXT`: Memory name \[required] * `-n, --namespace TEXT`: Namespace path segments (repeatable). Example: -n prod -n analytics * `--compact / --no-compact`: Compact dataset fragments \[default: compact] * `--cleanup / --no-cleanup`: Cleanup old dataset versions \[default: cleanup] * `--pretty / --no-pretty`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. ### `meshagent room container` Manage containers and images inside a room **Usage**: ```console theme={null} $ meshagent room container [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `image`: Image operations * `list`: List containers in a room. * `stop`: Stop a running container in a room. * `log`: Print container logs from a room. * `exec`: Execute a command inside a running container. * `run`: Run a container inside a room. #### `meshagent room container image` Image operations **Usage**: ```console theme={null} $ meshagent room container image [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `list`: List container images available in a room. * `inspect`: Inspect a container image in a room by... * `delete`: Delete a container image from a room. * `pull`: Pull a container image into a room. * `push`: Push a container image from a room. * `load`: Load an OCI image archive from room... * `save`: Save an OCI image archive from a room. ##### `meshagent room container image list` List container images available in a room. **Usage**: ```console theme={null} $ meshagent room container image list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--output TEXT`: table | json \[default: table] * `--help`: Show this message and exit. ##### `meshagent room container image inspect` Inspect a container image in a room by image ID. **Usage**: ```console theme={null} $ meshagent room container image inspect [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--image-id TEXT`: Image ID from `meshagent images list` \[required] * `--help`: Show this message and exit. ##### `meshagent room container image delete` Delete a container image from a room. **Usage**: ```console theme={null} $ meshagent room container image delete [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--image TEXT`: Image ref/tag to delete \[required] * `--help`: Show this message and exit. ##### `meshagent room container image pull` Pull a container image into a room. **Usage**: ```console theme={null} $ meshagent room container image pull [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--tag TEXT`: Image tag/ref to pull \[required] * `--cred TEXT`: Docker creds (username,password) or (registry,username,password) * `--help`: Show this message and exit. ##### `meshagent room container image push` Push a container image from a room. **Usage**: ```console theme={null} $ meshagent room container image push [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--tag TEXT`: Image tag/ref to push \[required] * `--private / --public`: Whether the push container is private to the participant \[default: public] * `--cred TEXT`: Docker creds (username,password) or (registry,username,password) * `--help`: Show this message and exit. ##### `meshagent room container image load` Load an OCI image archive from room storage into a room. **Usage**: ```console theme={null} $ meshagent room container image load [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-i, --archive-path, --image TEXT`: Absolute room storage path to the OCI image archive file \[required] * `--help`: Show this message and exit. ##### `meshagent room container image save` Save an OCI image archive from a room. **Usage**: ```console theme={null} $ meshagent room container image save [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--tag TEXT`: Image tag/ref to save \[required] * `--archive-path TEXT`: Path to write OCI archive inside one of the mounted paths (absolute path) \[required] * `--mount-room-path TEXT`: Room storage mount '\:\\[:ro|rw]'. Example '/images\:/workspace' * `--mount-image TEXT`: Image mount '\=\\[:ro|rw]'. Example 'alpine:latest=/toolchain:ro' * `--private / --public`: Whether the save container is private to the participant \[default: public] * `--help`: Show this message and exit. #### `meshagent room container list` List containers in a room. **Usage**: ```console theme={null} $ meshagent room container list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-a, --all`: Include exited containers in the listing. * `--output TEXT`: json | table \[default: json] * `--help`: Show this message and exit. #### `meshagent room container stop` Stop a running container in a room. **Usage**: ```console theme={null} $ meshagent room container stop [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--id TEXT`: Container ID \[required] * `--help`: Show this message and exit. #### `meshagent room container log` Print container logs from a room. **Usage**: ```console theme={null} $ meshagent room container log [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--id TEXT`: Container ID \[required] * `--follow / --no-follow`: Stream logs \[default: no-follow] * `--help`: Show this message and exit. #### `meshagent room container exec` Execute a command inside a running container. **Usage**: ```console theme={null} $ meshagent room container exec [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--container-id TEXT`: container id \[required] * `--command TEXT`: Command to execute in the container (quoted string) * `--help`: Show this message and exit. #### `meshagent room container run` Run a container inside a room. **Usage**: ```console theme={null} $ meshagent room container run [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--image TEXT`: Image to run \[required] * `--command TEXT`: Command to execute in the container (quoted string) * `--working-dir TEXT`: Working directory inside the container (must be an absolute path) * `-e, --env TEXT`: KEY=VALUE * `-p, --port TEXT`: CONTAINER:HOST * `--cred TEXT`: Docker creds (username,password) or (registry,username,password) * `--mount-path TEXT`: Room storage path to mount into the container * `--mount-subpath TEXT`: Subpath within `--mount-path` to mount * `--participant-name TEXT`: Participant name to associate with the run * `--role TEXT`: Role to run the container as \[default: user] * `--container-name TEXT`: Optional container name * `--template TEXT`: Allowed values: agent, none. agent: MeshAgent mounts room storage at /data, sets MESHAGENT\_TOKEN, OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, GROK\_API\_KEY, and XAI\_API\_KEY to a container-scoped MeshAgent token. agent also sets SMTP\_PASSWORD to that token, SMTP\_USERNAME to the container name, SMTP\_PORT to 587, SMTP\_HOSTNAME from MESHAGENT\_MAIL\_DOMAIN when available, plus OPENAI\_BASE\_URL, ANTHROPIC\_BASE\_URL, GROK\_BASE\_URL, XAI\_BASE\_URL, MESHAGENT\_API\_URL, MESHAGENT\_ROOM\_URL, MESHAGENT\_ROOM, MESHAGENT\_PROJECT\_ID, MESHAGENT\_SESSION\_ID, OTEL\_ENDPOINT, OTEL\_PYTHON\_LOG\_LEVEL, and MESHAGENT\_MAIL\_DOMAIN from the room runtime when available. Manual env values win. none: MeshAgent applies no template defaults. \[default: none] * `--help`: Show this message and exit. ### `meshagent room sync` Inspect and update mesh documents in a room **Usage**: ```console theme={null} $ meshagent room sync [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `import`: Import Anthropic Claude GDPR conversations... * `get`: Print the full document JSON * `grep`: Search the document for matching content * `inspect`: Print the document schema JSON * `create`: Create a new document at a path * `update`: Apply a JSON patch to a document #### `meshagent room sync import` Import Anthropic Claude GDPR conversations into room thread documents. **Usage**: ```console theme={null} $ meshagent room sync import [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `-f, --file PATH`: Path to Claude GDPR conversations.json \[required] * `--thread-dir TEXT`: Directory where imported .thread files will be stored \[default: .threads/anthropic] * `--overwrite`: Overwrite existing imported thread files * `--limit INTEGER RANGE`: Maximum number of conversations to import \[x>=1] * `--user-name, --human-name TEXT`: Author name used for user/human messages \[default: human] * `--assistant-name TEXT`: Author name used for assistant messages \[default: assistant] * `--include-empty-messages`: Include messages that normalize to empty text * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. #### `meshagent room sync get` Print the full document JSON **Usage**: ```console theme={null} $ meshagent room sync get [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--include-ids`: Include \$id attributes in output * `--pretty / --compact`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room sync grep` Search the document for matching content **Usage**: ```console theme={null} $ meshagent room sync grep [OPTIONS] PATH PATTERN ``` **Arguments**: * `PATH`: \[required] * `PATTERN`: Regex pattern to match \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--ignore-case`: Ignore case * `--before INTEGER RANGE`: Include siblings before \[default: 0; x>=0] * `--after INTEGER RANGE`: Include siblings after \[default: 0; x>=0] * `--include-ids`: Include \$id attributes in output * `--pretty / --compact`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room sync inspect` Print the document schema JSON **Usage**: ```console theme={null} $ meshagent room sync inspect [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--pretty / --compact`: Pretty-print JSON \[default: pretty] * `--help`: Show this message and exit. #### `meshagent room sync create` Create a new document at a path **Usage**: ```console theme={null} $ meshagent room sync create [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--schema PATH`: Schema JSON file \[required] * `--json TEXT`: Initial JSON payload * `--json-file PATH`: Path to initial JSON payload * `--help`: Show this message and exit. #### `meshagent room sync update` Apply a JSON patch to a document **Usage**: ```console theme={null} $ meshagent room sync update [OPTIONS] PATH ``` **Arguments**: * `PATH`: \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--room TEXT`: Room name \[default: (dynamic)] * `--patch TEXT`: JSON patch array * `--patch-file PATH`: Path to JSON patch array * `--help`: Show this message and exit. ### `meshagent room connect` Connect to a room and run a local command with MESHAGENT\_API\_URL, MESHAGENT\_PROJECT\_ID, MESHAGENT\_TOKEN, OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, GROK\_API\_KEY, XAI\_API\_KEY, and MESHAGENT\_ROOM set by the default agent template. Use -- before the local command. **Usage**: ```console theme={null} $ meshagent room connect [OPTIONS] [COMMAND]... ``` **Arguments**: * `[COMMAND]...` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. * `--room TEXT`: Room name * `-e, --env TEXT`: Set environment variable as KEY=VALUE * `--identity TEXT`: Identity name to use for the connected token and --meshagent-token. Required with --role and --meshagent-token. When set, room connect mints a participant token locally. * `--role TEXT`: Participant role for locally minted tokens. Requires --identity and defaults to agent. * `--meshagent-token TEXT`: Inject MESHAGENT\_TOKEN using userDefault, agentDefault, full, or a JSON ApiScope object. * `--template TEXT`: Allowed values: agent, none. agent: MeshAgent sets MESHAGENT\_TOKEN, OPENAI\_API\_KEY, ANTHROPIC\_API\_KEY, GROK\_API\_KEY, and XAI\_API\_KEY to a room-scoped MeshAgent token, and sets OPENAI\_BASE\_URL, ANTHROPIC\_BASE\_URL, GROK\_BASE\_URL, XAI\_BASE\_URL, MESHAGENT\_API\_URL, MESHAGENT\_PROJECT\_ID, and MESHAGENT\_ROOM for the connected room unless manually set. Provider base URLs use the project API endpoint. none: MeshAgent applies no template defaults. \[default: agent] * `--help`: Show this message and exit. ## `meshagent llm` Local LLM proxy utilities **Usage**: ```console theme={null} $ meshagent llm [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--install-completion`: Install completion for the current shell. * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. * `--help`: Show this message and exit. **Commands**: * `logger`: Manage project LLM loggers * `proxy`: Expose a local MeshAgent-authenticated LLM... ### `meshagent llm logger` Manage project LLM loggers **Usage**: ```console theme={null} $ meshagent llm logger [OPTIONS] COMMAND [ARGS]... ``` **Options**: * `--help`: Show this message and exit. **Commands**: * `create`: Create an LLM logger. * `update`: Update an LLM logger. * `get`: Get an LLM logger. * `list`: List LLM loggers for the project. * `delete`: Delete an LLM logger. #### `meshagent llm logger create` Create an LLM logger. **Usage**: ```console theme={null} $ meshagent llm logger create [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--destination-feed-id, --feed-id TEXT`: Destination feed id \[required] * `-f, --filter-expression TEXT`: JMESPath metadata filter \[required] * `--paused`: Create the logger in a paused state * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. #### `meshagent llm logger update` Update an LLM logger. **Usage**: ```console theme={null} $ meshagent llm logger update [OPTIONS] LOGGER_ID ``` **Arguments**: * `LOGGER_ID`: LLM logger id to update \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--destination-feed-id, --feed-id TEXT`: Destination feed id * `-f, --filter-expression TEXT`: JMESPath metadata filter * `--paused`: Pause the logger * `--resume`: Resume a paused logger * `--annotations TEXT`: annotations in json format \{"name":"value"} * `--help`: Show this message and exit. #### `meshagent llm logger get` Get an LLM logger. **Usage**: ```console theme={null} $ meshagent llm logger get [OPTIONS] LOGGER_ID ``` **Arguments**: * `LOGGER_ID`: LLM logger id to get \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. #### `meshagent llm logger list` List LLM loggers for the project. **Usage**: ```console theme={null} $ meshagent llm logger list [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `-o, --output TEXT`: output format \[default: table] * `--help`: Show this message and exit. #### `meshagent llm logger delete` Delete an LLM logger. **Usage**: ```console theme={null} $ meshagent llm logger delete [OPTIONS] LOGGER_ID ``` **Arguments**: * `LOGGER_ID`: LLM logger id to delete \[required] **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--help`: Show this message and exit. ### `meshagent llm proxy` Expose a local MeshAgent-authenticated LLM proxy. **Usage**: ```console theme={null} $ meshagent llm proxy [OPTIONS] ``` **Options**: * `--project-id TEXT`: A MeshAgent project id. If empty, the activated project will be used. \[default: (dynamic)] * `--host TEXT`: Local host to bind the proxy to. \[default: 127.0.0.1] * `--port INTEGER`: Local port to bind the proxy to. \[default: 8766] * `--bearer TEXT`: Explicit local bearer token. If omitted, the stored token is reused or generated on first run. * `--token-from-env TEXT`: Name of environment variable containing a MeshAgent token to forward upstream. * `--insecure`: Disable local bearer-token enforcement. * `--tui / --no-tui`: Show the live usage dashboard when attached to a TTY. \[default: tui] * `--help`: Show this message and exit. # Install the Python SDK Source: https://docs.meshagent.com/reference/python_package_overview Choose the right MeshAgent Python packages for your workflow. Python is the only MeshAgent SDK published as a split package family. In code, you import modules like `meshagent.api` and `meshagent.agents`. In your environment, you install distributions like `meshagent-api` and `meshagent-agents`. The other MeshAgent SDKs do not use this split distribution model. ## Choose an install path Choose the install path that matches what you are trying to do: | If you want to... | Install | | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------- | | Build agents with the CLI and have the common integrations available | `meshagent[all]` | | Use the CLI for local setup, testing, and deployment | `meshagent[cli]` | | Add room and REST clients to an existing Python service | `meshagent-api` | | Build custom agent code on top of the Python runtime | `meshagent-agents` | | Add a specific capability such as tools, MCP, OpenAI, Anthropic, LiveKit, Telegram, Twilio, or computer use | Install the matching split package directly | If you are new to the Python SDK, start with `meshagent[all]`. If you are keeping an environment small on purpose, install only the packages you need. ```bash uv theme={null} uv add "meshagent[all]" uv add "meshagent[cli]" uv add meshagent-api uv add meshagent-agents ``` ```bash pip theme={null} pip install "meshagent[all]" pip install "meshagent[cli]" pip install meshagent-api pip install meshagent-agents ``` ## Package Map | Installable package | Python imports | Use it when... | | ----------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------- | | `meshagent` | `meshagent` | You want the umbrella package and extras such as `[all]`, `[cli]`, and `[agents]` | | `meshagent-api` | `meshagent.api` | You need room clients, REST/admin clients, participant tokens, service specs, or webhooks | | `meshagent-agents` | `meshagent.agents` | You are building custom agents or using the lower-level Python runtime types behind `meshagent process` | | `meshagent-cli` | `meshagent.cli` | You need the `meshagent` CLI commands | | `meshagent-tools` | `meshagent.tools` | You are defining tools or toolkits in Python | | `meshagent-mcp` | `meshagent.mcp` | You want to expose MCP tools through MeshAgent | | `meshagent-openai` | `meshagent.openai` | You need OpenAI adapters | | `meshagent-anthropic` | `meshagent.anthropic` | You need Anthropic adapters | | `meshagent-livekit` | `meshagent.livekit` | You are building voice or LiveKit-based workflows | | `meshagent-commoncrawl` | `meshagent.commoncrawl` | You want to import Common Crawl captures into room datasets | | `meshagent-scrapy` | `meshagent.scrapy` | You want to spider websites with Scrapy into room datasets | | `meshagent-computers` | `meshagent.computers` | You need browser or computer-control helpers | | `meshagent-codex` | `meshagent.codex` | You need Codex-specific integrations | | `meshagent-otel` | `meshagent.otel` | You want OpenTelemetry helpers in Python | Provider channel implementations for Telegram, Slack, Twilio, and WhatsApp are generated as editable source by `meshagent create`; they are not separate Python packages. ## Imports vs. Packages The import names and the install names are intentionally different: * `from meshagent.api import ParticipantToken` comes from the `meshagent-api` package. * `from meshagent.agents import SingleRoomAgent` comes from the `meshagent-agents` package. * `from meshagent.openai import OpenAIResponsesAdapter` comes from the `meshagent-openai` package. If you need the cross-language view, go back to [SDK Overview](./sdk_reference). If you want to build and deploy agents from the CLI, go to [Process Agents](../agents/process/overview). # SDK Overview Source: https://docs.meshagent.com/reference/sdk_reference Choose the right MeshAgent SDK for your stack. MeshAgent ships official SDKs for Python, TypeScript/JavaScript, Dart/Flutter, and .NET. Python is the only SDK that uses a split package family. The other SDKs center on one core package, with optional UI, auth, or service packages layered on top. | Language | Start with | Add-on packages | Best fit | | --------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | **Python** | `meshagent[all]` | `meshagent-api`, `meshagent-agents`, `meshagent-cli`, `meshagent-tools`, `meshagent-openai`, `meshagent-anthropic`, `meshagent-livekit`, `meshagent-mcp`, `meshagent-computers` | Full agent authoring, CLI workflows, room clients, process channels, and project admin | | **TypeScript / JavaScript** | `@meshagent/meshagent` | `@meshagent/meshagent-node`, `@meshagent/meshagent-livekit`, `@meshagent/meshagent-react`, `@meshagent/meshagent-ts-auth`, `@meshagent/meshagent-react-auth` | Browser and Node apps, room clients, admin clients, local Node dev servers, LiveKit helpers, and React UI | | **Dart / Flutter** | `meshagent` | `meshagent_flutter`, `meshagent_flutter_auth`, `meshagent_flutter_shadcn`, `meshagent_service` | Flutter apps, room clients, admin clients, widgets, and Dart services | | **.NET** | `Meshagent.Api` | `None` | Room clients and project admin from .NET services | * Need the fullest MeshAgent runtime and CLI today: start with Python. * Building browser or Node apps: start with `@meshagent/meshagent`. * Building a browser or Node app that needs framework-agnostic OAuth or PKCE helpers: add `@meshagent/meshagent-ts-auth`. * Building a Node dev server that needs to expose the local room websocket proxy: add `@meshagent/meshagent-node`. * Building a React app that needs OAuth login and auth state helpers: add `@meshagent/meshagent-react-auth`; use `useAuth` or `useEnsureLogin`, and you do not need a React Query provider. * Building Flutter apps: start with `meshagent`, then add the Flutter packages you need. * Building .NET services or tools: start with `Meshagent.Api`. If you are working in Python and need to choose between `meshagent[all]`, `meshagent[cli]`, and the split packages, continue to [Install the Python SDK](./python_package_overview). # API Scopes Source: https://docs.meshagent.com/rest_api/api_scopes `ApiScope` objects describe exactly which parts of the Rooms API a participant may call. They are carried inside the `api` grant of every [`ParticipantToken`](./participant_tokens) and are defined in `meshagent.api.participant_token.ApiScope`. ## Built-in presets MeshAgent ships three convenience constructors: * `ApiScope.agent_default()` – enables Livekit, Queues, Messaging, Dataset, SQLite, Memory, Sync, Storage, Containers, Developer, Agents, LLM, and Services access. Use `ApiScope.agent_default(tunnels=True)` to include the tunnels grant. * `ApiScope.user_default()` – enables the same core room access as `agent_default()`, including SQLite, but omits the LLM grant and still excludes Admin and Tunnels. * `ApiScope.full()` – everything in `agent_default()` plus the Admin and Tunnels grants. It does not add the room `secrets` grant. Use these helpers when you want broad access, then override individual fields when you need to lock things down. ## Scope fields Each top-level field is a grant for one Room API surface. If a grant object is absent, that API surface is denied. When a grant object is present, `None` in an allowlist generally means unrestricted access within that grant. Tunnels are opt-in: when `tunnels` is absent, tunnel access is denied. ### `livekit` `LivekitGrant` contains an optional `breakout_rooms` list. When omitted, any breakout room may be joined. When provided, only the named breakout rooms can be joined. ### `queues` `QueuesGrant` exposes three controls: * `send`: list of queue names the participant may publish to (`can_send` checks membership; `None` means all queues). * `receive`: list of queues the participant may consume from (`can_receive`). * `list`: boolean flag gating `QueuesClient.list` operations (defaults to `True`). ### `messaging` `MessagingGrant` has simple booleans for `broadcast`, `list`, and `send`, all defaulting to `True`. ### `dataset` `DatasetGrant` manages table-level access: * `tables`: optional list of `TableGrant` entries (`name`, and booleans for `read`, `write`, `alter`). When omitted the participant may access every table. * `list_tables`: boolean (defaults to `True`). * Helper methods (`can_read`, `can_write`, `can_alter`) enforce the per-table flags. Table grants can also include `namespace`. A grant with no namespace matches the table in any namespace; a grant with a namespace only matches requests for that namespace. ### `sqlite` `SqliteGrant` controls room-scoped SQLite databases: * `create_database`: boolean controlling database creation. * `list_databases`: boolean controlling database discovery. * `databases`: optional list of `SqliteDatabaseGrant` entries. When omitted, the participant may use every SQLite database allowed by the grant. Each database grant can include: * `name`: database name. * `namespace`: optional namespace restriction. * `create_table`, `drop`, `inspect`, `list_tables`, and `execute`: booleans for database-level operations. * `tables`: optional list of table-specific grants. When omitted on a matching database grant, table read, write, and alter access applies to all tables in that database. Each SQLite table grant includes `database`, `table`, optional `namespace`, and booleans for `read`, `write`, and `alter`. ### `memory` `MemoryGrant` controls room-memory access: * `list`: boolean controlling whether the participant may list memories. * `memories`: optional list of `MemoryEntryGrant` objects, each scoped by `name` and optional `namespace`. * Each memory entry has its own `permissions` object with booleans for `create`, `drop`, `inspect`, `query`, `upsert`, `ingest`, `recall`, and `optimize`. ### `sync` `SyncGrant` accepts `paths`: a list of `SyncPathGrant { path, read_only }`. Paths may end with `*` to match prefixes. When no paths are supplied, read and write access is global. `can_read` and `can_write` verify the constraints. ### `storage` `StorageGrant` mirrors the sync semantics but checks filesystem-style prefixes (`path.startswith(...)`). A `read_only` flag prevents writes on matching paths. ### `containers` `ContainersGrant` controls container management features: * `use_containers`: overall switch for container operations (defaults to `True`). * `pull` / `run`: optional allowlists of image tags; each entry can end with `*` to allow a prefix (`can_pull` / `can_run`). * `logs`: booleans toggling log streaming support. * `registry`: optional `ContainerRegistryGrant` for repository-level registry operations. `ContainerRegistryGrant` includes: * `list`: repositories the participant may list. * `pull`: repositories the participant may pull from. * `run`: repositories the participant may run images from. * `write`: repositories the participant may write to. Repository patterns can be exact names or prefixes ending in `*`. If `registry` is absent, registry repository checks allow any repository; image pull and run checks are still controlled separately by the top-level `pull` and `run` image allowlists. If `registry.list` is absent but `pull`, `run`, or `write` are present, list access is inferred from those repository allowlists. ### `developer` `DeveloperGrant` currently exposes a single `logs` boolean, enabling developer log forwarding when `True`. ### `tunnels` `TunnelsGrant` controls port-forwarding into room containers. * `ports`: optional list of allowed container ports. If omitted or empty, all ports are allowed. If the `tunnels` grant is absent, port forwarding is denied. ### `agents` `AgentsGrant` exposes boolean switches for registering agents or toolkits (`register_agent`, `register_public_toolkit`, `register_private_toolkit`) and for invoking the Agents API (`call`, `use_agents`, `use_tools`). They default to `True` to match the typical agent workflow. Use `allowed_toolkits` to restrict tool use to specific toolkit names. When `allowed_toolkits` is omitted, the participant may use any toolkit allowed by the rest of the grant. ### `llm` `LLMGrant` controls room-scoped LLM proxy access. * `models`: optional provider/model allowlist. When omitted, the participant may use any model allowed by the project policy. Entries can be exact `provider/model` names or prefixes ending in `*`. ### `admin` `AdminGrant` currently exposes a single `config` boolean. When `True`, the participant may use the admin configuration surface. ### `secrets` The room API `SecretsGrant` enables room routes that require a participant-token secrets grant. It has no nested fields. User and service-account secrets are managed through the account REST API. Proxy use is controlled by OAuth scopes such as `secrets:proxy` plus service-account permissions. ### `services` `ServicesGrant` currently exposes a `list` boolean for service-listing operations in the room. ## Examples ```yaml theme={null} # Restrict a service to a single queue and read-only storage api: queues: send: ["notifications"] receive: ["notifications"] storage: paths: - path: "/data/uploads" read_only: true ``` ```yaml theme={null} # Allow port forwarding only to container port 9000 api: tunnels: ports: ["9000"] ``` ```yaml theme={null} # Allow only selected room SQLite access api: sqlite: create_database: false list_databases: true databases: - name: reports inspect: true list_tables: true execute: true tables: - database: reports table: daily_metrics read: true write: false alter: false ``` ```yaml theme={null} # Limit LLM proxy access and tool use api: llm: models: ["openai/gpt-5.5", "anthropic/claude-opus-*"] agents: allowed_toolkits: ["support-search", "ticket-reader"] ``` ```python theme={null} from meshagent.api.participant_token import ApiScope, QueuesGrant scope = ApiScope( queues=QueuesGrant(send=["events"], receive=["events"]) ) ``` Combine these snippets with the `api` field when [packaging a service](../services/deployment/deploy_services) to set the appropriate permissions for your service. # REST API Source: https://docs.meshagent.com/rest_api/overview The MeshAgent REST API exposes administrative and lifecycle operations for projects, rooms, users, permissions, services, storage, billing, sessions, and project settings. The REST API can be used for: * **Projects & Rooms**: Create projects, manage rooms, and mint room connection tokens * **Resource policies**: Manage access to rooms, repositories, feeds, service accounts, and other project resources * **Project storage**: Upload/download project files by path * **Services**: Manage project-wide and room-scoped services * **Secrets**: Manage user-owned and service-account-owned credentials * **Project settings & integrations**: Update project settings, model routing configuration, webhooks, API keys, and OAuth clients * **Shares**: Create share links for Rooms * **Mailboxes**: Manage mailboxes mapped to Rooms * **Operations**: Understand sessions (events/spans/metrics) and create/manage scheduled tasks * **Billing & usage**: Get insight into your account balance, transactions, subscriptions, and usage reporting For room-specific operations such as working with agents, datasets, or queues use the [Room APIs](../room_api/overview). ## Getting started To call the MeshAgent REST API, authenticate with a project API key. The simplest path is: 1. **Set up a Python environment** with the MeshAgent SDK installed (requires Python 3.13) 2. **Use the MeshAgent CLI to create and activate an API key**, then store it in a `.env` file 3. **Load the key from `.env`** and create a `Meshagent()` client > MeshAgent requires **Python 3.13**. We recommend using `uv`, which manages Python versions, virtual environments, and dependencies automatically. To learn more about `uv` see the [Machine Setup Guide for Python](../reference/machine_setup) ### 1. Set up the SDK Install uv, then create a project and virtual environment with MeshAgent installed: ```bash theme={null} # Install uv if needed curl -LsSf https://astral.sh/uv/install.sh | sh # Create and navigate to your project directory mkdir meshagent-project && cd meshagent-project # Initialize the project and pin Python 3.13 uv init --python 3.13 # Create virtual environment (uv will download python 3.13 if not already installed on your machine) uv venv --python 3.13 # Install MeshAgent SDK and other dependencies uv add "meshagent[all]" python-dotenv ``` Activate your virtual environment: ```bash macOS/Linux theme={null} source .venv/bin/activate ``` ```bash Windows theme={null} .venv\Scripts\activate ``` > **Note**: You'll know your virtual environment is active when you see `(.venv)` at the start of your terminal prompt. When the environment is activated, you can run commands directly (e.g. `meshagent setup` or `python main.py`). If the environment is not activated, prefix commands with `uv run` (e.g. `uv run meshagent setup` or `uv run python main.py`). To upgrade dependencies later, run: ```bash theme={null} uv lock --upgrade uv sync ``` ### 2. Create a new API key and store it in `.env` ```bash theme={null} # Authenticate to MeshAgent if not already signed in meshagent setup # this will also print your project ID # Get your current project ID meshagent project list # the project with the * next to it is the current active project # Create an API Key meshagent api-key create my-key --activate ``` Create a `.env` file in your project and paste the key value: ```bash theme={null} MESHAGENT_API_KEY=your-api-key-value MESHAGENT_PROJECT_ID=your-project-id ``` ### 3. Create a MeshAgent client Now we can create the MeshAgent client and use it to do something like list all the rooms in our project. ```python Python theme={null} import asyncio import os from dotenv import load_dotenv from meshagent.api.client import Meshagent load_dotenv() api_key = os.getenv("MESHAGENT_API_KEY") project_id = os.getenv("MESHAGENT_PROJECT_ID") if not api_key: raise RuntimeError("MESHAGENT_API_KEY is not set") if not project_id: raise RuntimeError("MESHAGENT_PROJECT_ID is not set") async def main(): client = Meshagent(token=api_key) try: rooms = await client.list_rooms(project_id=project_id) print(rooms) finally: await client.close() asyncio.run(main()) ``` ### Client configuration The `Meshagent()` client accepts a `base_url` and `token`. * `base_url`: defaults to `MESHAGENT_API_URL` (defaults to [https://api.meshagent.com](https://api.meshagent.com)) * `token`: a bearer token for the Authorization header. * This will default to `MESHAGENT_API_KEY`. API keys are scoped to a specific project, so most REST calls will also require a `project_id`. REST calls raise `meshagent.api.RoomException` on non-2xx responses. Many methods also validate responses with typed models, while others still return plain JSON dicts or lists directly. ## Projects, Rooms, and managed agents Create and manage projects, Rooms, and managed agent identities. Room and agent connection methods return signed connection information for the target runtime. Project settings are independent documents named `openai`, `anthropic`, `otel`, `admission`, `room`, and `room_roles`. They are stored in project storage under `.meshagent/settings/` as one JSON file per group (for example, `.meshagent/settings/openai.json`). The REST path and storage filename for `room_roles` use `room-roles`; SDK clients translate that name automatically. A missing document is unconfigured and is not read from the legacy project settings field or any database fallback. | SDK method | HTTP route | What it does | | ------------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `create_project(name)` | `POST /accounts/projects` | Create a project. | | `list_projects()` | `GET /accounts/projects` | List projects you can access. | | `get_project(project_id)` | `GET /accounts/projects/{project_id}` | Fetch one project. | | `get_project_settings_document(project_id, name)` | `GET /accounts/projects/{project_id}/settings/{name}` | Fetch one settings document. | | `set_project_settings_document(project_id, name, document)` | `PUT /accounts/projects/{project_id}/settings/{name}` | Set one settings document. | | `delete_project_settings_document(project_id, name)` | `DELETE /accounts/projects/{project_id}/settings/{name}` | Revert one settings document to its unconfigured/default state. | | `get_project_status(project_id)` | `GET /accounts/projects/{project_id}/status` | Check whether the project is enabled. | | `get_project_role(project_id)` | `GET /accounts/projects/{project_id}/role` | Get your role in the project. | | `add_user_to_project(project_id, user_id, …)` | `POST /accounts/projects/{project_id}/users` | Add a user with project roles such as `admin`, `developer`, `room_creator`, `agent_creator`, or `llm_proxy_user`. | | `remove_user_from_project(project_id, user_id)` | `DELETE /accounts/projects/{project_id}/users/{user_id}` | Remove a user from the project. | | `get_users_in_project(project_id)` | `GET /accounts/projects/{project_id}/users` | List users in the project. | | `get_user_profile(user_id)` | `GET /accounts/profiles/{user_id}` | Fetch a user profile. | | `update_user_profile(user_id, first_name, last_name)` | `PUT /accounts/profiles/{user_id}` | Update basic profile fields. | | `create_room(project_id, name, metadata?, permissions?, if_not_exists?)` | `POST /accounts/projects/{project_id}/rooms` | Create a room (supports metadata + optional initial permissions). | | `list_rooms(project_id, limit?, offset?, order_by?)` | `GET /accounts/projects/{project_id}/rooms` | List rooms with pagination. | | `get_room(project_id, room_name)` | `GET /accounts/projects/{project_id}/rooms/{room_name}` | Fetch a room by name. | | `get_room_status(project_id, room_name)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/status` | Return current control-plane allocation state (`Allocated` or `Unallocated`), including allocation time and running duration when active; this is not lifecycle history or service health. | | `list_room_events(project_id, room_name, limit?)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/events` | List recent historical lifecycle transitions across the room's sessions, including allocation, startup, shutdown, and startup failures; this is not current state. | | `update_room(project_id, room_id, name, metadata?)` | `PUT /accounts/projects/{project_id}/rooms/{room_id}` | Rename/update a room. | | `delete_room(project_id, room_id)` | `DELETE /accounts/projects/{project_id}/rooms/{room_id}` | Delete a room. | | `connect_room(project_id, room_name)` | `POST /accounts/projects/{project_id}/rooms/{room_name}/connect` | Return `RoomConnectionInfo` (`jwt`, `room_url`, etc.). | | `create_agent(project_id, configuration, if_not_exists?, permissions?)` | `POST /accounts/projects/{project_id}/agents` | Create a managed agent identity. | | `get_agent(project_id, name)` | `GET /accounts/projects/{project_id}/agents/{agent_name}` | Fetch a managed agent by name. | | `update_agent(project_id, agent_id, configuration)` | `PUT /accounts/projects/{project_id}/agents/{agent_id}` | Update a managed agent. | | `delete_agent(project_id, agent_id)` | `DELETE /accounts/projects/{project_id}/agents/{agent_id}` | Delete a managed agent. | | `connect_agent(project_id, agent)` | `POST /accounts/projects/{project_id}/agents/{agent_name}/connect` | Return `AgentConnectionInfo`. | ## Resource policies Managed agent resource policies are not supported. Use service-account `run_as` configuration for agent access, and use resource policies for supported resource types. | SDK method | HTTP route | What it does | | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------- | | `grant_resource_policy(project_id, resource_type, resource_id, subject, roles)` | `POST /accounts/projects/{project_id}/policies/resources/{resource_type}/{resource_id}` | Grant roles on supported resource types. | | `revoke_resource_policy(project_id, resource_type, resource_id, subject, roles?)` | `DELETE /accounts/projects/{project_id}/policies/resources/{resource_type}/{resource_id}` | Revoke resource-policy roles. | | `get_resource_policy(project_id, resource_type, resource_id, page_size?, continuation_token?)` | `GET /accounts/projects/{project_id}/policies/resources/{resource_type}/{resource_id}` | List direct resource-policy bindings. | ## Project Storage MeshAgent allows you to use both project wide and room specific storage. For room-scoped storage see the [Storage API](../room_api/storage) documentation. | SDK method | HTTP route | What it does | | -------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------ | | `upload(project_id, path, data)` | `POST /projects/{project_id}/storage/upload?path=…` | Upload raw bytes (`Content-Type: application/octet-stream`). | | `download(project_id, path)` | `GET /projects/{project_id}/storage/download?path=…` | Download raw bytes. | ## Services Create and manage project and room services. Project services are available to all rooms in your project while room services are scoped to a specific room. ### Project Services | SDK method | HTTP route | What it does | | ------------------------------------------------------------------------ | -------------------------------------------------------------- | ------------------------------------------------- | | `create_service(project_id, service)` | `POST /accounts/projects/{project_id}/services` | Create a project-level service. | | `create_service_from_template(project_id, template, values)` | `POST /accounts/projects/{project_id}/services` | Create a project service from a template payload. | | `list_services(project_id)` | `GET /accounts/projects/{project_id}/services` | List project services. | | `get_service(project_id, service_id)` | `GET /accounts/projects/{project_id}/services/{service_id}` | Fetch a service spec. | | `update_service(project_id, service_id, service)` | `PUT /accounts/projects/{project_id}/services/{service_id}` | Update a service. | | `update_service_from_template(project_id, service_id, template, values)` | `PUT /accounts/projects/{project_id}/services/{service_id}` | Update a service from a template payload. | | `delete_service(project_id, service_id)` | `DELETE /accounts/projects/{project_id}/services/{service_id}` | Delete a service. | ## Room Services | SDK method | HTTP route | What it does | | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------- | | `create_room_service(project_id, room_name, service)` | `POST /accounts/projects/{project_id}/rooms/{room_name}/services` | Create a room-scoped service. | | `create_room_service_from_template(project_id, room_name, template, values)` | `POST /accounts/projects/{project_id}/rooms/{room_name}/services` | Create a room service from a template payload. | | `list_room_services(project_id, room_name)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/services` | List room services. | | `get_room_service(project_id, room_name, service_id)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/services/{service_id}` | Fetch a room service spec. | | `update_room_service(project_id, room_name, service_id, service)` | `PUT /accounts/projects/{project_id}/rooms/{room_name}/services/{service_id}` | Update a room service. | | `update_room_service_from_template(project_id, room_name, service_id, template, values)` | `PUT /accounts/projects/{project_id}/rooms/{room_name}/services/{service_id}` | Update a room service from a template payload. | | `delete_room_service(project_id, room_name, service_id)` | `DELETE /accounts/projects/{project_id}/rooms/{room_name}/services/{service_id}` | Delete a room service. | ## Secrets Secret workflows use user-owned and service-account-owned secrets; see [Secrets and Credentials](../secrets/overview). ## Routes Create and manage project routes that map domains to rooms, ports, and route specs. | SDK method | HTTP route | What it does | | ------------------------------------------------------------------- | -------------------------------------------------------------- | ----------------------- | | `create_route(project_id, spec? or domain, room_name, port)` | `POST /accounts/projects/{project_id}/routes` | Create a route. | | `update_route(project_id, domain, spec? or room_name, port)` | `PUT /accounts/projects/{project_id}/routes/{domain}` | Update a route. | | `get_route(project_id, domain)` | `GET /accounts/projects/{project_id}/routes/{domain}` | Fetch a route. | | `list_routes(project_id, count?, offset?, filter?)` | `GET /accounts/projects/{project_id}/routes` | List project routes. | | `list_room_routes(project_id, room_name, count?, offset?, filter?)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/routes` | List routes for a room. | | `delete_route(project_id, domain)` | `DELETE /accounts/projects/{project_id}/routes/{domain}` | Delete a route. | ## Feeds and subscriptions Create project feeds, publish messages, and fan them out into room storage through subscriptions. | SDK method | HTTP route | What it does | | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------- | | `create_feed(project_id, name, description?, visibility?, paused?, annotations?, message_schema?)` | `POST /accounts/projects/{project_id}/feeds` | Create a feed. | | `update_feed(project_id, feed_id, name, description?, paused?, annotations?, message_schema?)` | `PUT /accounts/projects/{project_id}/feeds/{feed_id}` | Update a feed. | | `get_feed(project_id, feed_id)` | `GET /accounts/projects/{project_id}/feeds/{feed_id}` | Fetch a feed. | | `list_feeds(project_id, count?, offset?, filter?)` | `GET /accounts/projects/{project_id}/feeds` | List project feeds. | | `list_room_feeds(project_id, room_name, count?, offset?, filter?)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/feeds` | List feeds visible to a room. | | `delete_feed(project_id, feed_id)` | `DELETE /accounts/projects/{project_id}/feeds/{feed_id}` | Delete a feed. | | `publish_feed_message(project_id, feed_id, message)` | `POST /accounts/projects/{project_id}/feeds/{feed_id}/messages` | Publish one message. | | `publish_feed_batch(project_id, feed_id, messages)` | `POST /accounts/projects/{project_id}/feeds/{feed_id}/messages/batch` | Publish a batch. | | `create_feed_subscription(project_id, feed_id, room, path, filename_datetime_format?, annotations?)` | `POST /accounts/projects/{project_id}/feeds/{feed_id}/subscriptions` | Create a subscription. | | `update_feed_subscription(project_id, feed_id, subscription_id, filename_datetime_format?, annotations?)` | `PUT /accounts/projects/{project_id}/feeds/{feed_id}/subscriptions/{subscription_id}` | Update a subscription. | | `get_feed_subscription(project_id, feed_id, subscription_id)` | `GET /accounts/projects/{project_id}/feeds/{feed_id}/subscriptions/{subscription_id}` | Fetch a subscription. | | `list_feed_subscriptions(project_id, feed_id)` | `GET /accounts/projects/{project_id}/feeds/{feed_id}/subscriptions` | List subscriptions. | | `delete_feed_subscription(project_id, feed_id, subscription_id)` | `DELETE /accounts/projects/{project_id}/feeds/{feed_id}/subscriptions/{subscription_id}` | Delete a subscription. | ## LLM loggers Create project LLM loggers that copy LLM proxy events into destination feeds. Use these when you need a feed-backed stream of LLM request metadata for processing or analysis. | SDK method | HTTP route | What it does | | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------- | | `create_llm_logger(project_id, destination_feed_id, filter_expression, paused?, annotations?)` | `POST /accounts/projects/{project_id}/llm-loggers` | Create an LLM logger. | | `update_llm_logger(project_id, logger_id, destination_feed_id, filter_expression, paused?, annotations?)` | `PUT /accounts/projects/{project_id}/llm-loggers/{logger_id}` | Update an LLM logger. | | `get_llm_logger(project_id, logger_id)` | `GET /accounts/projects/{project_id}/llm-loggers/{logger_id}` | Fetch an LLM logger. | | `list_llm_loggers(project_id)` | `GET /accounts/projects/{project_id}/llm-loggers` | List LLM loggers. | | `delete_llm_logger(project_id, logger_id)` | `DELETE /accounts/projects/{project_id}/llm-loggers/{logger_id}` | Delete an LLM logger. | ## Registries Create and manage project-owned image repositories. | SDK method | HTTP route | What it does | | ------------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------- | | `create_repository(project_id, repository)` | `POST /accounts/projects/{project_id}/repositories` | Create a project repository. | | `update_repository(project_id, repository_id, repository)` | `PUT /accounts/projects/{project_id}/repositories/{repository_id}` | Update a repository. | | `get_repository(project_id, repository_id)` | `GET /accounts/projects/{project_id}/repositories/{repository_id}` | Fetch a repository. | | `list_repositories(project_id)` | `GET /accounts/projects/{project_id}/repositories` | List repositories. | | `delete_repository(project_id, repository_id)` | `DELETE /accounts/projects/{project_id}/repositories/{repository_id}` | Delete a repository. | | `create_repository_token(project_id, repository_id, request)` | `POST /accounts/projects/{project_id}/repositories/{repository_id}/token` | Create a repository token. | ## Webhooks | SDK method | HTTP route | What it does | | ------------------------------------------- | -------------------------------------------------------------- | ----------------- | | `create_webhook(project_id, …)` | `POST /accounts/projects/{project_id}/webhooks` | Create a webhook. | | `list_webhooks(project_id)` | `GET /accounts/projects/{project_id}/webhooks` | List webhooks. | | `update_webhook(project_id, webhook_id, …)` | `PUT /accounts/projects/{project_id}/webhooks/{webhook_id}` | Update a webhook. | | `delete_webhook(project_id, webhook_id)` | `DELETE /accounts/projects/{project_id}/webhooks/{webhook_id}` | Delete a webhook. | ## API Keys | SDK method | HTTP route | What it does | | ----------------------------------------------- | ------------------------------------------------------ | ----------------------------------------- | | `create_api_key(project_id, name, description)` | `POST /accounts/projects/{project_id}/api-keys` | Issue a new API key (returns value once). | | `list_api_keys(project_id)` | `GET /accounts/projects/{project_id}/api-keys` | List keys (does not list key value). | | `delete_api_key(project_id, id)` | `DELETE /accounts/projects/{project_id}/api-keys/{id}` | Revoke a key. | ## OAuth clients Manage OAuth Clients for connections with other services. | SDK method | HTTP route | What it does | | ----------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------- | | `create_oauth_client(project_id, …)` | `POST /accounts/projects/{project_id}/oauth/clients` | Create an OAuth client (includes secret). | | `list_oauth_clients(project_id)` | `GET /accounts/projects/{project_id}/oauth/clients` | List OAuth clients. | | `get_oauth_client(project_id, client_id)` | `GET /accounts/projects/{project_id}/oauth/clients/{client_id}` | Fetch one client. | | `update_oauth_client(project_id, client_id, …)` | `PUT /accounts/projects/{project_id}/oauth/clients/{client_id}` | Update a client. | | `delete_oauth_client(project_id, client_id)` | `DELETE /accounts/projects/{project_id}/oauth/clients/{client_id}` | Delete a client. | ## External OAuth registrations Manage project and room external OAuth registrations. These records are separate from project OAuth clients: OAuth clients let your app authenticate users through MeshAgent, while external OAuth registrations connect MeshAgent-managed integrations to external OAuth providers. | SDK method | HTTP route | What it does | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------- | | `create_project_external_oauth_registration(project_id, registration)` | `POST /accounts/projects/{project_id}/external-oauth` | Create a project external OAuth registration. | | `update_project_external_oauth_registration(project_id, registration_id, registration)` | `PUT /accounts/projects/{project_id}/external-oauth/{registration_id}` | Update a project external OAuth registration. | | `list_project_external_oauth_registrations(project_id)` | `GET /accounts/projects/{project_id}/external-oauth` | List project external OAuth registrations. | | `delete_project_external_oauth_registration(project_id, registration_id)` | `DELETE /accounts/projects/{project_id}/external-oauth/{registration_id}` | Delete a project external OAuth registration. | | `create_room_external_oauth_registration(project_id, room_name, registration)` | `POST /accounts/projects/{project_id}/rooms/{room_name}/external-oauth` | Create a room external OAuth registration. | | `update_room_external_oauth_registration(project_id, room_name, registration_id, registration)` | `PUT /accounts/projects/{project_id}/rooms/{room_name}/external-oauth/{registration_id}` | Update a room external OAuth registration. | | `list_room_external_oauth_registrations(project_id, room_name)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/external-oauth` | List room external OAuth registrations. | | `delete_room_external_oauth_registration(project_id, room_name, registration_id)` | `DELETE /accounts/projects/{project_id}/rooms/{room_name}/external-oauth/{registration_id}` | Delete a room external OAuth registration. | ## Shares Manage share records for a project. | SDK method | HTTP route | What it does | | ----------------------------------------------- | ---------------------------------------------------------- | ---------------------- | | `create_share(project_id, settings?)` | `POST /accounts/projects/{project_id}/shares` | Create a share token. | | `list_shares(project_id)` | `GET /accounts/projects/{project_id}/shares` | List shares. | | `update_share(project_id, share_id, settings?)` | `PUT /accounts/projects/{project_id}/shares/{share_id}` | Update share settings. | | `delete_share(project_id, share_id)` | `DELETE /accounts/projects/{project_id}/shares/{share_id}` | Delete a share. | ## Mailboxes Create and manage mailboxes that can be used by Agents or Rooms. | SDK method | HTTP route | What it does | | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | `create_mailbox(project_id, address, room, queue, public?)` | `POST /accounts/projects/{project_id}/mailboxes` | Create a mailbox mapping. | | `list_mailboxes(project_id)` | `GET /accounts/projects/{project_id}/mailboxes` | List mailboxes. | | `list_room_mailboxes(project_id, room_name)` | `GET /accounts/projects/{project_id}/rooms/{room_name}/mailboxes` | List mailboxes for a room. | | `get_mailbox(project_id, address)` | `GET /accounts/projects/{project_id}/mailboxes/{address}` | Get a mailbox. | | `update_mailbox(project_id, address, room, queue, public?)` | `PUT /accounts/projects/{project_id}/mailboxes/{address}` | Update mapping. | | `delete_mailbox(project_id, address)` | `DELETE /accounts/projects/{project_id}/mailboxes/{address}` | Delete mapping. | | `list_mailbox_deliveries(project_id, address, ...)` | `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries` | List recipient deliveries, ordered by `submitted_at DESC, id DESC`. | | `get_mailbox_delivery(project_id, address, delivery_id)` | `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries/{delivery_id}` | Get current delivery status and SMTP details. | | `list_mailbox_delivery_events(project_id, address, delivery_id, ...)` | `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries/{delivery_id}/events` | List provider events, ordered by `occurred_at ASC, id ASC`. | Delivery routes require `mailboxes:read` plus the project `mailbox_inventory` relation. They are not room-scoped, and the response does not repeat the mailbox address because it is already part of the request path. Project API keys retain project-wide access. ### Delivery status API `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries` returns one current delivery record per recipient. Results are newest first and the response has the shape `{ "deliveries": [...], "total": number }`. It accepts: | Query parameter | Description | | --------------- | ----------------------------------------------------------------- | | `status` | Current status: `accepted`, `deferred`, `delivered`, or `failed`. | | `recipient` | Case-insensitive recipient substring. | | `message_id` | Exact message ID. | | `count` | Page size from 1 through 1000; defaults to 100. | | `offset` | Zero-based row offset; defaults to 0. | `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries/{delivery_id}` returns `{ "delivery": {...} }`. The record contains the current status, submission and recipient identifiers, status timestamps, attempt count, and the latest available SMTP, MX host, TLS, and failure details. `GET /accounts/projects/{project_id}/mailboxes/{address}/deliveries/{delivery_id}/events` returns `{ "events": [...], "total": number }`. It accepts `count` and `offset`, and returns events in chronological order. The normalized event types are `accepted`, `temporary_failed`, `delivered`, and `permanent_failed`; their resulting delivery statuses are `accepted`, `deferred`, `delivered`, and `failed`, respectively. Each event includes its occurrence and receipt times, provider event ID, resulting status, and any provider-supplied attempt, SMTP, MX host, TLS, certificate, reason, and description fields. ## Sessions Inspect active/recent sessions and fetch diagnostics, or terminate sessions. | SDK method | HTTP route | What it does | | ----------------------------------------------------------- | ------------------------------------------------------------------------ | --------------------------- | | `list_active_sessions(project_id)` | `GET /accounts/projects/{project_id}/sessions/active` | List active sessions. | | `list_recent_sessions(project_id)` | `GET /accounts/projects/{project_id}/sessions` | List recent sessions. | | `get_session(project_id, session_id)` | `GET /accounts/projects/{project_id}/sessions/{session_id}` | Fetch session metadata. | | `list_session_events(project_id, session_id)` | `GET /accounts/projects/{project_id}/sessions/{session_id}/events` | Session event stream. | | `list_session_spans(project_id, session_id)` | `GET /accounts/projects/{project_id}/sessions/{session_id}/spans` | Trace spans. | | `list_session_metrics(project_id, session_id)` | `GET /accounts/projects/{project_id}/sessions/{session_id}/metrics` | Metrics data. | | `get_session_participant_counts(project_id, session_id)` | `GET /accounts/projects/{project_id}/sessions/{session_id}/participants` | Participant counts. | | `list_active_agent_sessions(project_id)` | `GET /accounts/projects/{project_id}/agents/sessions/active` | List active agent sessions. | | `list_recent_agent_sessions(project_id, limit?, agent_id?)` | `GET /accounts/projects/{project_id}/agents/sessions` | List recent agent sessions. | | `terminate(project_id, session_id)` | `POST /accounts/projects/{project_id}/sessions/{session_id}/terminate` | Terminate a session. | ## Scheduled Tasks Scheduled tasks let you automate room workflows by sending queued messages on a schedule (cron or one-time). | SDK method | HTTP route | What it does | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------ | | `create_scheduled_task(project_id, room_name, …)` | `POST /accounts/projects/{project_id}/rooms/{room_name}/scheduled-tasks` | Create a scheduled task. | | `update_scheduled_task(project_id, task_id, …)` | `PUT /accounts/projects/{project_id}/scheduled-tasks/{task_id}` | Update a task. | | `delete_scheduled_task(project_id, task_id)` | `DELETE /accounts/projects/{project_id}/scheduled-tasks/{task_id}` | Delete a task. | | `list_scheduled_tasks(project_id, room_id?, task_id?, active?, limit?, offset?)` | `GET /accounts/projects/{project_id}/scheduled-tasks` | List tasks with filters. | | `list_scheduled_task_runs(project_id, task_id, limit?, offset?)` | `GET /accounts/projects/{project_id}/scheduled-tasks/{task_id}/runs` | List task runs. | ## Billing & usage Checkout balances, transactions, subscriptions, and usage reports. | SDK method | HTTP route | What it does | | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `get_pricing()` | `GET /pricing` | Fetch pricing metadata. | | `get_balance(project_id)` | `GET /accounts/projects/{project_id}/balance` | Fetch current balance and auto-recharge config, including the monthly auto-recharge budget. | | `get_recent_transactions(project_id)` | `GET /accounts/projects/{project_id}/transactions` | List recent transactions. | | `set_auto_recharge(project_id, enabled, amount, threshold, monthly_budget?)` | `POST /accounts/projects/{project_id}/recharge` | Configure auto-recharge and an optional monthly auto-recharge budget. | | `get_checkout_url(project_id, success_url, cancel_url)` | `POST /accounts/projects/{project_id}/subscription` | Create subscription checkout; returns `checkout_url`. | | `get_credits_checkout_url(project_id, success_url, cancel_url, quantity)` | `POST /accounts/projects/{project_id}/credits` | Purchase credits checkout; returns `checkout_url`. | | `get_subscription(project_id)` | `GET /accounts/projects/{project_id}/subscription` | Fetch subscription info. | | `get_usage(project_id, start?, end?, interval?, report?, users?, room?, provider?, model?, usage_type?)` | `GET /accounts/projects/{project_id}/usage` | Usage reporting with optional filters. | ## What’s next? * Explore the [Room API overview](../room_api/overview) to work with live collaborative rooms. * Review the [`ApiScope` reference](./api_scopes) for details on permission shape. * Learn how room connections inherit grants in [participant tokens](./participant_tokens). # Participant Tokens Source: https://docs.meshagent.com/rest_api/participant_tokens Every participant in a MeshAgent room operates with a secure token that defines their identity and permissions. These JWT-based tokens ensure that users, containers, and services can only access the resources they're authorized to use. ## Token Anatomy MeshAgent exposes tokens through `meshagent.api.participant_token.ParticipantToken` which consists of: * `name`: the participant identifier embedded in the JWT payload * `project_id` (optional): the project id, populated when the participant belongs to a project * `api_key_id` (optional): the API key id used to mint the token * `version` (optional): the participant-token schema version (defaulted when omitted) * `grants` (optional): a list of individual `ParticipantGrant` entries that describe permissions ### Permission Types Participant tokens use grants and scopes to define permissions. Each grant has a grant name which indicates the type of permission (`room`, `role`, `api`), and each grant has a scope which provides the specific details of what is allowed. | Grant | Scope format | What it controls | | ------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `room` | room name string | Which room the participant may join (`add_room_grant`) | | `role` | `"agent" \| "tool" \| "user"` | Participant role advertised to other services (`add_role_grant`) | | `api` | [`ApiScope`](./api_scopes) object | Fine-grained access to each Room API surface (`add_api_grant`). A single `ApiScope` can enable multiple sections (storage, containers, secrets, etc.) | **Tunnels and port forwarding** Port forwarding is authorized via the `api.tunnels` grant (see [API Scopes](./api_scopes)). If `tunnels` is omitted, tunnel access is denied. If `tunnels.ports` is omitted or empty, all ports are allowed; otherwise only the listed ports are allowed. Some older tokens include a top-level `tunnel_ports` grant, but current tunnel enforcement uses `api.tunnels`. ```yaml theme={null} # Allow port forwarding to container port 9000 api: tunnels: ports: ["9000"] ``` ## How tokens are issued MeshAgent signs participant tokens automatically for room connections it creates on your behalf. Deployed services describe the identity and permissions in their manifest. Local development commands can also mint a room-scoped token for the process they start. When building a custom application on MeshAgent, generate ParticipantTokens so participants can connect to your rooms with the appropriate permissions. * **Project services and room containers**: MeshAgent reads the manifest for each endpoint or container (identity, role, `api` scope) and injects the signed token into the runtime as `MESHAGENT_TOKEN` during startup. * **Local room-connected processes**: `meshagent room connect --identity -- ` mints a participant token locally for that identity and starts the command with `MESHAGENT_TOKEN`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` set to that room-scoped token. Use `--meshagent-token` when you need to choose the API scope (`agentDefault`, `userDefault`, `full`, or a JSON `ApiScope`). * **End-user connections**: When a participant connects to the room, MeshAgent looks up the participant’s permissions and returns the JWT to the browser or client that is joining the room. * **Custom apps built on MeshAgent**: When building a custom app on MeshAgent, create a `ParticipantToken` and define permissions for your users. Service-account API keys authenticate the service account; they do not bypass room or agent policy. Tokens requested normally use the service account's effective resource role. A service account with `participant_token_creator` can pass `email` when connecting to a room or agent, or when requesting a participant token, to act as that user or service account. MeshAgent still derives the token permissions from the target subject's effective role on the requested resource. ## Generate a token from the CLI Use `meshagent token` when you need to sign a participant token yourself. This is useful for custom clients, coding agents, or temporary room identities that need to access room APIs directly. Create a token spec file such as `token-spec.yaml`: ```yaml theme={null} version: v1 kind: ParticipantToken identity: my-client room: my-room role: user api: llm: {} ``` Current CLI token specs require an explicit `api.llm` field. Include `api.llm: {}` when the token should make LLM proxy requests; tokens without `api.llm` are rejected by the proxy. The main fields are: * `identity`: the participant name in the room * `room`: the room this token should join * `role`: `user`, `agent`, or `tool` * `api`: the [API scope](./api_scopes) for that participant. In the current CLI token spec, this must include `llm`. Generate the token: ```bash theme={null} meshagent token --input token-spec.yaml ``` Write it to a file instead: ```bash theme={null} meshagent token --input token-spec.yaml --output room.token ``` By default, the command uses the active project and active API key. Use `--project-id` or `--key` when you want to override those defaults. ## Related topics * [`ApiScope` reference](./api_scopes) * [Managing project room grants](../rest_api/overview) * [MeshAgent LLM Proxy](../agents/routing/llm_proxy) # Agents Source: https://docs.meshagent.com/room_api/agents ## Overview The `AgentsClient` is the Room API for calling agents and discovering the toolkits available in a room. Use it when you want to send work to a deployed agent, inspect which built-in or service-provided toolkits are available, or call a tool directly. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room agents --help meshagent room agents list-toolkits --room myroom meshagent room agents invoke-tool --room myroom --toolkit my-toolkit --tool my_tool ``` ## Why use the Agents API? * Call a named agent endpoint from the CLI or SDK instead of wiring your own service-to-service protocol. * Discover the tools available in the current room before handing work to an agent or rendering a tool picker. * Invoke a room toolkit directly when you already know which tool you want. ## How it works The Agents API exposes three core concepts: * **Agent**: a named endpoint you call with `make_call` / `call`. * **Toolkit**: a named collection of tools available in the room. * **Tool**: an individual operation inside a toolkit. `list_toolkits` returns toolkit metadata objects, and each toolkit contains a `tools` list with the corresponding tool metadata. That metadata is useful when you need to inspect available tools or render dynamic tool UIs, but most users only need the three methods below. If you are looking for how to create or deploy agents, start with [`meshagent process`](../agents/process/overview) and the broader [Agents overview](../agents/overview). This page is about interacting with agents and toolkits that are already available in a room. ## Permissions and grants The Agents API is controlled by the `agents` grant on the participant token. In practice: * use `call`, `use_agents`, and `use_tools` when a service needs to call agents or invoke tools * use `register_agent`, `register_public_toolkit`, and `register_private_toolkit` when a service needs to publish agents or toolkits into the room See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## API reference Use the methods below to call a named agent endpoint, inspect toolkits in the room, or invoke a tool directly. ### `call(...)` / `make_call(...)` * **Description**: Send a request to an agent to perform an action. Python uses `make_call`; other SDKs use `call`. * **Parameters**: * `name`: The agent name. * `url`: The route on the agent to call. * `arguments`: Payload to send. * `api` *(optional, Python)*: Room API scope to include with the call. * **Returns**: `None`. ```python Python theme={null} await room.agents.make_call( name="example-agent", url="some-endpoint", arguments={"foo": "bar"}, ) ``` ```javascript NodeJs theme={null} await room.agents.call({ name: "example-agent", url: "some-endpoint", arguments: { foo: "bar" }, }); ``` ```typescript TypeScript theme={null} await room.agents.call({ name: "example-agent", url: "some-endpoint", arguments: { foo: "bar" }, }); ``` ```dart Dart theme={null} await room.agents.call( name: "example-agent", url: "some-endpoint", arguments: {"foo": "bar"}, ); ``` ```dotnet C# theme={null} await room.Agents.MakeCall( "example-agent", "some-endpoint", new Dictionary { ["foo"] = "bar" } ); ``` ### `list_toolkits()` * **Description**: Get the toolkits currently available in the room. * **Parameters**: * `participant_id` *(optional, Python)*: Filter toolkits for a given participant. * `participant_name` *(optional, Python)*: Filter toolkits for a participant by name. * `timeout` *(optional, Python)*: Discovery timeout in seconds. * **Returns**: `ToolkitDescription[]`, where each toolkit includes its metadata and a `tools` list. ```bash CLI theme={null} meshagent room agents list-toolkits \ --room myroom ``` ```python Python theme={null} all_toolkits = await room.agents.list_toolkits() for toolkit in all_toolkits: print(f"Toolkit: {toolkit.name}, Tools: {[tool.name for tool in toolkit.tools]}") ``` ```javascript NodeJs theme={null} const allToolkits = await room.agents.listToolkits(); allToolkits.forEach((toolkit) => { console.log(`Toolkit: ${toolkit.name}, Tools: ${toolkit.tools.map((t) => t.name)}`); }); ``` ```typescript TypeScript theme={null} const allToolkits = await room.agents.listToolkits(); allToolkits.forEach((toolkit) => { console.log(`Toolkit: ${toolkit.name}, Tools: ${toolkit.tools.map((t) => t.name)}`); }); ``` ```dart Dart theme={null} final allToolkits = await room.agents.listToolkits(); for (final toolkit in allToolkits) { print('Toolkit: ${toolkit.name}, Tools: ${toolkit.tools.map((t) => t.name).join(", ")}'); } ``` ```dotnet C# theme={null} var toolkits = await room.Agents.ListToolkits(); foreach (var toolkit in toolkits) { Console.WriteLine($"{toolkit.Name}: {toolkit.Title}"); foreach (var tool in toolkit.Tools) { Console.WriteLine($" {tool.Name}: {tool.Title}"); } } ``` ### `invoke_tool(...)` * **Description**: Invoke a tool inside a toolkit directly. * **Parameters**: * `toolkit`: Toolkit name. * `tool`: Tool name. * `input` *(Python/Dart)*: Payload for the tool. * `arguments` *(JS/TS/.NET)*: Payload for the tool. * `participant_id` *(optional, Python)*: Target a specific participant-hosted toolkit. * `on_behalf_of_id` *(optional, Python)*: Invoke on behalf of another participant when the token allows it. * **Returns**: Tool output (`Content` / `JsonChunk`, depending on the SDK). ```bash CLI theme={null} meshagent room agents invoke-tool \ --room myroom \ --toolkit example-toolkit \ --tool toolA \ --arguments '{"param1":"value1"}' ``` ```python Python theme={null} response = await room.agents.invoke_tool( toolkit="example-toolkit", tool="toolA", input={"param1": "value1"}, ) ``` ```javascript NodeJs theme={null} const response = await room.agents.invokeTool({ toolkit: "example-toolkit", tool: "toolA", arguments: { param1: "value1" }, }); ``` ```typescript TypeScript theme={null} const response = await room.agents.invokeTool({ toolkit: "example-toolkit", tool: "toolA", arguments: { param1: "value1" }, }); ``` ```dart Dart theme={null} final response = await room.agents.invokeTool( toolkit: "example-toolkit", tool: "toolA", input: ToolContentInput( JsonContent(json: {"param1": "value1"}), ), ); ``` ```dotnet C# theme={null} var toolArgs = new Dictionary { ["param1"] = "value1" }; var toolResult = await room.Agents.InvokeTool("example-toolkit", "toolA", toolArgs); ``` ## Related guides * [Room API Overview](./overview) * [Service YAML](../services/deployment/deploy_services) * [Agents Overview](../agents/overview) # Containers Source: https://docs.meshagent.com/room_api/containers ## Overview The `ContainersClient` lets you run temporary containers inside a room. Use it for one-off jobs, debugging, image management, or testing code in the same room environment that deployed services use. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room container --help meshagent room container image list --room myroom meshagent room container image pull --room myroom --tag meshagent/cli:default meshagent room container run --room myroom --image meshagent/cli:default meshagent room container list --room myroom ``` ## Why use the Containers API? * Pull and manage images without leaving the room context. * Run short-lived workloads or exploratory commands on demand. * Inspect logs or open an interactive terminal in a running container. ## How it works Containers are room-scoped workloads. You can pull images, run a container, stream logs, exec into it, stop it, and delete its metadata when you are done. Deployed Room Services and Project Services rely on the same underlying container infrastructure, but the Containers API gives you direct, on-demand control. ## Permissions and grants The Containers API is controlled by the `containers` grant on the participant token. In practice: * `use_containers` is the main switch for container operations * `pull` and `run` can be narrowed to specific image names or prefixes * `logs` controls access to container log streaming See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## API reference Use the methods below to manage room images, start and inspect containers, and clean up container state. The SDKs also expose image-transfer helpers such as `push_image`, `load` / `load_image`, `save_image`, build helpers such as `build`, `list_builds`, `cancel_build`, `delete_build`, and `get_build_logs`, and service helpers such as `run_service`. ### `list_images()` * **Description**: List images currently available to the room (built or pulled previously). * **Parameters**: None. * **Returns**: `list[Image]` summary records including `id`, `preferred_ref`, `references`, `labels`, `created_at`, `updated_at`, and `target_media_type`. ```bash CLI theme={null} meshagent room container image list \ --room myroom ``` ```python Python theme={null} images = await room.containers.list_images() for image in images: print(image.preferred_ref, image.id) ``` ### `inspect_image(image_id)` * **Description**: Inspect a room image by ID and return detailed content metadata from the container runtime. * **Parameters**: * `image_id`: Image ID from `list_images()`. * **Returns**: `ImageInspection` including the image summary, target descriptor, selected manifest, manifests, config descriptor, layers, and `content_size`. ```bash CLI theme={null} meshagent room container image inspect \ --room myroom \ --image-id sha256:abc123 ``` ```python Python theme={null} inspection = await room.containers.inspect_image(image_id="sha256:abc123") print(inspection.image.preferred_ref, inspection.content_size) for layer in inspection.layers: print(layer.digest, layer.size) ``` ### `delete_image(image)` * **Description**: Delete an unused image from the room. * **Parameters**: * `image`: Tag or digest string to delete. * **Returns**: `None`. ```bash CLI theme={null} meshagent room container image delete \ --room myroom \ --image chatbot:old ``` ```python Python theme={null} await room.containers.delete_image(image="chatbot:old") ``` ### `pull_image(tag, credentials=None)` * **Description**: Pull an image into the room. Supports passing registry credentials when needed. * **Parameters**: * `tag`: Image reference (e.g. `myrepo/app:latest`). * `credentials`: Optional list of `DockerSecret` credentials for private registries. * **Returns**: `None` once the pull completes. ```bash CLI theme={null} meshagent room container image pull \ --room myroom \ --tag registry.example.com/agents/chatbot:0.2 ``` ```python Python theme={null} await room.containers.pull_image(tag="registry.example.com/agents/chatbot:0.2") ``` ### `run(image, ...)` * **Description**: Start a container in the room. * **Parameters** (all optional except `image`): * `image`: Container image to run. * `command`: Override the default command (`str`). * `working_dir`: Working directory for the container process. * `env`: Environment variables injected as `dict[str, str]`. * `mount_path`, `mount_subpath`: Mount configuration when using storage. * `mounts`: Structured container mount configuration for advanced mount layouts. * `role`, `participant_name`: Launch on behalf of a specific room identity. * `ports`: Port mappings `{container_port: host_port}`. * `credentials`: Registry secrets for the image. * `name`: Friendly name for the container. * `template`: Runtime defaults to apply. `"none"` (default) applies no template defaults; `"agent"` mounts room storage at `/data` and injects MeshAgent/OpenAI/Anthropic/SMTP proxy environment variables using a token for the container name with role `agent`. * `writable_root_fs`: Override whether the container root filesystem is writable. * `private`: Request private container placement where supported. * **Returns**: Container ID string. ```bash CLI theme={null} meshagent room container run \ --room myroom \ --image registry.example.com/agents/chatbot:0.2 \ --env SYSTEM_PROMPT="Always respond with a fun fact." \ --container-name chatbot-demo ``` ```python Python theme={null} container_id = await room.containers.run( image="registry.example.com/agents/chatbot:0.2", env={"SYSTEM_PROMPT": "Always respond with a fun fact."}, name="chatbot-demo", ) print(f"Container launched: {container_id}") ``` ### `exec(container_id, ...)` * **Description**: Attach an interactive command to an existing container and stream its output. * **Parameters**: * `container_id`: Target container. * `command`: Optional command list; defaults to the container's shell. * `tty`: Request a TTY session (`True` for interactive). * **Returns**: An exec-session object (`ExecSession` in Python) exposing helpers to read output, send input, resize the terminal, and await completion. ```bash CLI theme={null} meshagent room container exec \ --room myroom \ --container-id "$CONTAINER_ID" \ --command "bash" ``` ```python Python theme={null} session = await room.containers.exec( container_id=container_id, command=["bash"], tty=True, ) async for chunk in session.stdout(): print(chunk.decode(), end="") # (Optional) Send input; for example, list files then exit the shell await session.write(b'ls -la\n') await session.write(b'exit\n') # end the interactive session status = await session.result print(f"Exec finished with status: {status}") ``` The CLI streams a non-TTY exec session. Use the SDK directly when you need an explicit TTY session and terminal resize control. ### Image transfer helpers In addition to pulling an image into a room, the CLI can push an image from the room to a registry, load an OCI archive from room storage, or save an image as an OCI archive: ```bash bash theme={null} meshagent room container image push \ --room myroom \ --tag registry.example.com/agents/chatbot:0.2 meshagent room container image load \ --room myroom \ --archive-path /images/chatbot.tar meshagent room container image save \ --room myroom \ --tag registry.example.com/agents/chatbot:0.2 \ --archive-path /workspace/chatbot.tar \ --mount-room-path /images:/workspace ``` The Python SDK exposes these container image, build, service, and lifecycle helpers: ```python Python theme={null} await room.containers.push_image(tag="registry.example.com/agents/chatbot:0.2", credentials=None, private=False) await room.containers.load(archive_path="/images/chatbot.tar") await room.containers.load_image(mounts=mounts, archive_path="/workspace/chatbot.tar", private=False) await room.containers.save_image(tag="registry.example.com/agents/chatbot:0.2", mounts=mounts, archive_path="/workspace/chatbot.tar", private=False) build_id = await room.containers.build( tags=["registry.example.com/agents/chatbot:0.2"], mount_path="/workspace", context_path=".", chunks=chunks, dockerfile_path=None, optimize_image=True, private=False, credentials=None, builder_name=None, size=None, ) builds = await room.containers.list_builds() await room.containers.cancel_build(build_id=build_id) await room.containers.delete_build(build_id=build_id) logs = room.containers.get_build_logs(build_id=build_id, follow=True) container_id = await room.containers.run_service(service_id="svc_123", env=None) exit_code = await room.containers.wait_for_exit(container_id=container_id) status = await room.containers.wait_for_exit_status(container_id=container_id) ``` ### `logs(container_id, follow=False)` * **Description**: Stream container logs and optionally follow until exit. * **Parameters**: * `container_id`: Target container. * `follow`: `True` to keep streaming until the container exits. * **Returns**: `LogStream[None]`, which you can iterate for log lines or await for completion. ```bash CLI theme={null} meshagent room container log \ --room myroom \ --id "$CONTAINER_ID" \ --follow ``` ```python Python theme={null} stream = room.containers.logs(container_id=container_id, follow=True) async for line in stream.logs(): print(line) await stream # optional: wait for the request to finish ``` ### `list(all=None)` * **Description**: List containers in the room, optionally including exited ones. * **Parameters**: * `all`: `True` to include stopped containers. * **Returns**: `list[RoomContainer]` with name, image, state, status, applicable manifest, and metadata about who started it. ```bash CLI theme={null} meshagent room container list \ --room myroom \ --all \ --output table ``` ```python Python theme={null} containers = await room.containers.list(all=True) for container in containers: print(container.id, container.state, container.started_by.name) ``` ### `stop(container_id, force=False)` * **Description**: Request a graceful stop (or force stop) of a running container. * **Parameters**: * `container_id`: Target container. * `force`: Send a forceful termination signal when `True`. * **Returns**: `None`. ```bash CLI theme={null} meshagent room container stop \ --room myroom \ --id "$CONTAINER_ID" ``` ```python Python theme={null} await room.containers.stop(container_id=container_id, force=False) ``` ### `delete(container_id)` * **Description**: Remove container metadata after it has stopped. Useful for cleaning up history. * **Parameters**: * `container_id`: Container to delete. * **Returns**: `None`. ```python Python theme={null} await room.containers.delete(container_id=container_id) ``` ## Related guides * [Room API Overview](./overview) * [Service YAML](../services/deployment/deploy_services) * [MeshAgent Studio](../interfaces/meshagent_studio) # Datasets Source: https://docs.meshagent.com/room_api/datasets ## Overview The `DatasetsClient` is the Room API for room-scoped structured data. Use it to create tables, insert and update rows, build indexes, and run text or vector search without provisioning a separate dataset. Datasets are designed and optimized for batch writes, indexing, scans, search, and retrieval. They are not a transactional database replacement: avoid using them for high-frequency row-by-row mutations, cross-table transactions, locks, or workloads that require immediate transactional consistency. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room dataset --help meshagent room dataset table --room myroom meshagent room dataset inspect --room myroom --table users meshagent room dataset search --room myroom --table users ``` ## Why use the Datasets API? * Keep structured room data close to the agents and services that use it. * Support filtering, analytics, semantic search, and retrieval workflows in one place. * Manage schemas and indexes through the same Room API surface you already use for messaging, storage, and sync. ## How it works Each room dataset contains named tables. You can create tables from a schema or from raw data, update rows, create scalar/full-text/vector indexes, and run searches that combine filters with text or vector similarity. Use it when your room needs structured records instead of only files or chat history. > Current implementation: MeshAgent room dataset is currently backed directly by Lance datasets, which provide the table, vector, and full-text primitives used by the room dataset toolkit. > Typed values: MeshAgent also supports `json`, `uuid`, `list`, and `struct` dataset types. In the typed SDKs, use the wrapper classes for those values, such as `DatasetJson`, `DatasetStruct`, `DatasetUuid` / `UuidValue`, and `DatasetExpression` where the client requires them. ## Permissions and grants The Datasets API is controlled by the `dataset` grant on the participant token. In practice: * `list_tables` controls whether the participant can list tables * table grants control `read`, `write`, and `alter` access per table * if no table list is supplied, access is broad across the room dataset See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## API reference Use the methods below to manage room tables, rows, indexes, and search workflows. Most methods are asynchronous calls that you `await`; streaming helpers such as `sql_stream()`, `search_stream()`, and `watch_table()` return async iterators that you consume with `async for`. ### Python SDK signatures The examples below focus on common cross-SDK workflows. The Python SDK also exposes namespace, branch, version, streaming, SQL, and maintenance helpers directly on `room.datasets`: ```python Python theme={null} await room.datasets.list_tables(namespace=None, branch=None) await room.datasets.inspect(table="users", namespace=None, branch=None, version=None) await room.datasets.create_table_with_schema( name="users", schema=None, data=None, mode="create", namespace=None, branch=None, metadata=None, ) await room.datasets.create_table_from_data( name="users", data=None, mode="create", namespace=None, branch=None, metadata=None, ) await room.datasets.create_table_from_data_stream( name="users", chunks=chunks, schema=None, mode="create", namespace=None, branch=None, metadata=None, ) await room.datasets.create_table_from_json_data( name="users", data=None, mode="create", namespace=None, branch=None, metadata=None, ) await room.datasets.drop_table(name="users", ignore_missing=False, namespace=None, branch=None) await room.datasets.rename_table(name="users", new_name="customers", namespace=None, branch=None) await room.datasets.add_columns(table="users", new_columns={"active": "true"}, namespace=None, branch=None) await room.datasets.drop_columns(table="users", columns=["active"], namespace=None, branch=None) await room.datasets.insert(table="users", records=records, namespace=None, branch=None) await room.datasets.insert_stream(table="users", chunks=chunks, namespace=None, branch=None) await room.datasets.update(table="users", where="id = 1", values={"email": "alice@example.com"}, namespace=None, branch=None) await room.datasets.delete(table="users", where="id = 1", namespace=None, branch=None) await room.datasets.merge(table="users", on="id", records=records, namespace=None, branch=None) await room.datasets.merge_stream(table="users", on="id", chunks=chunks, namespace=None, branch=None) rows = await room.datasets.sql(query="select * from users", tables=None, params=None, namespace=None, branch=None) opened = await room.datasets.open_sql_query(query="select * from users", tables=None, params=None, namespace=None, branch=None) result = await room.datasets.execute_sql(query="select * from users", tables=None, params=None, namespace=None, branch=None) async for batch in room.datasets.sql_stream(query="select * from users", tables=None, params=None, namespace=None, branch=None): ... async for batch in room.datasets.read_sql_query(query_id=opened.query_id): ... await room.datasets.close_sql_query(query_id=opened.query_id) await room.datasets.cancel_sql_query(query_id=opened.query_id) rows_affected = await room.datasets.execute_sql_statement(query="delete from users where active = false", tables=None, params=None, namespace=None, branch=None) rows = await room.datasets.search( table="users", text=None, vector=None, where=None, offset=None, limit=None, select=None, namespace=None, branch=None, version=None, ) async for batch in room.datasets.search_stream( table="users", text=None, vector=None, where=None, offset=None, limit=None, select=None, namespace=None, branch=None, version=None, ): ... async for event in room.datasets.watch_table(table="users", namespace=None, branch=None, poll_interval_seconds=0.5): ... count = await room.datasets.count(table="users", text=None, vector=None, where=None, namespace=None, branch=None, version=None) await room.datasets.optimize(table="users", namespace=None, branch=None, config=None) stats = await room.datasets.stats(table="users", namespace=None, branch=None, version=None, max_rows_per_group=None) await room.datasets.restore(table="users", version=12, namespace=None, branch=None) versions = await room.datasets.list_versions(table="users", namespace=None, branch=None) await room.datasets.create_index(table="users", config=index_config, namespace=None, branch=None) await room.datasets.drop_index(table="users", name="users_email_idx", namespace=None, branch=None) indexes = await room.datasets.list_indexes(table="users", namespace=None, branch=None, version=None) branches = await room.datasets.list_branches(namespace=None) await room.datasets.create_branch(branch="exp", from_branch=None, namespace=None) await room.datasets.delete_branch(branch="exp", namespace=None) ``` ### `list_tables()` **Description** Retrieves a list of all table names currently present in the dataset. **Returns**: * A promise that resolves to an array of table name strings. ```bash CLI theme={null} meshagent room dataset table \ --room myroom ``` ```python Python theme={null} tables = await room.datasets.list_tables() print(tables) # ["users", "orders", "products", ...] ``` ```javascript NodeJs theme={null} const tables = await room.datasets.listTables(); console.log(tables); // ["users", "orders", "products", ...] ``` ```typescript TypeScript theme={null} const tables = await room.datasets.listTables(); console.log(tables); // ["users", "orders", "products", ...] ``` ```dart Dart theme={null} final tables = await room.datasets.listTables(); print(tables); // ["users", "orders", "products", ...] ``` ```dotnet C# theme={null} var tables = await room.Datasets.ListTables(); Console.WriteLine(string.Join(", ", tables)); // ["users", "orders", "products", ...] ``` ### `create_table_with_schema(...)` * **Description**: Creates a new table with an optional schema and initial data. You can specify how the table should be created through the `mode` parameter. * **modes**: * `"create"`: Creates the table; fails if it already exists. * `"overwrite"`: Drops the existing table (if any) and creates a new one. * `"create_if_not_exists"`: Creates the table only if it does not already exist. * **Parameters**: * **name**: The name of the new table. * **schema**: An optional record defining column names and their data types. * **data**: An optional array of initial records to populate the table. Prefer batching records together rather than issuing many single-row writes. * **mode**: The creation mode (default is `"create"`). * **Returns**: A promise that resolves once the table is created. **Example**: ```bash CLI theme={null} meshagent room dataset create \ --room myroom \ --table users \ --columns "id int, username text, email text" \ --data-json '[{"id":1,"username":"alice","email":"alice@example.com"},{"id":2,"username":"bob","email":"bob@example.com"}]' ``` ```python Python theme={null} import pyarrow as pa await room.datasets.create_table_with_schema( name="users", schema={ "id": pa.int64(), "username": pa.string(), "email": pa.string(), }, data=[ {"id": 1, "username": "alice", "email": "alice@example.com" }, {"id": 2, "username": "bob", "email": "bob@example.com" } ], mode="create" ) ``` ```javascript NodeJs theme={null} import { Field, Int64, Schema, Utf8 } from "apache-arrow"; await room.datasets.createTableWithSchema({ name: "users", schema: new Schema([ new Field("id", new Int64()), new Field("username", new Utf8()), new Field("email", new Utf8()), ]), mode: "create", }); ``` ```typescript TypeScript theme={null} import { Field, Int64, Schema, Utf8 } from "apache-arrow"; await room.datasets.createTableWithSchema({ name: "users", schema: new Schema([ new Field("id", new Int64()), new Field("username", new Utf8()), new Field("email", new Utf8()), ]), mode: "create", }); ``` ```dart Dart theme={null} await room.datasets.createTableWithArrowSchema( name: "users", schema: arrowIpcSchema, mode: "create", ); ``` ```dotnet C# theme={null} await room.Datasets.CreateTableWithSchema( "users", new ArrowSchema(new[] { new ArrowField("id", Int64Type.Default, true), new ArrowField("username", StringType.Default, true), new ArrowField("email", StringType.Default, true), }, null), CreateMode.create ); ``` ### `create_table_from_data(...)` * **Description**: Creates a table using only data and an optional mode. * **Parameters**: * **name**: The table name to create. * **data**: An array of records to initialize the table with. * **mode**: Table creation mode (default `"create"`). * **Returns**: A promise that resolves once the table is created. **Example**: ```bash CLI theme={null} meshagent room dataset create \ --room myroom \ --table orders \ --mode overwrite \ --data-json '[{"id":1,"product":"Laptop","quantity":2},{"id":2,"product":"Phone","quantity":5}]' ``` ```python Python theme={null} await room.datasets.create_table_from_data( name="orders", data=[ {"id": 1, "product": "Laptop", "quantity": 2}, {"id": 2, "product": "Phone", "quantity": 5}, ], mode="overwrite" ) ``` ```javascript NodeJs theme={null} await room.datasets.createTableFromData({ name: "orders", data: [ { id: 1, product: "Laptop", quantity: 2 }, { id: 2, product: "Phone", quantity: 5 }, ], mode: "overwrite", }); ``` ```typescript TypeScript theme={null} await room.datasets.createTableFromData({ name: "orders", data: [ { id: 1, product: "Laptop", quantity: 2 }, { id: 2, product: "Phone", quantity: 5 }, ], mode: "overwrite", }); ``` ```dart Dart theme={null} await room.datasets.createTableFromData( name: "orders", data: [ {"id": 1, "product": "Laptop", "quantity": 2}, {"id": 2, "product": "Phone", "quantity": 5}, ], mode: "overwrite", ); ``` ```dotnet C# theme={null} await room.Datasets.CreateTableFromData( "orders", new List> { new() { ["id"] = 1, ["product"] = "Laptop", ["quantity"] = 2 }, new() { ["id"] = 2, ["product"] = "Phone", ["quantity"] = 5 }, }, CreateMode.overwrite ); ``` ### `drop_table(name, ...)` * **Description**: Drops (deletes) a table by name, optionally ignoring if it does not exist. * **Parameters**: * **name**: The name of the table to drop. * **ignoreMissing**: If `true`, no error is thrown if the table does not exist. * **Returns**: A promise that resolves once the table is dropped. **Example**: ```bash CLI theme={null} meshagent room dataset drop \ --room myroom \ --table temp_table \ --ignore-missing ``` ```python Python theme={null} await room.datasets.drop_table( name="temp_table", ignore_missing=True ) ``` ```javascript NodeJs theme={null} await room.datasets.dropTable({ name: "temp_table", ignoreMissing: true, }); ``` ```typescript TypeScript theme={null} await room.datasets.dropTable({ name: "temp_table", ignoreMissing: true, }); ``` ```dart Dart theme={null} await room.datasets.dropTable( name: "temp_table", ignoreMissing: true, ); ``` ```dotnet C# theme={null} await room.Datasets.DropTable("temp_table", ignoreMissing: true); ``` ### `add_columns(...)` * **Description**: Adds one or more columns to an existing table, specifying default value expressions. * **Parameters**: * **table**: Name of the target table. * **newColumns**: A record mapping column names to default value expressions (SQL or literal). * **Returns**: A promise that resolves once the columns are added. For Dart, the expression-based helper is `addColumnWithExpression(...)`. If you want to add columns by explicit Arrow schema instead, use `addColumnsWithSchema(...)`. **Example**: ```bash CLI theme={null} meshagent room dataset add-columns \ --room myroom \ --table users \ --columns "isActive bool, createdAt timestamp" ``` ```python Python theme={null} await room.datasets.add_columns( table="users", new_columns={ "isActive": "true", "createdAt": "CURRENT_TIMESTAMP", } ) ``` ```javascript NodeJs theme={null} await room.datasets.addColumns({ table: "users", newColumns: { isActive: "true", createdAt: "CURRENT_TIMESTAMP", }, }); ``` ```typescript TypeScript theme={null} await room.datasets.addColumns({ table: "users", newColumns: { isActive: "true", createdAt: "CURRENT_TIMESTAMP", }, }); ``` ```dart Dart theme={null} await room.datasets.addColumnWithExpression( table: "users", newColumns: { "isActive": "true", "createdAt": "CURRENT_TIMESTAMP", }, ); ``` ```dotnet C# theme={null} await room.Datasets.AddColumns( "users", new Dictionary { ["isActive"] = "true", ["createdAt"] = "CURRENT_TIMESTAMP", } ); ``` ### `drop_columns(...)` * **Description**: Drops (removes) one or more columns from an existing table. * **Parameters**: * **table**: Name of the target table. * **columns**: An array of column names to remove. * **Returns**: A promise that resolves once the columns are dropped. **Example**: ```bash CLI theme={null} meshagent room dataset drop-columns \ --room myroom \ --table users \ --column deprecatedColumn1 \ --column deprecatedColumn2 ``` ```python Python theme={null} await room.datasets.drop_columns( table="users", columns=["deprecatedColumn1", "deprecatedColumn2"] ) ``` ```javascript NodeJs theme={null} await room.datasets.dropColumns({ table: "users", columns: ["deprecatedColumn1", "deprecatedColumn2"], }); ``` ```typescript TypeScript theme={null} await room.datasets.dropColumns({ table: "users", columns: ["deprecatedColumn1", "deprecatedColumn2"], }); ``` ```dart Dart theme={null} await room.datasets.dropColumns( table: "users", columns: ["deprecatedColumn1", "deprecatedColumn2"], ); ``` ```dotnet C# theme={null} await room.Datasets.DropColumns( "users", new List { "deprecatedColumn1", "deprecatedColumn2" } ); ``` ### `insert(table, records)` * **Description**: Inserts one or more new records into a table. * **Parameters**: * **table**: The name of the table to insert into. * **records**: An array of objects, each containing column-value pairs. * **Returns**: A promise that resolves once the records are inserted. **Example**: ```bash CLI theme={null} meshagent room dataset insert \ --room myroom \ --table users \ --json '[{"id":3,"username":"charlie","email":"charlie@example.com"},{"id":4,"username":"dana","email":"dana@example.com"}]' ``` ```python Python theme={null} await room.datasets.insert( table="users", records=[ { "id": 3, "username": "charlie", "email": "charlie@example.com" }, { "id": 4, "username": "dana", "email": "dana@example.com" }, ], ) ``` ```javascript NodeJs theme={null} await room.datasets.insert({ table: "users", records: [ { id: 3, username: "charlie", email: "charlie@example.com" }, { id: 4, username: "dana", email: "dana@example.com" }, ], }); ``` ```typescript TypeScript theme={null} await room.datasets.insert({ table: "users", records: [ { id: 3, username: "charlie", email: "charlie@example.com" }, { id: 4, username: "dana", email: "dana@example.com" }, ], }); ``` ```dart Dart theme={null} await room.datasets.insert( table: "users", records: [ { "id": 3, "username": "charlie", "email": "charlie@example.com" }, { "id": 4, "username": "dana", "email": "dana@example.com" }, ], ); ``` ```dotnet C# theme={null} await room.Datasets.Insert( "users", new List> { new() { ["id"] = 3, ["username"] = "charlie", ["email"] = "charlie@example.com" }, new() { ["id"] = 4, ["username"] = "dana", ["email"] = "dana@example.com" }, } ); ``` ### `update(table, where, ...)` * **Description**: Updates existing records in a table. * **Parameters**: * **table**: Name of the table to update. * **where**: A SQL `WHERE` clause specifying which records to update (e.g. `"id = 123"`). * **values**: A record of key-value pairs for direct assignment or expressions (e.g. `{ age: 30 }` or `{ age: new DatasetExpression("age + 1") }` in typed clients). * **Returns**: A promise that resolves once the update is complete. **Example**: ```bash CLI theme={null} meshagent room dataset update \ --room myroom \ --table users \ --where "id = 3" \ --values-json '{"email":"newcharlie@example.com","loginCount":{"expression":"loginCount + 1"}}' ``` ```python Python theme={null} await room.datasets.update( table="users", where="id = 3", values={ "email": "newcharlie@example.com", "loginCount": DatasetExpression("loginCount + 1"), }, ) ``` ```javascript NodeJs theme={null} await room.datasets.update({ table: "users", where: "id = 3", values: { email: "newcharlie@example.com", loginCount: new DatasetExpression("loginCount + 1"), }, }); ``` ```typescript TypeScript theme={null} await room.datasets.update({ table: "users", where: "id = 3", values: { email: "newcharlie@example.com", loginCount: new DatasetExpression("loginCount + 1"), }, }); ``` ```dart Dart theme={null} await room.datasets.update( table: "users", where: "id = 3", values: { "email": "newcharlie@example.com", "loginCount": DatasetExpression("loginCount + 1"), }, ); ``` ```dotnet C# theme={null} await room.Datasets.Update( "users", "id = 3", values: new Dictionary { ["email"] = "newcharlie@example.com", ["loginCount"] = new DatasetExpression("loginCount + 1") } ); ``` ### `delete(table, where)` * **Description**: Deletes records from a table that match a specified condition. * **Parameters**: * **table**: The target table. * **where**: A SQL `WHERE` clause for filtering which records to delete. * **Returns**: A promise that resolves once the records are deleted. **Example**: ```bash CLI theme={null} meshagent room dataset delete \ --room myroom \ --table users \ --where "id = 4" ``` ```python Python theme={null} await room.datasets.delete( table="users", where="id = 4" ) ``` ```javascript NodeJs theme={null} await room.datasets.delete({ table: "users", where: "id = 4", }); ``` ```typescript TypeScript theme={null} await room.datasets.delete({ table: "users", where: "id = 4", }); ``` ```dart Dart theme={null} await room.datasets.delete( table: "users", where: "id = 4", ); ``` ```dotnet C# theme={null} await room.Datasets.Delete( "users", "id = 4" ); ``` ### `merge(table, records, ...)` * **Description**: Performs an **upsert** (update/insert) by merging incoming records into an existing table. Records matching the `on` column are updated; otherwise, new rows are inserted. * **Parameters**: * **table**: The target table. * **on**: The column name used to match existing records. * **records**: The record(s) to merge/upsert. * **Returns**: A promise that resolves once the operation is complete. **Example**: ```bash CLI theme={null} meshagent room dataset merge \ --room myroom \ --table users \ --on id \ --json '[{"id":1,"username":"alice","email":"alice_new@example.com"},{"id":5,"username":"eric","email":"eric@example.com"}]' ``` ```python Python theme={null} await room.datasets.merge( table="users", on="id", records=[ { "id": 1, "username": "alice", "email": "alice_new@example.com" }, { "id": 5, "username": "eric", "email": "eric@example.com" }, ], ) ``` ```javascript NodeJs theme={null} await room.datasets.merge({ table: "users", on: "id", records: [ { id: 1, username: "alice", email: "alice_new@example.com" }, { id: 5, username: "eric", email: "eric@example.com" }, ], }); ``` ```typescript TypeScript theme={null} await room.datasets.merge({ table: "users", on: "id", records: [ { id: 1, username: "alice", email: "alice_new@example.com" }, { id: 5, username: "eric", email: "eric@example.com" }, ], }); ``` ```dart Dart theme={null} await room.datasets.merge( table: "users", on: "id", records: [ { "id": 1, "username": "alice", "email": "alice_new@example.com" }, { "id": 5, "username": "eric", "email": "eric@example.com" }, ], ); ``` ```dotnet C# theme={null} await room.Datasets.Merge( "users", "id", new List> { new() { ["id"] = 1, ["username"] = "alice", ["email"] = "alice_new@example.com" }, new() { ["id"] = 5, ["username"] = "eric", ["email"] = "eric@example.com" }, } ); ``` ### `search(table, ...)` * **Description**: Searches for records in a table. This can be used for plain text search, vector similarity search, or simple SQL filtering. * **Parameters**: * **table**: The target table name. * **text**: An optional search string (if using full-text indexes). * **vector**: An optional numeric array for vector-based similarity queries. * **where**: SQL `WHERE` clause string or an object representing key-value equals conditions. * **offset**: Optional offset for pagination in Python and Dart. * **limit**: Maximum number of matching records to return. * **select**: An array of column names to be returned. * **Returns**: Python returns a `pyarrow.Table`. JavaScript, TypeScript, Dart, and .NET return arrays/lists of matching records. **Example**: ```bash CLI theme={null} meshagent room dataset search \ --room myroom \ --table users \ --where-json '{"username":"alice"}' \ --limit 1 ``` ```python Python theme={null} results = await room.datasets.search( table="users", where={ "username": "alice" }, limit=1 ) print(results.to_pylist()) # [{"id": 1, "username": "alice", "email": "alice@example.com"}] ``` ```javascript NodeJs theme={null} const results = await room.datasets.search({ table: "users", where: { username: "alice" }, limit: 1, }); console.log(results); // [{ id: 1, username: "alice", email: "alice@example.com" }] ``` ```typescript TypeScript theme={null} const results = await room.datasets.search({ table: "users", where: { username: "alice" }, limit: 1, }); console.log(results); // [{ id: 1, username: "alice", email: "alice@example.com" }] ``` ```dart Dart theme={null} final results = await room.datasets.search( table: "users", where: {"username": "alice"}, limit: 1, ); print(results); // [{"id": 1, "username": "alice", "email": "alice@example.com"}] ``` ```dotnet C# theme={null} var results = await room.Datasets.Search( "users", where: new Dictionary { ["username"] = "alice" }, limit: 1 ); Console.WriteLine(results); // [{ "id": 1, "username": "alice", "email": "alice@example.com" }] ``` ### `optimize(table, ...)` * **Description**: Optimizes a table (e.g., compacts its storage or rebuilds indexes if required). * **Parameters**: * **table**: Name of the table to optimize. * **config**: Optional optimization configuration using Lance option names, including `compact_files`, `optimize_indices`, `cleanup_old_versions`, `target_rows_per_fragment`, `max_rows_per_group`, `max_bytes_per_file`, `materialize_deletions`, `materialize_deletions_threshold`, `defer_index_remap`, `num_threads`, `batch_size`, `compaction_mode`, `binary_copy_read_batch_bytes`, `num_indices_to_merge`, `index_names`, `retrain`, `older_than_seconds`, `retain_versions`, `delete_unverified`, `error_if_tagged_old_versions`, and `delete_rate_limit`. * **Returns**: Optimization result details for compaction, index optimization, and cleanup. **Example**: ```bash CLI theme={null} meshagent room dataset optimize \ --room myroom \ --table users ``` ```python Python theme={null} await room.datasets.optimize(table="users") ``` ```javascript NodeJs theme={null} await room.datasets.optimize("users"); ``` ```typescript TypeScript theme={null} await room.datasets.optimize("users"); ``` ```dart Dart theme={null} await room.datasets.optimize(table: "users"); ``` ```dotnet C# theme={null} await room.Datasets.Optimize("users"); ``` ### `stats(table, ...)` * **Description**: Returns Lance dataset and data statistics for a table. * **Parameters**: * **table**: Name of the table. * **max\_rows\_per\_group**: Optional row-group threshold used by Lance dataset stats. * **Returns**: Parsed `dataset` and `data` statistics. **Example**: ```bash CLI theme={null} meshagent room dataset stats \ --room myroom \ --table users meshagent room dataset stats \ --room myroom \ --table users \ --output json ``` ```python Python theme={null} stats = await room.datasets.stats(table="users") ``` ```typescript TypeScript theme={null} const stats = await room.datasets.stats({ table: "users" }); ``` ```dart Dart theme={null} final stats = await room.datasets.stats("users"); ``` ### `create_index(...)` * **Description**: Creates a Lance index on a dataset table. * **Parameters**: * **table**: The target table name. * **config**: Index configuration. Uses Lance option names such as `column`, `index_type`, `name`, `replace`, `metric`, `num_partitions`, `num_sub_vectors`, `target_partition_size`, `filter_nan`, `train`, `fragment_ids`, `index_uuid`, `skip_transpose`, `num_bits`, `index_file_version`, `max_level`, `m`, `ef_construction`, `with_position`, `memory_limit`, `num_workers`, `skip_merge`, `base_tokenizer`, `language`, `max_token_length`, `lower_case`, `stem`, `remove_stop_words`, `custom_stop_words`, and `ascii_folding`. * **Returns**: A promise that resolves once the index is created. Supported `index_type` values include vector indexes (`IVF_PQ`, `IVF_HNSW_PQ`, `IVF_HNSW_SQ`, `IVF_RQ`) and scalar/text indexes (`BTREE`, `BITMAP`, `LABEL_LIST`, `NGRAM`, `ZONEMAP`, `INVERTED`, `FTS`, `BLOOMFILTER`, `RTREE`). **Example**: ```bash CLI theme={null} meshagent room dataset index-create \ --room myroom \ --table documents \ --column embedding \ --index-type IVF_PQ \ --num-partitions 32 \ --num-sub-vectors 8 ``` ```python Python theme={null} from meshagent.api import DatasetIndexConfig await room.datasets.create_index( table="documents", config=DatasetIndexConfig( column="embedding", index_type="IVF_PQ", num_partitions=32, num_sub_vectors=8, ), ) ``` ```javascript NodeJs theme={null} await room.datasets.createIndex({ table: "documents", config: { column: "embedding", index_type: "IVF_PQ", num_partitions: 32, num_sub_vectors: 8, }, }); ``` ```typescript TypeScript theme={null} await room.datasets.createIndex({ table: "documents", config: { column: "embedding", index_type: "IVF_PQ", num_partitions: 32, num_sub_vectors: 8, }, }); ``` ```dart Dart theme={null} await room.datasets.createIndex( table: "documents", config: const DatasetIndexConfig( column: "embedding", indexType: "IVF_PQ", numPartitions: 32, numSubVectors: 8, ), ); ``` ```dotnet C# theme={null} await room.Datasets.CreateIndex( "documents", new DatasetIndexConfig { Column = "embedding", IndexType = "IVF_PQ", NumPartitions = 32, NumSubVectors = 8, } ); ``` ### `drop_index(...)` * **Description**: Drop an index by name. * **Parameters**: * **table**: Table name. * **name**: Index name to drop. * **Returns**: `None`. * **Availability**: Python, JavaScript/TypeScript, Dart, and .NET expose helpers today. ```bash CLI theme={null} meshagent room dataset index-drop \ --room myroom \ --table users \ --name email_idx ``` ```python Python theme={null} await room.datasets.drop_index(table="users", name="email_idx") ``` ```typescript TypeScript theme={null} await room.datasets.dropIndex({ table: "users", name: "email_idx", }); ``` ```dart Dart theme={null} await room.datasets.dropIndex( table: "users", name: "email_idx", ); ``` ```dotnet C# theme={null} await room.Datasets.DropIndex("users", "email_idx"); ``` ### `list_indexes(table)` * **Description**: Lists the indexes currently defined on a table. * **Parameters**: * **table**: The name of the table for which to list indexes. * **Returns**: A list of index entries. Entries include `name`, `columns`, `type`, `fields`, `type_url`, `num_rows_indexed`, `num_segments`, `total_size_bytes`, `details`, and `statistics`. **Example**: ```bash CLI theme={null} meshagent room dataset index \ --room myroom \ --table users ``` ```python Python theme={null} indexes = await room.datasets.list_indexes(table="users") print(indexes) # Example output: # [TableIndex(name="email_idx", columns=["email"], type="scalar")] ``` ```javascript NodeJs theme={null} const indexes = await room.datasets.listIndexes({ table: "users" }); console.log(indexes); // Example output: // [{ name: "email_idx", columns: ["email"], type: "scalar" }] ``` ```typescript TypeScript theme={null} const indexes = await room.datasets.listIndexes({ table: "users" }); console.log(indexes); // Example output: // [{ name: "email_idx", columns: ["email"], type: "scalar" }] ``` ```dart Dart theme={null} final indexes = await room.datasets.listIndexes("users"); print(indexes); // Example output: // [TableIndex(name: "email_idx", columns: ["email"], type: "scalar")] ``` ```dotnet C# theme={null} var indexes = await room.Datasets.ListIndexes("users"); Console.WriteLine(indexes); // Example output: // [{ "name": "email_idx", "columns": ["email"], "type": "scalar" }] ``` ### `list_versions(table)` * **Description**: List historical versions of a table. Reads can target a specific `version` directly, and `restore` creates a new head version from an older snapshot. * **Methods**: * `list_versions(table, branch=None)` → list of versions (`version`, `timestamp`, `metadata`) for the selected branch. * `search(table, branch=None, version=None)` → read a branch head or a specific historical version without any checkout step. * `restore(table, version, branch=None)` → restore a table branch to a prior version by creating a new head commit. * **Availability**: Python exposes `list_versions`, `search(..., version=...)`, `restore`, and dataset branch operations. TypeScript exposes `listVersions`, `restore`, and branch helpers. .NET exposes `ListVersions` and `Restore`. Dart currently exposes `listVersions`. ```bash CLI theme={null} meshagent room dataset version \ --room myroom \ --table users ``` ```python Python theme={null} versions = await room.datasets.list_versions(table="users") await room.datasets.restore(table="users", version=versions[-1].version) ``` ```dart Dart theme={null} final versions = await room.datasets.listVersions("users"); for (final version in versions) { print("${version.version} ${version.timestamp}"); } ``` ### `list_branches()` * **Description**: List, create, and delete dataset branches for a namespace. Table reads and writes can then target a branch directly with `branch=...`. * **Methods**: * `list_branches()` → list available branches. * `create_branch(branch, from_branch=None)` → create a branch from the head of `main` or another branch. * `delete_branch(branch)` → delete a non-`main` branch. ```bash CLI theme={null} meshagent room dataset branch list --room myroom meshagent room dataset branch create --room myroom --branch exp --from-branch main ``` ```python Python theme={null} await room.datasets.create_branch(branch="exp") rows = await room.datasets.search(table="users", branch="exp") branches = await room.datasets.list_branches() ``` ```typescript TypeScript theme={null} await room.datasets.createBranch({ branch: "exp" }); const rows = await room.datasets.search({ table: "users", branch: "exp" }); const branches = await room.datasets.listBranches(); ``` ### Additional dataset operations The current SDKs and CLI include a few operations that are useful once tables move beyond basic CRUD: * `rename_table(...)` renames a table without copying its data. * `sql(...)`, `open_sql_query(...)`, `execute_sql(...)`, `sql_stream(...)`, and `execute_sql_statement(...)` run SQL against room datasets. * `watch_table(...)` streams table changes. * `count(...)` returns the matching row count for a table query. * `restore(...)` restores a table to a previous version. * `meshagent room dataset import` imports local data into a room table. * `meshagent room dataset sql` runs SQL from the CLI. ## Related guides * [Room API Overview](./overview) * [Memory API](./memory) # Developer Source: https://docs.meshagent.com/room_api/developer ## Overview The `DeveloperClient` is the Room API for structured developer logs. Use it to send logs into the Developer Console and subscribe to live logs from other participants in the room. ## CLI commands Start with the CLI help, then use the main live-log command: ```bash bash theme={null} meshagent room developer --help meshagent room developer --room myroom ``` ## Why use the Developer API? * Debug agents, tools, and services while a room is live. * Send structured log payloads instead of plain text so downstream tools can filter or render them. * Watch a room log stream from the CLI or SDK during development. ## How it works The Developer API is event-oriented. Producers call `log` (or convenience helpers such as `info`) to emit structured events, and consumers call `logs()` to subscribe to the live stream. ## Permissions and grants Developer logs are controlled by the `developer` grant on the participant token. In practice, `developer.logs` enables emitting and consuming developer-log events for the room. See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## Streaming Logs * **`logs()`** Opens a streamed subscription to developer logs for the room. Stop receiving logs by closing the stream or breaking iteration. ```bash CLI theme={null} meshagent room developer \ --room myroom ``` ```python Python theme={null} async for event in room.developer.logs(): print(f"[{event.type}] {event.data}") ``` ```javascript NodeJs theme={null} for await (const event of room.developer.logs()) { console.log(`[${event.type}]`, event.data); } ``` ```typescript TypeScript theme={null} for await (const event of room.developer.logs()) { console.log(`[${event.type}]`, event.data); } ``` ```dart Dart theme={null} await for (final event in room.developer.logs()) { print("[${event.type}] ${event.data}"); } ``` ```dotnet C# theme={null} await foreach (var log in room.Developer.Logs()) { Console.WriteLine($"[{log.Type}] {log.Data}"); } ``` ## API reference Use the methods below to emit structured developer logs or subscribe to the live room log stream. ### `log(type, data)` * **Description**: Emit a developer log event. * **Parameters**: * `type`: A log category string (for example, `"info"` or `"error"`). * `data`: A JSON-serializable payload with any extra fields. * **Returns**: `None` ```python Python theme={null} await room.developer.log(type="info", data={"message": "Hello from DeveloperClient!"}) ``` ```javascript NodeJs theme={null} await room.developer.log("info", { message: "Hello from DeveloperClient!" }); ``` ```typescript TypeScript theme={null} await room.developer.log("info", { message: "Hello from DeveloperClient!" }); ``` ```dart Dart theme={null} await room.developer.log("info", {"message": "Hello from DeveloperClient!"}); ``` ```dotnet C# theme={null} await room.Developer.Log("info", new Dictionary { ["message"] = "Hello from DeveloperClient!" }); ``` ### `log_nowait(type, data)` * **Description**: Fire-and-forget log emission without awaiting a response. * **Availability**: Python and .NET SDKs. * **Parameters**: * `type`: A log category string. * `data`: A JSON-serializable payload. * **Returns**: `None` ```python Python theme={null} room.developer.log_nowait(type="info", data={"message": "Log without await"}) ``` ```dotnet C# theme={null} room.Developer.LogNowait("info", new Dictionary { ["message"] = "Log without await" }); ``` ### `info(...)`, `warning(...)`, `error(...)` * **Description**: Convenience helpers for emitting structured logs with common severity labels. * **Availability**: Python and Dart SDKs. * **Parameters**: * `message`: Human-readable text. * `extra` *(optional)*: Additional fields to include with the log. * **Returns**: `None` ```python Python theme={null} room.developer.info("Background sync started", extra={"phase": "init"}) room.developer.warning("Retrying sync", extra={"attempt": 2}) room.developer.error("Sync failed", extra={"reason": "timeout"}) ``` ```dart Dart theme={null} await room.developer.info("Background sync started", extra: {"phase": "init"}); await room.developer.warning("Retrying sync", extra: {"attempt": 2}); await room.developer.error("Sync failed", extra: {"reason": "timeout"}); ``` ### `logs()` * **Description**: Open a streamed subscription to developer logs for the room. * **Parameters**: None. * **Returns**: A stream / async iterator of log events. ```bash CLI theme={null} meshagent room developer \ --room myroom ``` ```python Python theme={null} async for event in room.developer.logs(): print(event.type, event.data) ``` ```javascript NodeJs theme={null} for await (const event of room.developer.logs()) { console.log(event.type, event.data); } ``` ```typescript TypeScript theme={null} for await (const event of room.developer.logs()) { console.log(event.type, event.data); } ``` ```dart Dart theme={null} await for (final event in room.developer.logs()) { print(event.type); } ``` ```dotnet C# theme={null} await foreach (var log in room.Developer.Logs()) { Console.WriteLine(log.Type); } ``` ## Related guides * [Room API Overview](./overview) * [Observability Overview](../observability/overview) * [API Scopes](../rest_api/api_scopes) # Memory Source: https://docs.meshagent.com/room_api/memory ## Overview The `MemoryClient` is the Room API for room-scoped structured memory. Use it to build shared context that agents can ingest, query, and recall across workflows. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room memory --help meshagent room memory list --room myroom meshagent room memory create --room myroom --name customer-memory meshagent room memory recall --room myroom --name customer-memory --query "latest priorities" ``` ## Why use the Memory API? * Preserve structured knowledge across tasks instead of reconstructing it from chat history each time. * Ingest text, files, images, tables, and room storage content into a shared memory. * Recall the most relevant entities and relationships when building prompts or workflows. ## How it works A memory is a named dataset inside a room. You can create it, ingest data into it, inspect or query it directly, and use recall to retrieve relevant context. Some operations work at the entity and relationship level so you can maintain graph-like memory over time. > Current implementation: MeshAgent room memory is currently backed by [Lance Graph](https://github.com/lance-format/lance-graph), which stores entities and relationships in a graph-oriented format. Lance Graph is a Cypher-capable graph query engine. ## Permissions and grants The Memory API is controlled by the `memory` grant on the participant token. In practice: * `list` controls whether the participant can list memories * memory entry grants can be scoped by `name` and `namespace` * each entry can narrow permissions such as `create`, `drop`, `inspect`, `query`, `upsert`, `ingest`, `recall`, and `optimize` See [API Scopes](../rest_api/api_scopes), [Participant Tokens](../rest_api/participant_tokens), and [Service YAML](../services/deployment/deploy_services). ## API reference Use the methods below to create memories, ingest content, query or recall context, and maintain memory datasets over time. ### Python SDK signatures The examples below show common workflows. The Python SDK exposes these parameters directly on `room.memory`: ```python Python theme={null} await room.memory.list(namespace=None) await room.memory.create(name="customer-memory", namespace=None, overwrite=False, ignore_exists=False) await room.memory.drop(name="customer-memory", namespace=None, ignore_missing=False) details = await room.memory.inspect(name="customer-memory", namespace=None) rows = await room.memory.query(name="customer-memory", statement="MATCH (e) RETURN e LIMIT 10", namespace=None) await room.memory.upsert_table(name="customer-memory", table="facts", records=records, merge=True, namespace=None) await room.memory.upsert_nodes(name="customer-memory", records=nodes, merge=True, namespace=None) await room.memory.upsert_relationships(name="customer-memory", records=relationships, merge=True, namespace=None) result = await room.memory.ingest_text( name="customer-memory", text="ACME is planning a renewal review in Q3.", namespace=None, strategy="heuristic", llm_model=None, llm_temperature=None, ) result = await room.memory.ingest_image( name="customer-memory", caption=None, data=None, mime_type=None, source=None, annotations=None, namespace=None, strategy="heuristic", llm_model=None, llm_temperature=None, ) result = await room.memory.ingest_file( name="customer-memory", path=None, text=None, mime_type=None, namespace=None, strategy="heuristic", llm_model=None, llm_temperature=None, ) result = await room.memory.ingest_from_table( name="customer-memory", table="customer_notes", text_columns=None, table_namespace=None, limit=None, namespace=None, strategy="heuristic", llm_model=None, llm_temperature=None, ) result = await room.memory.ingest_from_storage( name="customer-memory", paths=["room://notes/acme.txt"], namespace=None, strategy="heuristic", llm_model=None, llm_temperature=None, ) result = await room.memory.recall( name="customer-memory", query="renewal timeline", namespace=None, limit=5, include_relationships=True, ) result = await room.memory.delete_entities(name="customer-memory", entity_ids=["acme"], namespace=None) result = await room.memory.delete_relationships(name="customer-memory", relationships=relationships, namespace=None) result = await room.memory.optimize(name="customer-memory", namespace=None, compact=True, cleanup=True) ``` ### `list(namespace=None)` * **Description**: List memory names in a namespace. ```bash CLI theme={null} meshagent room memory list \ --room myroom \ --namespace team \ --namespace support ``` ```python Python theme={null} memories = await room.memory.list(namespace=["team", "support"]) print(memories) ``` ```dart Dart theme={null} final memories = await room.memory.list(namespace: ["team", "support"]); print(memories); ``` ### `create(name, ...)` * **Description**: Create a memory. * **Parameters**: `name`, optional `namespace`, `overwrite`, `ignore_exists`. ```bash CLI theme={null} meshagent room memory create \ --room myroom \ --name customer-memory \ --namespace team \ --namespace support ``` ```python Python theme={null} await room.memory.create( name="customer-memory", namespace=["team", "support"], overwrite=False, ) ``` ```dart Dart theme={null} await room.memory.create( name: "customer-memory", namespace: ["team", "support"], overwrite: false, ); ``` ### `drop(name, ...)` * **Description**: Delete a memory. * **Parameters**: `name`, optional `namespace`, `ignore_missing`. ```bash CLI theme={null} meshagent room memory drop \ --room myroom \ --name customer-memory \ --namespace team \ --namespace support \ --ignore-missing ``` ```python Python theme={null} await room.memory.drop( name="customer-memory", namespace=["team", "support"], ignore_missing=True, ) ``` ```dart Dart theme={null} await room.memory.drop( name: "customer-memory", namespace: ["team", "support"], ignoreMissing: true, ); ``` ## More methods These examples use the Python `MemoryClient` API. The CLI, Dart SDK, TypeScript SDK, and .NET SDK expose matching room-memory operations for the same methods. ### `inspect(name, ...)` * **Description**: Return `MemoryDetails` including the memory path and dataset summaries. ```bash CLI theme={null} meshagent room memory inspect \ --room myroom \ --name customer-memory ``` ```python Python theme={null} details = await room.memory.inspect(name="customer-memory") print(details.path) for dataset in details.datasets: print(dataset.name, dataset.rows, dataset.columns) ``` ### `query(name, statement, ...)` * **Description**: Run a graph query against a memory and return rows. ```bash CLI theme={null} meshagent room memory query \ --room myroom \ --name customer-memory \ --statement 'MATCH (e) RETURN e.name LIMIT 10' ``` ```python Python theme={null} rows = await room.memory.query( name="customer-memory", statement="MATCH (e) RETURN e.name LIMIT 10", ) print(rows) ``` ### `upsert_table(name, table, records, ...)` * **Description**: Upsert arbitrary rows into a named memory dataset. ```bash CLI theme={null} meshagent room memory upsert-table \ --room myroom \ --name customer-memory \ --table facts \ --records-json '[{"entity_id":"acme","summary":"Renewal expected in Q3"}]' ``` ```python Python theme={null} await room.memory.upsert_table( name="customer-memory", table="facts", records=[ { "entity_id": "acme", "summary": "Renewal expected in Q3", } ], ) ``` ### `upsert_nodes(name, records, ...)` * **Description**: Upsert entity nodes using `MemoryEntityRecord`. ```bash CLI theme={null} meshagent room memory upsert-nodes \ --room myroom \ --name customer-memory \ --records-json '[{"entity_id":"acme","name":"ACME","entity_type":"company","context":"Enterprise customer"}]' ``` ```python Python theme={null} from meshagent.api.room_server_client import MemoryEntityRecord await room.memory.upsert_nodes( name="customer-memory", records=[ MemoryEntityRecord( entity_id="acme", name="ACME", entity_type="company", context="Enterprise customer", ) ], ) ``` ### `upsert_relationships(name, records, ...)` * **Description**: Upsert edges using `MemoryRelationshipRecord`. ```bash CLI theme={null} meshagent room memory upsert-relationships \ --room myroom \ --name customer-memory \ --records-json '[{"source_entity_id":"acme","target_entity_id":"renewal-q3","relationship_type":"HAS_MILESTONE","description":"Renewal target quarter"}]' ``` ```python Python theme={null} from meshagent.api.room_server_client import MemoryRelationshipRecord await room.memory.upsert_relationships( name="customer-memory", records=[ MemoryRelationshipRecord( source_entity_id="acme", target_entity_id="renewal-q3", relationship_type="HAS_MILESTONE", description="Renewal target quarter", ) ], ) ``` ### `ingest_text(name, text, ...)` * **Description**: Extract memory from inline text. ```bash CLI theme={null} meshagent room memory ingest-text \ --room myroom \ --name customer-memory \ --text 'ACME is planning a renewal review in Q3.' ``` ```python Python theme={null} result = await room.memory.ingest_text( name="customer-memory", text="ACME is planning a renewal review in Q3.", ) print(result.stats.entities, result.stats.relationships) ``` ### `ingest_image(name, data, ...)` * **Description**: Extract memory from an image and optional caption. ```bash CLI theme={null} meshagent room memory ingest-image \ --room myroom \ --name customer-memory \ --file ./whiteboard.png \ --caption 'Customer planning whiteboard' ``` ```python Python theme={null} with open("./whiteboard.png", "rb") as f: image_bytes = f.read() result = await room.memory.ingest_image( name="customer-memory", data=image_bytes, mime_type="image/png", caption="Customer planning whiteboard", ) print(result.stats) ``` ### `ingest_file(name, path, ...)` * **Description**: Extract memory from a file path visible to the room server, or from inline text. ```bash CLI theme={null} meshagent room memory ingest-file \ --room myroom \ --name customer-memory \ --path /data/acme-renewal.txt ``` ```python Python theme={null} result = await room.memory.ingest_file( name="customer-memory", path="/data/acme-renewal.txt", ) print(result.entity_ids) ``` ### `ingest_from_table(name, table, ...)` * **Description**: Extract memory from room dataset rows. ```bash CLI theme={null} meshagent room memory ingest-from-table \ --room myroom \ --name customer-memory \ --table customer_notes \ --text-column summary \ --text-column notes \ --limit 100 ``` ```python Python theme={null} result = await room.memory.ingest_from_table( name="customer-memory", table="customer_notes", text_columns=["summary", "notes"], limit=100, ) print(result.stats) ``` ### `ingest_from_storage(name, paths, ...)` * **Description**: Extract memory from one or more room storage paths. ```bash CLI theme={null} meshagent room memory ingest-from-storage \ --room myroom \ --name customer-memory \ --path room://notes/acme.txt \ --path room://notes/renewal.txt ``` ```python Python theme={null} result = await room.memory.ingest_from_storage( name="customer-memory", paths=["room://notes/acme.txt", "room://notes/renewal.txt"], ) print(result.stats) ``` ### `recall(name, query, ...)` * **Description**: Semantic recall using a natural-language query. ```bash CLI theme={null} meshagent room memory recall \ --room myroom \ --name customer-memory \ --query "What do we know about ACME's renewal timeline?" \ --limit 5 ``` ```python Python theme={null} result = await room.memory.recall( name="customer-memory", query="What do we know about ACME's renewal timeline?", limit=5, ) for item in result.items: print(item.entity_id, item.score) ``` ### `delete_entities(name, entity_ids, ...)` * **Description**: Remove entities and their related edges. ```bash CLI theme={null} meshagent room memory delete-entities \ --room myroom \ --name customer-memory \ --entity-id acme ``` ```python Python theme={null} result = await room.memory.delete_entities( name="customer-memory", entity_ids=["acme"], ) print(result.deleted_entities, result.deleted_relationships) ``` ### `delete_relationships(name, relationships, ...)` * **Description**: Remove relationships using `MemoryRelationshipSelector`. ```bash CLI theme={null} meshagent room memory delete-relationships \ --room myroom \ --name customer-memory \ --records-json '[{"source_entity_id":"acme","target_entity_id":"renewal-q3","relationship_type":"HAS_MILESTONE"}]' ``` ```python Python theme={null} from meshagent.api.room_server_client import MemoryRelationshipSelector result = await room.memory.delete_relationships( name="customer-memory", relationships=[ MemoryRelationshipSelector( source_entity_id="acme", target_entity_id="renewal-q3", relationship_type="HAS_MILESTONE", ) ], ) print(result.deleted_relationships) ``` ### `optimize(name, ...)` * **Description**: Compact and clean up memory datasets. ```bash CLI theme={null} meshagent room memory optimize \ --room myroom \ --name customer-memory \ --compact \ --cleanup ``` ```python Python theme={null} result = await room.memory.optimize( name="customer-memory", compact=True, cleanup=True, ) print(result) ``` ## Related guides * [Room API Overview](./overview) * [Datasets API](./datasets) * [Storage API](./storage) # Messaging Source: https://docs.meshagent.com/room_api/messaging ## Overview The `MessagingClient` is the Room API for participant-to-participant messages inside a room. Use it for direct JSON messages, room-wide broadcasts, and participant presence. If you need incremental or long-lived streaming, use **streaming toolkits** instead. Messaging stream APIs have been removed. If you need process-backed agent turn lifecycle such as `turn.start`, `turn.started`, `turn.ended`, steering, or interruption, see [Agent Turns](../agents/process/agent_turns). ## Why use the Messaging API? * Send structured JSON messages between room participants. * Broadcast announcements to everyone in a room. * Track which remote participants currently have messaging enabled. * Attach raw bytes to a normal message when needed. ## Core concepts ### Participant-based delivery Messaging targets `Participant` objects. That gives you one delivery model for users, agents, and services in the same room. ### Typed JSON payloads Each message has a `type` plus a JSON payload. Use that to build chat flows, control messages, coordination events, or lightweight app protocols. ### Optional binary attachments Messages may include an attachment for cases where you need to send bytes along with the JSON body. ### Streaming toolkits for streaming work Messaging no longer exposes stream open/accept/chunk/close APIs. If your use case needs incremental results or chunked transfer, use a streaming toolkit instead of `room.messaging`. ### Agent turns are a separate layer Process-backed agents use room messaging as transport, but the turn protocol is a separate runtime concept. Use `MessagingClient` when you want: * participant-to-participant messages * broadcasts * attachments * participant discovery Use [Agent Turns](../agents/process/agent_turns) when you want: * process-backed agent execution * turn lifecycle events * steering or interruption * thread-aware runtime control ## CLI commands Use `meshagent room messaging` when you want to inspect messaging-enabled participants or send one-off messages from the terminal: ```bash bash theme={null} meshagent room messaging --help meshagent room messaging list --room myroom meshagent room messaging send \ --room myroom \ --to-participant-id PARTICIPANT_ID \ --type chat \ --data '{"text":"Hello from the CLI"}' meshagent room messaging broadcast \ --room myroom \ --data '{"content":"Hello everyone"}' ``` ## Getting Started ```python Python theme={null} # Suppose you already have a RoomClient instance named `room` await room.messaging.enable() participant = room.messaging.get_participant_by_name("other-user") if participant is not None: await room.messaging.send_message( to=participant, type="chat", message={"text": "Hello from Python!"}, ) await room.messaging.broadcast_message( type="announcement", message={"content": "Hello everyone!"}, ) ``` ```ts TypeScript theme={null} // Suppose you already have a RoomClient instance named `room` await room.messaging.enable(); const participant = room.messaging.getParticipantByName("other-user"); if (participant) { await room.messaging.sendMessage({ to: participant, type: "chat", message: { text: "Hello from TypeScript!" }, }); } await room.messaging.broadcastMessage({ type: "announcement", message: { content: "Hello everyone!" }, }); ``` ```dart Dart theme={null} // Suppose you already have a RoomClient instance named `room` await room.messaging.enable(); final participant = room.messaging.remoteParticipants.isNotEmpty ? room.messaging.remoteParticipants.first : null; if (participant != null) { await room.messaging.sendMessage( to: participant, type: "chat", message: {"text": "Hello from Dart!"}, ); } await room.messaging.broadcastMessage( type: "announcement", message: {"content": "Hello everyone!"}, ); ``` ```dotnet C# theme={null} // Suppose you already have a RoomClient instance named `room` room.Messaging.Enable(); var participants = room.Messaging.GetParticipants(); if (participants.Count > 0) { await room.Messaging.SendMessage( to: participants[0], type: "chat", message: new Dictionary { ["text"] = "Hello from C#!" } ); } await room.Messaging.BroadcastMessage( type: "announcement", message: new Dictionary { ["content"] = "Hello everyone!" } ); ``` ## API Methods ### enable() Enables messaging for the current participant and starts participant discovery for the messaging subsystem. ```python Python theme={null} await room.messaging.enable() ``` ```ts TypeScript theme={null} await room.messaging.enable(); ``` ```dart Dart theme={null} await room.messaging.enable(); ``` ```dotnet C# theme={null} room.Messaging.Enable(); ``` ### disable() Disables messaging for the current participant. ```python Python theme={null} await room.messaging.disable() ``` ```ts TypeScript theme={null} await room.messaging.disable(); ``` ```dart Dart theme={null} await room.messaging.disable(); ``` ```dotnet C# theme={null} room.Messaging.Disable(); ``` ### sendMessage(...) Sends a direct message to one participant. ```python Python theme={null} await room.messaging.send_message( to=participant, type="chat", message={"text": "Hey!"}, attachment=b"\x01\x02\x03", ) ``` ```ts TypeScript theme={null} await room.messaging.sendMessage({ to: participant, type: "chat", message: { text: "Hey!" }, attachment: new Uint8Array([1, 2, 3]), }); ``` ```dart Dart theme={null} await room.messaging.sendMessage( to: participant, type: "chat", message: {"text": "Hey!"}, attachment: Uint8List.fromList([1, 2, 3]), ); ``` ```dotnet C# theme={null} await room.Messaging.SendMessage( to: participant, type: "chat", message: new Dictionary { ["text"] = "Hey!" }, attachment: new byte[] { 1, 2, 3 } ); ``` ### broadcastMessage(...) Broadcasts a message to every participant with messaging enabled. ```python Python theme={null} await room.messaging.broadcast_message( type="announcement", message={"title": "Maintenance", "content": "We will be down tonight."}, ) ``` ```ts TypeScript theme={null} await room.messaging.broadcastMessage({ type: "announcement", message: { title: "Maintenance", content: "We will be down tonight." }, }); ``` ```dart Dart theme={null} await room.messaging.broadcastMessage( type: "announcement", message: {"title": "Maintenance", "content": "We will be down tonight."}, ); ``` ```dotnet C# theme={null} await room.Messaging.BroadcastMessage( type: "announcement", message: new Dictionary { ["title"] = "Maintenance", ["content"] = "We will be down tonight." } ); ``` ### remoteParticipants / getParticipants() Returns the currently known remote participants with messaging enabled. ### getParticipant(id) / getParticipantByName(name) Looks up a known remote participant by id or by the `name` attribute. ## Notes * Messaging is intended for discrete participant messages, not incremental response streams. * For process-backed agent turn lifecycle, see [Agent Turns](../agents/process/agent_turns). * For streaming responses, chunked transfer, or bidirectional streaming, use a streaming toolkit. * Participant presence is only available after `enable()` completes. ## Related guides * [Room API Overview](./overview) * [Queues API](./queue) * [Sync API](./sync) # Overview Source: https://docs.meshagent.com/room_api/overview ## Overview Rooms are the runtime and collaboration boundary in MeshAgent. A room is where humans, agents, tools, services, files, queues, and shared documents come together around the same live context. Projects can contain many rooms, and each room can have its own participants, room-scoped services, and persisted state. The Room APIs are how you interact with that runtime. They give you the built-in primitives for messaging, storage, queues, documents, containers, and the other capabilities that make a room useful as an execution environment. ## CLI commands Use `meshagent rooms ...` to create and manage rooms in a project: ```bash bash theme={null} meshagent rooms --help meshagent setup meshagent rooms create myroom --if-not-exists meshagent rooms list meshagent rooms get --name myroom ``` Use `meshagent room ...` to work inside a specific room through the Room APIs. Start with `meshagent room --help`, then drill into the API you need: ```bash bash theme={null} meshagent room --help meshagent room connect --help meshagent room agents --help meshagent room queue --help meshagent room messaging --help meshagent room storage --help meshagent room dataset --help meshagent room memory --help meshagent room developer --help meshagent room container --help meshagent room sync --help meshagent room service --help ``` Use `meshagent room service ...` when you want to inspect or restart services that are already running in a room session. Use the project-level `meshagent service ...` command when you want to deploy, update, validate, or delete saved services. See [Service YAML](../services/deployment/deploy_services). ## How rooms fit into MeshAgent * A **project** groups many rooms. * A **room** is the live workspace for one stream of collaboration or execution. * A **session** is one active run of that room. When a room becomes active, MeshAgent starts a session for that room and starts any services that should run there. From that point on, participants can use the Room APIs and work over the same shared context. ## Room APIs Rooms expose a set of room-scoped APIs through the `RoomClient`: * **[Agents API](./agents) `AgentsClient`:** Call agents, invoke toolkits, and work with agent participants in the room. * **[Containers API](./containers) `ContainersClient`:** Run containers and inspect container activity in the room runtime. * **[Datasets API](./datasets) `DatasetsClient`:** Store and query structured room data in tables. * **[Memory API](./memory) `MemoryClient`:** Store and recall room-scoped memories for agents and workflows. * **[Developer API](./developer) `DeveloperClient`:** Send logs and inspect developer events for the room. * **[Messaging API](./messaging) `MessagingClient`:** Send and receive real-time messages between room participants. * **[Queues API](./queue) `QueuesClient`:** Send and receive queued work inside the room. * **[Services API](./services) `ServicesClient`:** List running services in the room and request a restart for one service. * **[Storage API](./storage) `StorageClient`:** Read and write files in room storage. * **[Sync API](./sync) `SyncClient`:** Work with shared documents and synchronized room state. ## Room lifecycle and sessions Rooms are durable named workspaces, but runtime activity happens in **sessions**. * A room session starts when the room becomes active. * During that session, participants connect, services run, and room activity is recorded. * When activity stops, the room shuts down automatically so compute is not kept running unnecessarily. Persisted data written through storage, dataset, or sync remains available according to that API's behavior. See [Sessions](./sessions) for the runtime implications. ## Using Room APIs in Deployed Services If you deploy a MeshAgent service and want that service to use the Room APIs, you must grant that access through the participant token `api` scope. Deployment alone does not automatically give a service access to storage, dataset, containers, or the other Room APIs. In practice, that means: * set the token `api` scope on service tokens injected through `container.environment[].token` * or set the endpoint `api` scope for the participant identity that joins through a MeshAgent endpoint Useful defaults: * `ApiScope.agent_default()` is the broad room-access preset for agents. The exact fields included vary slightly by SDK language, so check the helper in your SDK when you need the precise grant set. * `ApiScope.full()` is the broadest preset and adds admin-style access on top of the standard room APIs. Many Room APIs can also be narrowed further inside the scope: * **Storage / Sync**: path-based grants * **Dataset**: table-level grants * **Queues**: send/receive/list controls * **Messaging**: broadcast/list/send controls * **Containers**: pull/run/log controls For the full scope model and manifest fields, see [API Scopes](../rest_api/api_scopes), [Participant Tokens](../rest_api/participant_tokens), and [Service YAML](../services/deployment/deploy_services). If you are building your own application and minting participant tokens yourself, make sure the participant has both: * a room grant allowing it to join the room * an `api` scope granting access to the Room APIs it needs See [REST API overview](../rest_api/overview), [Participant Tokens](../rest_api/participant_tokens), and [API Scopes](../rest_api/api_scopes). ## Using RoomClient from SDKs All of the main SDKs expose a `RoomClient` with the same overall shape: * connect to a room * wait for readiness * use sub-clients such as agents, messaging, storage, dataset, queues, and sync * dispose the client when you are done The exact method names and property casing vary by language, but the underlying room model is the same. Use the SDK and language guides for the concrete examples: * **Python**: `RoomClient` in `meshagent.api` * **TypeScript / JavaScript**: `RoomClient` in `@meshagent/meshagent` * **Dart / Flutter**: `RoomClient` in `package:meshagent/meshagent.dart` * **.NET**: `RoomClient` in the MeshAgent .NET SDK # Queue Source: https://docs.meshagent.com/room_api/queue ## Overview The `QueuesClient` is the Room API for simple room-scoped work queues. Use it when one participant or service needs to hand off JSON work items to another participant or service asynchronously. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room queue --help meshagent room queue list --room myroom meshagent room queue size --room myroom --queue my-queue meshagent room queue send --room myroom --queue my-queue --json '{"payload":"Hello World!"}' meshagent room queue receive --room myroom --queue my-queue meshagent room queue send-mail --room myroom --queue my-queue --from support@example.com --subject "Support request" --body "Please review this." ``` ## Why use the Queues API? * Decouple producers and consumers when work should happen later. * Build lightweight background workflows without adding another queueing system. * Coordinate multi-agent jobs where one participant produces work and another consumes it. ## How it works A queue stores JSON messages until a consumer receives them. Senders and receivers can be different participants or services in the same room. SDKs can list, open, send, receive, drain, and close queues, while Python auto-creates queues during `send` or `receive` when `create=True`. ## Permissions and grants The Queues API is controlled by the `queues` grant on the participant token. In practice: * `list` controls queue discovery * `send` can be narrowed to specific queue names * `receive` can be narrowed separately to specific queue names See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## API reference Use the methods below to inspect queues, send JSON work items, and receive them from another participant or service in the same room. ### `list()` List the queues currently visible in the room. ```bash CLI theme={null} meshagent room queue list \ --room myroom ``` ```python Python theme={null} queues = await room.queues.list() ``` ```javascript NodeJs theme={null} const queues = await room.queues.list(); ``` ```typescript TypeScript theme={null} const queues = await room.queues.list(); ``` ```dart Dart theme={null} final queues = await room.queues.list(); ``` ```dotnet C# theme={null} var queues = await room.Queues.List(); ``` * **Returns**: An array of queue objects, each with a `name` and `size`. ### `open(name)` Create or reopen a queue explicitly. ```python Python theme={null} await room.queues.open(name="my-queue") ``` ```javascript NodeJs theme={null} await room.queues.open("my-queue"); ``` ```typescript TypeScript theme={null} await room.queues.open("my-queue"); ``` ```dart Dart theme={null} await room.queues.open("my-queue"); ``` ```dotnet C# theme={null} await room.Queues.Open("my-queue"); ``` * **Parameters**: * `name`: Queue name. ### `send(name, message, create=True)` Send one JSON message to a queue. ```bash CLI theme={null} meshagent room queue send \ --room myroom \ --queue my-queue \ --json '{"foo":"bar"}' ``` ```python Python theme={null} await room.queues.send(name="my-queue", message={"foo": "bar"}, create=True) ``` ```javascript NodeJs theme={null} await room.queues.send("my-queue", { foo: "bar" }, { create: true }); ``` ```typescript TypeScript theme={null} await room.queues.send("my-queue", { foo: "bar" }, { create: true }); ``` ```dart Dart theme={null} await room.queues.send("my-queue", {"foo": "bar"}, create: true); ``` ```dotnet C# theme={null} var message = new Dictionary { ["payload"] = "Hello World!" }; await room.Queues.Send("my-queue", message, create: true); ``` * **Parameters**: * `name`: Queue name. * `message`: JSON-serializable payload. * `create`: When `true`, create the queue if it does not already exist. ### Queue size from the CLI Use `meshagent room queue size` when you only need the current queue length: ```bash bash theme={null} meshagent room queue size \ --room myroom \ --queue my-queue ``` ### Send email-shaped work from the CLI Use `meshagent room queue send-mail` when a queue consumer expects an email payload instead of a generic JSON work item: ```bash bash theme={null} meshagent room queue send-mail \ --room myroom \ --queue my-queue \ --from support@example.com \ --subject "Support request" \ --body "Please review this." ``` When the queue consumer is a MeshAgent queue channel, the payload can include turn-oriented fields such as: * `prompt`: string or typed content items for the next turn * `content`: typed content items that should be passed through directly * `path`: explicit thread path for the work item * `model`, `instructions`, `tools`, `sender_name`: optional turn settings #### Structured agent payloads For queue-backed MeshAgent agents, `prompt` and `content` can carry typed content instead of a plain string. * Think of `prompt` as "text the agent should read". * Think of `content` as "input items the agent should receive". * Use `prompt` when you want a `room:///...` text file read from room storage and inlined into the turn as text before the turn starts. * Use `content` when you want a `room:///...` file passed through as a file item in the turn input instead of being converted into text. * `content` does not create or update room artifacts by itself. It only defines the turn input that the queue consumer receives. * `prompt` can be plain text, typed content, or typed content that includes `room:///...` files. You only need a room file when you want to pull existing room content into the prompt. * `path` can use UTC time tokens such as `{YYYY}`, `{MM}`, `{DD}`, `{HH}`, `{mm}`, and `{SECOND}`. Examples: 1. Plain text prompt ```bash theme={null} meshagent room queue send \ --room myroom \ --queue support-jobs \ --json '{"prompt":"Summarize the current support backlog and highlight urgent issues."}' ``` This sends plain prompt text. No room file is involved. 2. Prompt that reads a room file and turns it into text ```bash theme={null} meshagent room queue send \ --room myroom \ --queue support-jobs \ --json '{"path":"dataset://threads/support/{YYYY}/{MM}/{DD}/{HH}/{mm}/summary","prompt":[{"type":"file","url":"room:///prompts/support-summary.md"},{"type":"text","text":"Summarize the current support backlog and highlight urgent issues."}]}' ``` In this example, MeshAgent reads `room:///prompts/support-summary.md` from room storage and inserts that file's UTF-8 text into the turn before the agent runs. 3. Content that preserves the room file as a file input ```bash theme={null} meshagent room queue send \ --room myroom \ --queue support-jobs \ --json '{"content":[{"type":"file","url":"room:///docs/report.md"}]}' ``` In this example, MeshAgent keeps `room:///docs/report.md` as a file item in the turn input. It does not inline the file into prompt text, and it does not create a new room artifact. ### `receive(name, create=True, wait=True)` Receive one JSON message from a queue. ```bash CLI theme={null} meshagent room queue receive \ --room myroom \ --queue my-queue ``` ```python Python theme={null} message = await room.queues.receive(name="my-queue", create=True, wait=True) ``` ```javascript NodeJs theme={null} const message = await room.queues.receive("my-queue", { create: true, wait: true }); ``` ```typescript TypeScript theme={null} const message = await room.queues.receive("my-queue", { create: true, wait: true }); ``` ```dart Dart theme={null} final message = await room.queues.receive("my-queue", create: true, wait: true); ``` ```dotnet C# theme={null} var received = await room.Queues.Receive("my-queue", create: true, wait: true); ``` * **Parameters**: * `name`: Queue name. * `create`: When `true`, create the queue if it does not already exist. * `wait`: When `true`, wait until a message is available. * **Returns**: A JSON payload, or `null` if the queue is empty and `wait=False`. ### `drain(name)` Remove all messages from a queue. ```python Python theme={null} await room.queues.drain(name="my-queue") ``` ```javascript NodeJs theme={null} await room.queues.drain("my-queue"); ``` ```typescript TypeScript theme={null} await room.queues.drain("my-queue"); ``` ```dart Dart theme={null} await room.queues.drain("my-queue"); ``` ```dotnet C# theme={null} await room.Queues.Drain("my-queue"); ``` * **Parameters**: * `name`: Queue name. ### `close(name)` Close a queue so it stops accepting sends or receives until reopened. ```python Python theme={null} await room.queues.close(name="my-queue") ``` ```javascript NodeJs theme={null} await room.queues.close("my-queue"); ``` ```typescript TypeScript theme={null} await room.queues.close("my-queue"); ``` ```dart Dart theme={null} await room.queues.close("my-queue"); ``` ```dotnet C# theme={null} await room.Queues.Close("my-queue"); ``` * **Parameters**: * `name`: Queue name. ### `Queue` Queue objects returned by `list()` include: * `name`: Queue name. * `size`: Queue length at the time of retrieval. ## Related guides * [Room API Overview](./overview) * [Messaging API](./messaging) * [Service YAML](../services/deployment/deploy_services) # Services Source: https://docs.meshagent.com/room_api/services Inspect runtime state for services in a room and restart a running room service. ## Overview The `ServicesClient` is the Room API for inspecting the services that are currently running in a room session. Use it when you want to: * see which saved services are actually running in the active room * inspect runtime state such as container id, restart count, and last exit code * request a restart for a running room service without changing its saved deployment spec This page is about runtime control inside an active room. If you want to deploy, update, validate, or delete saved services, use [Service YAML](../services/deployment/deploy_services) and the project-level `meshagent service` command instead. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room service --help meshagent room service list --room myroom meshagent room service list --room myroom --output json meshagent room service describe --room myroom --name my-service meshagent room service restart --room myroom --name my-service ``` ## Why use the Services API? * check whether a deployed room or project service is actually running in the current session * inspect runtime state without leaving the room context * restart one managed room service while leaving the saved service definition alone ## How it works Saved services are deployed with the `meshagent service` command or generated through higher-level flows such as `meshagent process deploy`. Once a room session is active, those saved services become running workloads in the room runtime. The `ServicesClient` gives you visibility into that runtime layer: * `list()` returns the service specs visible in the room plus runtime state details from the room service controller * `restart()` asks MeshAgent to stop the current container for one service so it can come back up cleanly This is intentionally separate from service packaging and deployment. Deployment changes the saved configuration through `meshagent service`. The Room Services API tells you what is running right now. ## Permissions and grants Room service inspection and restart use the room `services` toolkit surfaced by the runtime. In practice, use the normal room connection path for operator tooling and deploy the service with the room/API access it needs. For the broader deployment permission model, see [API Scopes](../rest_api/api_scopes), [Participant Tokens](../rest_api/participant_tokens), and [Service YAML](../services/deployment/deploy_services). ## API reference ### `list()` * **Description**: List services plus runtime state details from the service controller. * **Returns**: `ListServicesResult` with: * `services`: the service specs visible in the room * `service_states`: runtime state keyed by service id Runtime state includes service state, container id, started time, restart count, last exit code, scheduled restart time, lifecycle events, and `status.ports`. Each `status.ports` entry is a `ServicePortRuntimeState`: | Field | Description | | ----------------- | ---------------------------------------------------------- | | `num` | Service port number, or `"*"` for an auto-assigned port. | | `liveness` | HTTP path MeshAgent checks for this port, when configured. | | `liveness_status` | `not_configured`, `not_ready`, or `ready`. | | `last_checked_at` | Unix timestamp for the most recent liveness check. | | `last_error` | Most recent liveness error, when the port is not ready. | The CLI table includes a `ports` column. Ports without a liveness path show `no liveness`; ports with a passing liveness check show `ready`; ports with a configured liveness path that is not passing show `not ready`. ```bash CLI theme={null} meshagent room service list \ --room myroom ``` ```python Python theme={null} result = await room.services.list() for service in result.services: state = result.service_states.get(service.id or "") print(service.metadata.name, state.state if state is not None else "unknown") ``` ```typescript TypeScript theme={null} const result = await room.services.list(); for (const service of result.services) { const state = service.id ? result.serviceStates[service.id] : undefined; console.log(service.metadata.name, state?.state ?? "unknown"); } ``` ```dart Dart theme={null} final result = await room.services.list(); for (final service in result.services) { final state = service.id == null ? null : result.serviceStates[service.id!]; print('${service.metadata.name}: ${state?.state ?? "unknown"}'); } ``` ### `restart(service_id)` / `restart({ serviceId })` * **Description**: Request a restart for one running room service. * **Parameters**: * `service_id` / `serviceId`: the room service id to restart * **Returns**: `None` Use this when the saved service spec is already correct and you only want MeshAgent to restart the running workload. ```bash CLI theme={null} meshagent room service restart \ --room myroom \ --name my-service ``` ```python Python theme={null} await room.services.restart(service_id="svc-1") ``` ```typescript TypeScript theme={null} await room.services.restart({ serviceId: "svc-1" }); ``` ```dart Dart theme={null} await room.services.restart(serviceId: "svc-1"); ``` ## Related guides * [Room API Overview](./overview) * [Sessions](./sessions) * [Service YAML](../services/deployment/deploy_services) * [Intro to Services](../services/intro) # Sessions Source: https://docs.meshagent.com/room_api/sessions Understand how room sessions start, what they contain, and what persists after they end. ## Overview A **session** is one active run of a room. The room is the named workspace. The session is the live runtime period during which participants connect, services run, activity is recorded, and the Room APIs are actively being used. ## CLI commands If you are debugging or trying to understand what happened in a room, start here: ```bash bash theme={null} meshagent session list meshagent session get SESSION_ID meshagent session traces SESSION_ID ``` Use `meshagent session list` to find recent sessions in the active project, then use `meshagent session get SESSION_ID` to inspect the recorded events for one specific run. Use `meshagent session traces SESSION_ID` to inspect trace spans for that run. You can also search traces by room or attributes: ```bash bash theme={null} meshagent session traces --room gettingstarted --min-duration 1000 meshagent session traces --room gettingstarted --attrs status=error ``` In [MeshAgent Studio](../interfaces/meshagent_studio), use **Active Sessions** and **Recent Sessions** to inspect sessions across rooms, and use the **Developer Console** inside a room for live logs, traces, metrics, and related runtime activity. ## Room vs session This distinction is important: * the **room** is the durable collaboration space inside a project * the **session** is the active runtime instance of that room That means a room can exist as a stable place for work even though the actual running state comes and goes over time. ## What happens when a session starts When a room becomes active: 1. MeshAgent starts a session for that room. 2. Participants can join and interact through the room APIs. 3. Room-scoped services start according to the room's saved configuration. 4. Project services that are available to the room also start running there. 5. Logs, traces, metrics, and events begin accumulating for that session. ## What happens when a session ends When room activity stops, MeshAgent shuts the room down automatically. That means active runtime behavior stops, including: * active participant connections * running room-scoped workloads tied to that session * ephemeral in-memory runtime state from that run What does **not** disappear depends on which room APIs you used. Data written to room storage, datasets, synchronized documents, or other persistent surfaces remains available according to that API's persistence model. Session history and telemetry remain available so you can inspect what happened during that run. ## Why sessions matter Understanding sessions helps with three common tasks: * **debugging**: inspect logs, traces, and events for one runtime period instead of mixing different runs together * **deployment reasoning**: understand when services start, restart, or stop relative to room activity * **data modeling**: distinguish between runtime state that exists only during a live session and data you intentionally persist through room APIs * **operational review**: understand what happened in a room before, during, and after a given piece of work Use [Observability](../observability/overview) when you want the broader telemetry model, and use the [REST API](../rest_api/overview) when you need to list or inspect sessions programmatically. # Storage Source: https://docs.meshagent.com/room_api/storage ## Overview The `StorageClient` is the Room API for room-scoped files and folders. Use it to store shared inputs, outputs, artifacts, and attachments that humans, agents, and services in the same room need to read or write. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room storage --help meshagent room storage ls --room myroom room:// meshagent room storage cp ./report.pdf room://artifacts/report.pdf --room myroom meshagent room storage get --room myroom room://artifacts/report.pdf ``` ## Why use the Storage API? * Share files between people, agents, and deployed services without wiring separate object storage access. * Store outputs such as reports, logs, generated media, or intermediate artifacts. * Download file contents directly or get a downloadable URL when you need to hand a file to another system. ## How it works Paths are relative to the room storage root. Use `upload` or `uploadStream` to write files, `download` or `downloadStream` to read them back, and `download_url` / `downloadUrl` when you need a fetchable URL for another system. The API also emits `file.updated`, `file.deleted`, and `file.moved` events so other participants can react to changes. ## Permissions and grants `upload` / `uploadStream` and `download` / `downloadStream` / `download_url` require a storage grant on the participant token for the target path. Storage grants are path-based, which lets you give a service access to only part of room storage. In the current server implementation, `list`, `exists`, `stat`, and `delete` are not gated by storage grants. Use [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services) for the full scope model. ## Events The storage system emits three types of events: * **`file.updated`**\ Triggered when a file is created or updated. Python and .NET handlers receive `path` and `participant_id`. JS/TS and Dart handlers receive a `FileUpdatedEvent` with `.path`. ```python Python theme={null} def on_file_updated(path: str, participant_id: str): print(f"File updated: {path} by {participant_id}") room.storage.on("file.updated", on_file_updated) ``` ```javascript NodeJs theme={null} function onFileUpdated(event) { console.log("File updated:", event.path); } room.storage.on("file.updated", onFileUpdated); ``` ```typescript TypeScript theme={null} function onFileUpdated(event: FileUpdatedEvent) { console.log("File updated:", event.path); } room.storage.on("file.updated", onFileUpdated); ``` ```dart Dart theme={null} void onFileUpdated(String path) { print("File updated: $path"); } room.listen((RoomEvent event) { if (event is FileUpdatedEvent) { onFileUpdated(event.path); } }); ``` ```dotnet C# theme={null} void OnFileUpdated(Dictionary data) { Console.WriteLine($"File updated: {data["path"]} by {data["participant_id"]}"); } room.Storage.On("file.updated", OnFileUpdated); ``` * **`file.deleted`**\ Triggered when a file is deleted. Python and .NET handlers receive `path` and `participant_id`. JS/TS and Dart handlers receive a `FileDeletedEvent` with `.path`. ```python Python theme={null} def on_file_deleted(path: str, participant_id: str): print(f"File deleted: {path} by {participant_id}") room.storage.on("file.deleted", on_file_deleted) ``` ```javascript NodeJs theme={null} function onFileDeleted(event) { console.log("File deleted:", event.path); } room.storage.on("file.deleted", onFileDeleted); ``` ```typescript TypeScript theme={null} function onFileDeleted(event: FileDeletedEvent) { console.log("File deleted:", event.path); } room.storage.on("file.deleted", onFileDeleted); ``` ```dart Dart theme={null} void onFileDeleted(String path) { print("File deleted: $path"); } room.listen((RoomEvent event) { if (event is FileDeletedEvent) { onFileDeleted(event.path); } }); ``` ```dotnet C# theme={null} void OnFileDeleted(Dictionary data) { Console.WriteLine($"File deleted: {data["path"]} by {data["participant_id"]}"); } room.Storage.On("file.deleted", OnFileDeleted); ``` * **`file.moved`** Triggered when a file or folder is moved. Python and .NET handlers receive `source_path`, `destination_path`, and `participant_id`. JS/TS and Dart handlers receive a `FileMovedEvent` with `.sourcePath` and `.destinationPath`. ```python Python theme={null} def on_file_moved(source_path: str, destination_path: str, participant_id: str): print(f"File moved: {source_path} -> {destination_path} by {participant_id}") room.storage.on("file.moved", on_file_moved) ``` ```javascript NodeJs theme={null} function onFileMoved(event) { console.log("File moved:", event.sourcePath, "->", event.destinationPath); } room.storage.on("file.moved", onFileMoved); ``` ```typescript TypeScript theme={null} function onFileMoved(event: FileMovedEvent) { console.log("File moved:", event.sourcePath, "->", event.destinationPath); } room.storage.on("file.moved", onFileMoved); ``` ```dart Dart theme={null} void onFileMoved(String sourcePath, String destinationPath) { print("File moved: $sourcePath -> $destinationPath"); } room.listen((RoomEvent event) { if (event is FileMovedEvent) { onFileMoved(event.sourcePath, event.destinationPath); } }); ``` ```dotnet C# theme={null} void OnFileMoved(Dictionary data) { Console.WriteLine($"File moved: {data["source_path"]} -> {data["destination_path"]} by {data["participant_id"]}"); } room.Storage.On("file.moved", OnFileMoved); ``` You can remove an event handler with: ```python Python theme={null} room.storage.off("file.updated", on_file_updated) room.storage.off("file.deleted", on_file_deleted) room.storage.off("file.moved", on_file_moved) ``` ```javascript NodeJs theme={null} room.storage.off("file.updated", onFileUpdated); room.storage.off("file.deleted", onFileDeleted); room.storage.off("file.moved", onFileMoved); ``` ```typescript TypeScript theme={null} room.storage.off("file.updated", onFileUpdated); room.storage.off("file.deleted", onFileDeleted); room.storage.off("file.moved", onFileMoved); ``` ```dart Dart theme={null} room.listen((RoomEvent event) { // Remove event handlers as needed if (event is FileUpdatedEvent) { // Remove handler logic } if (event is FileDeletedEvent) { // Remove handler logic } }); ``` ```dotnet C# theme={null} room.Storage.Off("file.updated", OnFileUpdated); room.Storage.Off("file.deleted", OnFileDeleted); room.Storage.Off("file.moved", OnFileMoved); ``` ## API reference Use the methods below to inspect room storage, upload and download files, and clean up stored artifacts. Each method is asynchronous, so you should `await` the call. ### `exists(path)` **Description** Checks if a file or folder exists at the given path. **Parameters** * `path` *(str)*: The path to check. **Returns** * *(bool)*: `True` if the file or folder exists; `False` otherwise. **Example**: ```bash CLI theme={null} meshagent room storage exists \ --room myroom \ room://folder/data.json ``` ```python Python theme={null} if await room.storage.exists(path="folder/data.json"): print("Data file exists!") else: print("Data file does not exist.") ``` ```javascript NodeJs theme={null} if (await room.storage.exists("folder/data.json")) { console.log("Data file exists!"); } else { console.log("Data file does not exist."); } ``` ```typescript TypeScript theme={null} if (await room.storage.exists("folder/data.json")) { console.log("Data file exists!"); } else { console.log("Data file does not exist."); } ``` ```dart Dart theme={null} if (await room.storage.exists("folder/data.json")) { print("Data file exists!"); } else { print("Data file does not exist."); } ``` ```dotnet C# theme={null} if (await room.Storage.Exists("folder/data.json")) { Console.WriteLine("Data file exists!"); } else { Console.WriteLine("Data file does not exist."); } ``` ### `stat(path)` **Description**\ Fetch basic metadata (exists, folder flag, created/updated timestamps) for a file or folder. **Parameters** * `path` *(str)*: The path to inspect. **Returns** * `StorageEntry | None`: Entry when present; `None` if not found. The server returns `name`, `is_folder`, `created_at`, and `updated_at` fields. SDKs that expose `stat` parse timestamps into native datetime types. **Example**: ```python Python theme={null} entry = await room.storage.stat(path="folder/data.json") if entry: print(entry.name, entry.is_folder, entry.created_at, entry.updated_at) ``` ```javascript NodeJs theme={null} const entry = await room.storage.stat("folder/data.json"); if (entry) { console.log(entry.name, entry.isFolder, entry.createdAt, entry.updatedAt); } ``` ```typescript TypeScript theme={null} const entry = await room.storage.stat("folder/data.json"); if (entry) { console.log(entry.name, entry.isFolder, entry.createdAt, entry.updatedAt); } ``` ```dart Dart theme={null} final entry = await room.storage.stat("folder/data.json"); if (entry != null) { print("${entry.name} ${entry.isFolder} ${entry.createdAt} ${entry.updatedAt}"); } ``` * **Availability**: Python, JavaScript/TypeScript, and Dart SDKs expose `stat`. ### `upload(path, data, overwrite=False, name=None, mime_type=None)` **Description**\ Uploads a complete file payload in one call. Use this when you already have the bytes in memory. **Parameters** * `path` *(str)*: The destination file path. * `data` *(bytes / Uint8Array / byte\[])*: The file contents to write. * `overwrite` *(bool, optional)*: Whether to replace an existing file at that path. * `name` *(optional)*: File-name metadata for the stored object. Defaults to the basename of `path` in SDKs that infer it. * `mime_type` / `mimeType` *(optional)*: MIME type metadata. Python, JavaScript/TypeScript, and Dart infer a MIME type from the file name when omitted. **Returns** * `None` **Example**: ```python Python theme={null} data_to_write = b"Hello, Storage!" await room.storage.upload( path="files/new.txt", data=data_to_write, overwrite=True, ) ``` ```javascript NodeJs theme={null} const dataToWrite = new TextEncoder().encode("Hello, Storage!"); await room.storage.upload("files/new.txt", dataToWrite, { overwrite: true, }); ``` ```typescript TypeScript theme={null} const dataToWrite = new TextEncoder().encode("Hello, Storage!"); await room.storage.upload("files/new.txt", dataToWrite, { overwrite: true, }); ``` ```dart Dart theme={null} final dataToWrite = Uint8List.fromList(utf8.encode("Hello, Storage!")); await room.storage.upload( "files/new.txt", dataToWrite, overwrite: true, ); ``` ```dotnet C# theme={null} var dataToWrite = Encoding.UTF8.GetBytes("Hello, Storage!"); await room.Storage.Upload( "files/new.txt", dataToWrite, overwrite: true ); ``` ### `upload_stream(path, chunks, overwrite=False, chunk_size=65536, size=None, name=None, mime_type=None)` **Description**\ Streams file contents chunk-by-chunk. Use this when you do not want to materialize the whole file in memory at once. **Parameters** * `path` *(str)*: The destination file path. * `chunks`: An async iterable / stream / `IAsyncEnumerable` of file chunks. * `overwrite` *(optional)*: Replace an existing file at that path. * `size` *(optional)*: Total byte size when you already know it. * `chunk_size` / `chunkSize` *(optional)*: Pull size for streamed uploads. * `name` *(optional)*: File-name metadata for the upload stream. Defaults to the basename of `path` in SDKs that infer it. * `mime_type` / `mimeType` *(optional)*: MIME type metadata for the upload stream. Python, JavaScript/TypeScript, and Dart infer a MIME type from the file name when omitted. **Returns** * `None` **Example**: ```python Python theme={null} async def chunks(): yield b"Hello, " yield b"world!" await room.storage.upload_stream( path="logs/output.txt", chunks=chunks(), overwrite=True, size=13, ) ``` ```javascript NodeJs theme={null} async function* chunks() { yield new TextEncoder().encode("Hello, "); yield new TextEncoder().encode("world!"); } await room.storage.uploadStream("logs/output.txt", chunks(), { overwrite: true, size: 13, }); ``` ```typescript TypeScript theme={null} async function* chunks(): AsyncGenerator { yield new TextEncoder().encode("Hello, "); yield new TextEncoder().encode("world!"); } await room.storage.uploadStream("logs/output.txt", chunks(), { overwrite: true, size: 13, }); ``` ```dart Dart theme={null} Stream chunks() async* { yield Uint8List.fromList(utf8.encode("Hello, ")); yield Uint8List.fromList(utf8.encode("world!")); } await room.storage.uploadStream( "logs/output.txt", chunks(), overwrite: true, size: 13, ); ``` ```dotnet C# theme={null} async IAsyncEnumerable Chunks() { yield return Encoding.UTF8.GetBytes("Hello, "); yield return Encoding.UTF8.GetBytes("world!"); await Task.CompletedTask; } await room.Storage.UploadStream( "logs/output.txt", Chunks(), overwrite: true, size: 13 ); ``` ### `download_stream(path, chunk_size=65536)` **Description**\ Streams a file back as metadata plus data chunks. Use this for larger files or when you want to process the response incrementally. **Parameters** * `path` *(str)*: The file path to download. * `chunk_size` / `chunkSize` *(optional)*: Requested chunk size for streamed downloads. **Returns** * A stream / async iterator of binary chunks. The first chunk carries metadata such as file name, MIME type, and size. **Example**: ```python Python theme={null} async for chunk in room.storage.download_stream(path="files/report.pdf"): if chunk.headers["kind"] == "start": print(chunk.headers["name"], chunk.headers["size"]) continue print(f"Received {len(chunk.data)} bytes") ``` ```javascript NodeJs theme={null} const stream = await room.storage.downloadStream("files/report.pdf"); for await (const chunk of stream) { if (chunk.headers.kind === "start") { console.log(chunk.headers.name, chunk.headers.size); continue; } console.log(`Received ${chunk.data.length} bytes`); } ``` ```typescript TypeScript theme={null} const stream = await room.storage.downloadStream("files/report.pdf"); for await (const chunk of stream) { if (chunk.headers.kind === "start") { console.log(chunk.headers.name, chunk.headers.size); continue; } console.log(`Received ${chunk.data.length} bytes`); } ``` ```dart Dart theme={null} final stream = await room.storage.downloadStream("files/report.pdf"); await for (final chunk in stream) { if (chunk.headers["kind"] == "start") { print("${chunk.headers["name"]} ${chunk.headers["size"]}"); continue; } print("Received ${chunk.data.length} bytes"); } ``` ```dotnet C# theme={null} await foreach (var chunk in room.Storage.DownloadStream("files/report.pdf")) { if ((chunk.Headers["kind"] as string) == "start") { Console.WriteLine($"{chunk.Headers["name"]} {chunk.Headers["size"]}"); continue; } Console.WriteLine($"Received {chunk.Data.Length} bytes"); } ``` ### `download(path)` **Description**\ Retrieves the content of a file from the remote storage. This loads the entire file into memory; use `download_url` for large files or streaming. **Parameters** * `path` *(str)*: The file path to download. **Returns** * *File-like Response*: Contains the file's raw data, typically accessible through a `.data` property. **Example**: ```bash CLI theme={null} meshagent room storage cp \ room://files/data.bin \ ./data.bin \ --room myroom ``` ```python Python theme={null} file_response = await room.storage.download(path="files/data.bin") print(file_response.data) # raw bytes ``` ```javascript NodeJs theme={null} const fileResponse = await room.storage.download("files/data.bin"); console.log(fileResponse.data); // raw bytes ``` ```typescript TypeScript theme={null} const fileResponse = await room.storage.download("files/data.bin"); console.log(fileResponse.data); // raw bytes ``` ```dart Dart theme={null} final fileResponse = await room.storage.download("files/data.bin"); print(fileResponse.data); // raw bytes ``` ```dotnet C# theme={null} var fileResponse = await room.Storage.Download("files/data.bin"); Console.WriteLine(fileResponse.Data); // raw bytes ``` ### `download_url(path)` **Description**\ Requests a downloadable URL for the specified file path, which can be used to fetch the file directly (e.g., via HTTP). The exact protocol or format of the returned URL may vary, and may be a signed URL if the backing storage provider supports it. **Parameters** * `path` *(str)*: The file path to retrieve a download URL for. **Returns** * *(str)*: A URL string you can fetch with your own HTTP or other suitable client. **Example**: ```python Python theme={null} url = await room.storage.download_url(path="files/report.pdf") print("Download the file from:", url) ``` ```javascript NodeJs theme={null} const url = await room.storage.downloadUrl("files/report.pdf"); console.log("Download the file from:", url); ``` ```typescript TypeScript theme={null} const url = await room.storage.downloadUrl("files/report.pdf"); console.log("Download the file from:", url); ``` ```dart Dart theme={null} final url = await room.storage.downloadUrl("files/report.pdf"); print("Download the file from: $url"); ``` ```dotnet C# theme={null} var url = await room.Storage.DownloadUrl("files/report.pdf"); Console.WriteLine($"Download the file from: {url}"); ``` ### `list(path)` **Description**\ Lists the contents of a folder, returning file and subfolder names along with a flag indicating if each entry is a folder. The server also returns `created_at` and `updated_at` timestamps; the Python SDK exposes them on `StorageEntry`. **Parameters** * `path` *(str)*: The folder path to list. **Returns** * *(list)*: A list of entries, each containing a `name` and `is_folder` property. Timestamps are available in SDKs that surface them. **Example**: ```bash CLI theme={null} meshagent room storage ls \ --room myroom \ room://some_folder ``` ```python Python theme={null} entries = await room.storage.list(path="some_folder") for e in entries: print(e.name, "is folder?" if e.is_folder else "is file?") ``` ```javascript NodeJs theme={null} const entries = await room.storage.list("some_folder"); entries.forEach(e => { console.log(e.name, e.isFolder ? "is folder" : "is file"); }); ``` ```typescript TypeScript theme={null} const entries = await room.storage.list("some_folder"); entries.forEach(e => { console.log(e.name, e.isFolder ? "is folder" : "is file"); }); ``` ```dart Dart theme={null} final entries = await room.storage.list("some_folder"); for (var e in entries) { print("${e.name} ${e.isFolder ? "is folder" : "is file"}"); } ``` ```dotnet C# theme={null} var entries = await room.Storage.List("some_folder"); foreach (var e in entries) { Console.WriteLine($"{e.Name} {(e.IsFolder ? "is folder" : "is file")}"); } ``` ### `delete(path, recursive=None)` **Description**\ Deletes a file or folder at the given path. A `file.deleted` event is typically emitted afterward. To delete a folder, pass `recursive=True` where the SDK exposes that option, or call the raw `storage.delete` request with the `recursive` flag. **Parameters** * `path` *(str)*: The file path to delete. * `recursive` *(bool, optional)*: Set `True` to delete folders recursively (Python helper or raw request). **Returns** * `None` **Example**: ```bash CLI theme={null} meshagent room storage rm \ --room myroom \ room://folder/old_file.txt ``` ```python Python theme={null} await room.storage.delete("folder/old_file.txt", recursive=False) print("File deleted.") ``` ```javascript NodeJs theme={null} await room.storage.delete("folder/old_file.txt"); console.log("File deleted."); ``` ```typescript TypeScript theme={null} await room.storage.delete("folder/old_file.txt"); console.log("File deleted."); ``` ```dart Dart theme={null} await room.storage.delete("folder/old_file.txt"); print("File deleted."); ``` ```dotnet C# theme={null} await room.Storage.Delete("folder/old_file.txt"); Console.WriteLine("File deleted."); ``` ### `move(source_path, destination_path, overwrite=False)` **Description** Moves or renames a file or folder. A `file.moved` event is typically emitted afterward. **Parameters** * `source_path` *(str)*: The current file or folder path. * `destination_path` *(str)*: The new file or folder path. * `overwrite` *(bool, optional)*: Whether to replace an existing destination. **Returns** * `None` **Example**: ```python Python theme={null} await room.storage.move( source_path="folder/draft.json", destination_path="folder/final.json", overwrite=True, ) ``` ```javascript NodeJs theme={null} await room.storage.move("folder/draft.json", "folder/final.json", { overwrite: true, }); ``` ```typescript TypeScript theme={null} await room.storage.move("folder/draft.json", "folder/final.json", { overwrite: true, }); ``` ```dart Dart theme={null} await room.storage.move( "folder/draft.json", "folder/final.json", overwrite: true, ); ``` ## Example Workflow A common use case: 1. Check if a file exists. 2. Upload data if it doesn’t exist. 3. Later, download the file to verify or use the data. 4. Delete the file when it’s no longer needed, reacting to the `file.deleted` event. ```python Python theme={null} import asyncio from meshagent.api import RoomClient async def main(): # Run with: # meshagent room connect --room=my-room --identity=participant-name -- python3 storage-download.py async with RoomClient() as room: data_to_write = b"Hello, Storage!" if not await room.storage.exists(path="example.txt"): await room.storage.upload( path="example.txt", data=data_to_write, overwrite=True, ) response = await room.storage.download(path="example.txt") print("Downloaded content:", response.data) await room.storage.delete(path="example.txt") asyncio.run(main()) ``` ```javascript NodeJs theme={null} const data = new TextEncoder().encode("Hello, Storage!"); if (!(await room.storage.exists("example.txt"))) { await room.storage.upload("example.txt", data, { overwrite: true }); } const response = await room.storage.download("example.txt"); console.log("Downloaded content:", new TextDecoder().decode(response.data)); await room.storage.delete("example.txt"); ``` ```typescript TypeScript theme={null} import { RoomClient } from "@meshagent/meshagent"; // Run with: // meshagent room connect --room=my-room --identity=participant-name -- async function main() { const room = new RoomClient(); try { await room.start(); const data = new TextEncoder().encode("Hello, Storage!"); if (!(await room.storage.exists("example.txt"))) { await room.storage.upload("example.txt", data, { overwrite: true }); } const response = await room.storage.download("example.txt"); console.log("Downloaded content:", new TextDecoder().decode(response.data)); await room.storage.delete("example.txt"); } catch (error) { console.error("Error starting the room client:", error); } finally { room.dispose(); } } void main(); ``` ```dart Dart theme={null} import 'dart:convert'; import 'dart:typed_data'; import 'package:meshagent/meshagent.dart'; Future downloadStorageExample(RoomClient room) async { final data = Uint8List.fromList(utf8.encode('Hello, Storage!')); if (!await room.storage.exists('example.txt')) { await room.storage.upload('example.txt', data, overwrite: true); } final response = await room.storage.download('example.txt'); print('Downloaded content: ${utf8.decode(response.data)}'); await room.storage.delete('example.txt'); } ``` ```dotnet C# theme={null} var data = Encoding.UTF8.GetBytes("Hello, Storage!"); if (!await room.Storage.Exists("example.txt")) { await room.Storage.Upload("example.txt", data, overwrite: true); } var response = await room.Storage.Download("example.txt"); Console.WriteLine($"Downloaded content: {Encoding.UTF8.GetString(response.Data)}"); await room.Storage.Delete("example.txt"); ``` This sequence demonstrates basic upload, read, and deletion flows within a single session. ## Related guides * [Room API Overview](./overview) * [Service YAML](../services/deployment/deploy_services) # Sync Source: https://docs.meshagent.com/room_api/sync ## Overview The `SyncClient` is the Room API for live shared documents (`MeshDocuments`). Use it when multiple humans or agents need to read and edit the same structured document in real time. ## CLI commands Start with the CLI help, then use a few common commands: ```bash bash theme={null} meshagent room sync --help meshagent room sync create --room myroom docs/briefing --schema ./briefing.schema.json meshagent room sync get --room myroom docs/briefing meshagent room sync grep --room myroom docs/briefing "priority" meshagent room sync update --room myroom docs/briefing --patch '[]' meshagent room sync inspect --room myroom docs/briefing meshagent room sync import --room myroom --file ./conversations.json ``` These commands use the actual CLI command shapes. `create` expects `./briefing.schema.json` to be a MeshSchema JSON file, `update --patch '[]'` is a no-op JSON Patch example, and `import` expects a local Claude GDPR `conversations.json` export plus the optional MeshAgent agent and Anthropic packages installed. ## Why use the Sync API? * Keep shared state in a live document instead of relying only on chat history. * Let multiple participants collaborate on the same structured content at once. * Define document schemas that help users and agents write valid data. ## How it works You create or open a document by path. Opening a document starts a live synchronization session so local changes propagate to other participants in the room. The Python SDK also exposes `describe` when you want the current JSON state without opening a sync session, and `sync` is available when you already have encoded changes to send. For the Python, JavaScript, TypeScript, and .NET standalone room examples on this page, start the script through `meshagent room connect --room={ROOM_NAME} --identity={AGENT_NAME} -- ` so MeshAgent injects the room connection environment automatically. For example: `meshagent room connect --room=my-room --identity=participant-name -- python3 documents-writing.py`. The Dart sample still shows the explicit protocol factory flow. ## Permissions and grants The Sync API is controlled by the `sync` grant on the participant token. In practice, sync grants are path-based and can be marked read-only. That lets you give a participant access to specific document paths without opening the entire sync surface. See [API Scopes](../rest_api/api_scopes) and [Service YAML](../services/deployment/deploy_services). ## Defining Your Document Structure To define the structure of a MeshDocument, you start by creating a schema using the MeshSchema class. A schema: * Documents the structure of your MeshDocument for anyone in your organization. * Ensures agents and users don’t write invalid data to the document. * Allows agents to automatically generate, manipulate, and validate structured documents. * Automatically generates LLM-compatible schemas for structured outputs. * Synchronizes documents across all platforms that MeshAgent supports. Similar to how a web page is structured, a MeshSchema begins with a root element that includes an allowed tag name and optional attributes. Afterward, you can define additional tags, their attributes, and the types of child nodes they can contain. ### Example Schema Suppose you have a basic web page structure and want to define a schema for it. ```python Python theme={null} from meshagent.api.schema import MeshSchema, ElementType, ChildProperty, ValueProperty schema = MeshSchema( root_tag_name="html", elements=[ ElementType( tag_name="html", properties=[ # a ChildProperty describes the type of children that # an element allows. There can be at most one child # property for each element type, but the child property # can allow multiple types of child elements. ChildProperty(name="children", child_tag_names=["body"]) ], ), ElementType( tag_name="body", properties=[ # Our body can only contain paragraph elements ChildProperty(name="children", child_tag_names=["p"]) ], ), ElementType( tag_name="p", properties=[ # A ValueProperty property describes an attribute that # contains a single value ValueProperty(name="class", type="string"), ], ), ], ) ``` ```javascript NodeJs theme={null} import { MeshSchema, ElementType, ChildProperty, ValueProperty, } from '@meshagent/meshagent'; // Create the schema const schema = new MeshSchema({ rootTagName: 'html', elements: [ new ElementType({ tagName: 'html', properties: [ // A ChildProperty describes the type of children that an element allows. // There can be at most one child property for each element type, but // the child property can allow multiple types of child elements. new ChildProperty({ name: 'children', childTagNames: ['body'], }), ], }), new ElementType({ tagName: 'body', properties: [ // Our body can only contain paragraph elements. new ChildProperty({ name: 'children', childTagNames: ['p'], }), ], }), new ElementType({ tagName: 'p', properties: [ // A ValueProperty describes an attribute that contains a single value. new ValueProperty({ name: 'class', type: 'string', }), ], }), ], }); ``` ```typescript TypeScript theme={null} import { MeshSchema, ElementType, ChildProperty, ValueProperty, SimpleValue, } from '@meshagent/meshagent'; // Create the schema const schema = new MeshSchema({ rootTagName: 'html', elements: [ new ElementType({ tagName: 'html', properties: [ // A ChildProperty describes the type of children that an element allows. // There can be at most one child property for each element type, but // the child property can allow multiple types of child elements. new ChildProperty({ name: 'children', childTagNames: ['body'], }), ], }), new ElementType({ tagName: 'body', properties: [ // Our body can only contain paragraph elements. new ChildProperty({ name: 'children', childTagNames: ['p'], }), ], }), new ElementType({ tagName: 'p', properties: [ // A ValueProperty describes an attribute that contains a single value. new ValueProperty({ name: 'class', type: SimpleValue.string, }), ], }), ], }); ``` ```dart Dart theme={null} import 'package:meshagent/meshagent.dart'; final schema = MeshSchema( rootTagName: 'html', elements: [ ElementType( tagName: 'html', description: 'The root html element.', properties: [ // A ChildProperty describes the type of children that // an element allows. There can be at most one child // property for each element type, but the child property // can allow multiple types of child elements. ChildProperty(name: 'children', childTagNames: ['body']), ], ), ElementType( tagName: 'body', description: 'The document body element.', properties: [ // Our body can only contain paragraph elements. ChildProperty(name: 'children', childTagNames: ['p']), ], ), ElementType( tagName: 'p', description: 'A paragraph element.', properties: [ // A ValueProperty describes an attribute that // contains a single value. ValueProperty(name: 'class', type: SimpleValue.string), ], ), ], ); void main() { // Here you could do something with `schema`, like // passing it to a registry or printing it out. print(schema); } ``` ```dotnet C# theme={null} using Meshagent.Api.Schema; using System.Collections.Generic; var schema = new MeshSchema( rootTagName: "html", elements: new List { new ElementType( tagName: "html", properties: new List { // A ChildProperty describes the type of children an element allows new ChildProperty( name: "children", childTagNames: new List { "body" } ) } ), new ElementType( tagName: "body", properties: new List { // Our body can only contain paragraph elements new ChildProperty( name: "children", childTagNames: new List { "p" } ) } ), new ElementType( tagName: "p", properties: new List { // A ValueProperty describes an attribute that contains a single value new ValueProperty( name: "class", type: SimpleValue.String ) } ) } ); ``` Many LLMs (such as OpenAI) and agent frameworks (such as MeshAgent) support JSON Schemas for defining inputs and outputs. Generating an OpenAI-compatible JSON schema from your MeshSchema requires only one line of code: ```python Python theme={null} json_schema = schema.to_json() ``` ```javascript NodeJs theme={null} const jsonSchema = schema.toJson(); ``` ```typescript TypeScript theme={null} const jsonSchema: Record = schema.toJson(); ``` ```dart Dart theme={null} final jsonSchema = schema.toJson(); ``` ```dotnet C# theme={null} var jsonSchema = schema.ToJson(); ``` ## Creating a MeshDocument To create a MeshDocument based on your schema and enable synchronization across different clients, use the MeshAgent runtime: ```python Python theme={null} import asyncio from meshagent.api import RoomClient async def main(): # Run with: # meshagent room connect --room=my-room --identity=participant-name -- python3 documents-writing.py path = "hello-world.document" async with RoomClient() as room: print(f"Connected to room: {room.room_name}") document = await room.sync.open(path=path, create=True) try: await document.synchronized document.root.append_child( tag_name="body", attributes={"text": "hello world!"} ) await asyncio.sleep(1) finally: await room.sync.close(path=path) asyncio.run(main()) ``` ```javascript NodeJs theme={null} import { RoomClient } from "@meshagent/meshagent"; // Run with: // meshagent room connect --room=my-room --identity=participant-name -- async function main() { const path = "hello-world.document"; const room = new RoomClient(); try { await room.start(); console.log(`Connected to room: ${room.roomName}`); const document = await room.sync.open(path, { create: true }); try { await document.synchronized; document.root.createChildElement("body", { text: "hello world!", }); await new Promise((resolve) => setTimeout(resolve, 1000)); } finally { await room.sync.close(path); } } catch (error) { console.error("Error:", error); } finally { room.dispose(); } } void main(); ``` ```typescript TypeScript theme={null} import { RoomClient } from "@meshagent/meshagent"; // Run with: // meshagent room connect --room=my-room --identity=participant-name -- async function main() { const path = "hello-world.document"; const room = new RoomClient(); try { await room.start(); console.log(`Connected to room: ${room.roomName}`); const document = await room.sync.open(path, { create: true }); try { await document.synchronized; document.root.createChildElement("body", { text: "hello world!", }); await new Promise((resolve) => setTimeout(resolve, 1000)); } finally { await room.sync.close(path); } } catch (error) { console.error("Error:", error); } finally { room.dispose(); } } void main(); ``` ```dart Dart theme={null} import 'package:meshagent/meshagent.dart'; import 'package:meshagent/helpers.dart' show websocketProtocol; void main() async { // Define a unique room name and chose your participant name const String roomName = 'examples'; const String participantName = 'example-participant'; // Document name (the extension identifies the schema) const String path = 'hello-world.document'; // Establish communication channel using participant token final protocolFactory = websocketProtocol( roomName: roomName, participantName: participantName, ); // Instantiate a new RoomClient for interacting with the room final room = RoomClient(protocolFactory: protocolFactory); // Connect to the room await room.start(); // Open our document final meshDocument = await room.sync.open(path); // Wait for the document to sync from the server await meshDocument.synchronized; meshDocument.root.createChildElement("body", {"text": "hello world!"}); } ``` ```dotnet C# theme={null} using System; using System.Collections.Generic; using System.Threading.Tasks; using Meshagent.Api.Room; // Run with: // meshagent room connect --room=my-room --identity=participant-name -- var path = "hello-world.document"; await using var room = new RoomClient(); await room.ConnectAsync(); Console.WriteLine($"Connected to room: {room.RoomName}"); var doc = await room.Sync.Open(path, create: true); try { await doc.Synchronized; doc.Root.AppendChild("body", new Dictionary { ["text"] = "hello world!", }); await Task.Delay(1000); } finally { await room.Sync.Close(path); } ``` ## API reference Use the methods below to create documents, open live sync sessions, inspect the current document state, and send low-level sync operations when needed. ### `create(path, json=None, schema=None)` ```bash CLI theme={null} meshagent room sync create \ --room myroom \ my/path \ --schema ./schema.json \ --json '{"key":"value"}' ``` ```python Python theme={null} await room.sync.create(path="my/path", json={"key": "value"}, schema=my_schema) ``` ```javascript NodeJs theme={null} await room.sync.create("my/path", { key: "value" }); ``` ```typescript TypeScript theme={null} await room.sync.create("my/path", { key: "value" }); ``` ```dart Dart theme={null} await room.sync.create("my/path", {"key": "value"}); ``` ```dotnet C# theme={null} await room.Sync.Create("my/path", new Dictionary { ["title"] = "Hello World" }); ``` * **Parameters**: * `path`: Document path. * `json`: Optional initial JSON payload. * `schema`: Optional `MeshSchema` for validating and describing the document shape. The Python helper exposes this parameter; other SDKs can pass a schema when opening a document. * **Description**: Create a new `MeshDocument` at the given path. The CLI create command requires `--schema`; Python SDK callers can pass a `MeshSchema` when creating a document. ### `describe(path, create=True)` ```python Python theme={null} doc_json = await room.sync.describe(path="my/path") ``` * **Parameters**: * `path`: Document path. * `create`: Accepted by the Python helper for compatibility; the current implementation ignores it and only describes the existing document. * **Returns**: The current document root as JSON. * **Description**: Read the current state of a `MeshDocument` without opening a live sync session. * **Availability**: Python exposes `room.sync.describe` today. Other SDKs can use `open()` or a lower-level request until they add a helper. ### `open(path, create=True, initial_json=None, schema=None)` ```python Python theme={null} doc = await room.sync.open( path="my/path", create=True, initial_json={"key": "value"}, schema=my_schema, ) ``` ```javascript NodeJs theme={null} const doc = await room.sync.open("my/path", { create: true }); ``` ```typescript TypeScript theme={null} const doc = await room.sync.open("my/path", { create: true }); ``` ```dart Dart theme={null} final doc = await room.sync.open("my/path", create: true); ``` ```dotnet C# theme={null} var doc = await room.Sync.Open("my/path", create: true); ``` * **Parameters**: * `path`: Document path. * `create`: When `true`, create the document if it does not already exist. * `initial_json`: Optional initial document JSON when creating a document through `open`. * `schema`: Optional `MeshSchema` to use when creating/opening the document. * **Returns**: A `MeshDocument` tied to that path. * **Description**: Open a live synchronization session for the document. Local changes are sent automatically while the document remains open. ### `close(path)` ```python Python theme={null} await room.sync.close(path="my/path") ``` ```javascript NodeJs theme={null} await room.sync.close("my/path"); ``` ```typescript TypeScript theme={null} await room.sync.close("my/path"); ``` ```dart Dart theme={null} await room.sync.close("my/path"); ``` ```dotnet C# theme={null} await room.Sync.Close("my/path"); ``` * **Parameters**: * `path`: Document path. * **Description**: Close the local sync session for that document path. Once closed, local changes are no longer synchronized. ### `sync(path, data)` ```python Python theme={null} await room.sync.sync(path="my/path", data=b"some bytes") ``` ```javascript NodeJs theme={null} await room.sync.sync("my/path", new Uint8Array([/*...bytes...*/])); ``` ```typescript TypeScript theme={null} await room.sync.sync("my/path", new Uint8Array([/*...bytes...*/])); ``` ```dart Dart theme={null} await room.sync.sync("my/path", Uint8List.fromList([/*...bytes...*/])); ``` ```dotnet C# theme={null} await room.Sync.Sync("my/path", Encoding.UTF8.GetBytes("some bytes")); ``` * **Parameters**: * `path`: Document path. * `data`: Serialized sync bytes. * **Description**: Send encoded sync data directly to the server. Use this when you already have the wire-format change payload. ## Notes * **Synchronized Changes**\ Once a document is opened, any local changes you make in the associated `MeshDocument` are automatically queued for sending, thanks to `sendChangesToBackend`. You rarely need to call `sync()` manually unless you want to send raw data yourself. * **Reference Counting**\ The `SyncClient` internally tracks how many times a document is opened via the same path. Calling `open` multiple times for the same path returns the same underlying document. Only when all references are closed (via `close()`) will the client actually disconnect. * **Error Handling**\ If a request fails, the `RoomClient` may throw an error (like `RoomServerException`). Wrap calls in `try/catch` (or use `.catch(...)`) to handle them gracefully. * **Concurrency and Performance** * For high throughput, ensure that your `RoomClient` and server are configured for concurrent operations. * The `SyncClient` uses a `StreamController` internally to manage queued updates, sending them asynchronously to the server. ## Related guides * [Room API Overview](./overview) * [Storage API](./storage) # HTTP Secret Proxy Source: https://docs.meshagent.com/secrets/http_proxy Use secrets without retrieving secret values directly. The HTTP secret proxy lets a user or service account use a credential without exposing the secret value to the caller. ```text theme={null} {api_url}/proxy-request?url={target_url}&secret-id={secret_id} ``` Add `user={email}` when the request should use a user-owned secret for a specific user. ## Authorization OAuth callers must own the user secret. If `user` is supplied, it must match the OAuth subject. API-key callers run as the API key's service account. The service account must have `use_proxy_secrets`, and the target secret must grant that service account per-secret `use_proxy`. ## Behavior The proxy sets the upstream `Authorization` header from the secret value. OAuth credential secrets are refreshed when needed and saved as a new secret version. The proxy supports normal HTTP requests, WebSocket upgrades, and streaming SSE responses. # Image Pull Secrets Source: https://docs.meshagent.com/secrets/image_pull_secrets Private image pulls use service-account pull secrets. Pull secrets are stored on service accounts. Services run as a service account with `container.run_as`, and MeshAgent uses pull secrets associated with that service account when pulling private images. See [Secrets and Credentials](./overview) for the current model. # MCP Secret Proxy Source: https://docs.meshagent.com/secrets/mcp_proxy Route MCP servers through the MeshAgent secret proxy. MCP endpoints can use proxy-backed credentials with `use_proxy_secret`. ```yaml yaml theme={null} ports: - num: 443 endpoints: - path: /mcp mcp: label: github use_proxy_secret: secret-123 ``` When `use_proxy_secret` is set, MeshAgent routes MCP requests through `/proxy-request` and supplies the upstream authorization header from the secret. OAuth credentials are refreshed by the proxy before use when needed. Agents and services using proxy-backed MCP should run as a service account with a runtime scope that includes `secrets:proxy`. # OAuth Credential Secrets Source: https://docs.meshagent.com/secrets/oauth_flows OAuth credentials use user secrets and proxy access. OAuth credentials are stored as user-owned secrets. Services and agents use those credentials through the HTTP or MCP proxy when the owning user grants proxy access to the service account. See [Secrets and Credentials](./overview) for the current model. # Secrets and Credentials Source: https://docs.meshagent.com/secrets/overview User and service-account secrets in MeshAgent. MeshAgent secrets use a user-owned and service-account-owned model. Secret APIs are scoped to: * the authenticated user, for credentials the user owns and manages * a service account, for credentials used by services that run as that account Secrets can carry metadata and annotations for search and credential context. Runtime services should use service-account identity (`container.run_as`) and service-account permissions rather than project-level secret references. ## Runtime Use Services that need secrets should run as a service account. Secret access is authorized through that service account and, for proxy-only credentials, through per-secret proxy grants. Credentials that should not be retrieved directly can be used through HTTP/MCP proxy flows. ## Related Guides * [User Secrets](./user_secrets) * [Service Account Secrets](./service_account_secrets) * [HTTP Secret Proxy](./http_proxy) * [MCP Secret Proxy](./mcp_proxy) * [Image Pull Secrets](./image_pull_secrets) * [OAuth Credential Storage](./oauth_flows) # Service Account Secrets Source: https://docs.meshagent.com/secrets/service_account_secrets Manage credentials owned by service accounts. Service account secrets are credentials owned by a service account. Services and managed agents should run as that service account with `container.run_as` or agent `run_as`. ## CLI Use `--subject` with the service account email, id, key, or name: ```bash bash theme={null} meshagent secret list --subject agent@service.example.meshagent.dev meshagent secret create registry-token \ --subject agent@service.example.meshagent.dev \ --type opaque \ --value "$TOKEN" ``` ## Roles Service-account secret operations are protected by service-account roles: * `secret_list` permits listing and searching secrets. * `secret_accessor` permits direct retrieval when the secret is not `http_only`. * `secret_manager` permits create, update, version, delete, metadata, annotation, and pull-secret management. * `use_proxy_secrets` permits proxy use when the per-secret `use_proxy` grant also allows it. * `run_service_as` permits configuring a service or managed agent to run as the service account. Project admins inherit service-account secret management access through the project model. ## Pull Secrets Image pull credentials attach to service accounts: ```bash bash theme={null} meshagent secret add-pull-secret secret-123 \ --project-id "$MESHAGENT_PROJECT_ID" \ --subject builder@service.example.meshagent.dev ``` When a service runs as that service account, MeshAgent uses the account's pull secrets while pulling private images. # User Secrets Source: https://docs.meshagent.com/secrets/user_secrets Manage credentials owned by the authenticated user. User secrets are credentials owned by the authenticated user. They are useful for personal OAuth tokens, API keys, and credentials that the user can grant to a service account for proxy use. ## CLI Use `--subject me` or omit `--subject`: ```bash bash theme={null} meshagent secret list --subject me meshagent secret search --subject me --query github meshagent secret create github-token --type opaque --value "$GITHUB_TOKEN" meshagent secret versions secret-123 --subject me meshagent secret add-version secret-123 --subject me --value "$ROTATED_TOKEN" ``` Direct retrieval of an `http_only` secret is denied. Use [HTTP Secret Proxy](./http_proxy) or [MCP Secret Proxy](./mcp_proxy) for proxy-only credentials. ## Proxy Grants A user can grant a service account proxy access to one of their secrets: ```bash bash theme={null} meshagent secret grant-proxy secret-123 \ --project-id "$MESHAGENT_PROJECT_ID" \ --subject agent@service.example.meshagent.dev ``` The grant allows proxy use only. It does not allow direct secret retrieval. ## OAuth Scopes User-secret APIs require the appropriate secret OAuth scopes, such as `secrets:read`, `secrets:write`, `secrets:delete`, or `secrets:grant`. # MeshAgent Base Images Source: https://docs.meshagent.com/services/containers/meshagent_base_images MeshAgent publishes base images so you can package and ship agents/services quickly without building every dependency from scratch. ## Where to Pull * [Docker Hub](https://hub.docker.com/u/meshagent) * [Google Artifact Registry](https://console.cloud.google.com/artifacts/docker/meshagent-public/us-central1/images) ## Image Catalog | Image | Best for | What’s inside | Notes | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `meshagent/cli` | Process-backed CLI agents, meeting transcribers, and VoiceBot containers that do not need in-container browser automation | A lean runtime image with the prebuilt `meshagent` binary as the entrypoint | Use this when you want the CLI runtime itself, not a general-purpose Linux shell image. Typically you run `meshagent process join ...`, `meshagent meeting-transcriber join ...`, or `meshagent voicebot join ...`. | | `meshagent/cli-playwright` | CLI agents that need bundled Playwright or Stagehand browser automation inside the container | `meshagent/cli` **plus** Playwright, downloaded browser binaries, Xvfb, fonts, and browser runtime libraries | Use this only when the container itself launches Playwright-managed browsers. If you do not need browser automation, prefer `meshagent/cli`. | | `meshagent/python` | Minimal Python runtime base for custom images and runtime-label deploy flows | Python 3.13 slim runtime with a standard virtualenv path preconfigured on `PATH` | Use this when you want a clean Python base and will install your own dependencies or let MeshAgent layer your code on top at deploy time. This is not the same image as `meshagent/python-sdk`. | | `meshagent/python-sdk-slim` | Standard Python agents and services that want core MeshAgent Python packages preinstalled without the heavier optional integrations | `meshagent/python` **plus** `uv` and the core MeshAgent Python packages: API, Agents, Tools, OpenAI, and OTEL | Recommended starting point for most Python services when you want MeshAgent packages preinstalled but do not need the broader integration set. | | `meshagent/python-sdk` | Python services that want the fuller preinstalled MeshAgent Python stack | `meshagent/python-sdk-slim` **plus** Codex, Computers, LiveKit, MarkItDown, MCP, and Anthropic packages | Use this when you want the broader MeshAgent Python package set already in the image. If you only need a base runtime, use `meshagent/python` instead. | | `meshagent/shell` | Shell-based tools, utility containers, and developer-style agents that need a Bash entrypoint and common Linux tools | Python 3.13 slim, a Python virtualenv with selected MeshAgent packages, and common Linux tools such as `git`, `curl`, `ripgrep`, `tree`, and `tcpdump` | This is the better fit when you want an interactive shell-style container rather than the lean `meshagent` CLI binary image. | | `meshagent/node` | Minimal JS/TS runtime base for custom Node services | A plain Node runtime image | Use this when you want a bare Node base and will install or copy your own application code yourself. This is not the same image as `meshagent/node-sdk`. | | `meshagent/node-sdk` | JS/TS services using the MeshAgent Node workspace scaffold | Node runtime **plus** the `meshagent-entrypoint` and `meshagent-ts` workspace scaffold | Preferred Node SDK image when you want the MeshAgent TS workspace already present. Also published with the compatibility tag `meshagent/nodejs-sdk`. | | `meshagent/dotnet-sdk` | .NET services | The latest .NET SDK image with the `meshagent-dotnet` source tree copied into the workspace | Use this as a build base when you want the MeshAgent .NET SDK source already available in the image. | | `meshagent/flutter` | Flutter and Dart UI builds | Flutter SDK image with the `meshagent-dart`, `meshagent-flutter`, and `meshagent-flutter-shadcn` workspace packages copied in | Use this when you are building or publishing Flutter-based UIs or packages on top of the MeshAgent Flutter workspace. | ## How to Choose * Use `meshagent/cli` when the container should start directly into the `meshagent` CLI and join a room as a process, meeting transcriber, or VoiceBot. * Use `meshagent/cli-playwright` only when that same CLI-style container also needs bundled Playwright browsers. * Use `meshagent/python` or `meshagent/node` when you want a slimmer language runtime base and will install your own app dependencies. * Use `meshagent/python-sdk-slim`, `meshagent/python-sdk`, or `meshagent/node-sdk` when you want MeshAgent packages or workspace scaffolding already present. * Use `meshagent/shell` when you want a shell-first utility image with common Linux tooling instead of the lean CLI runtime. ## Prewarmed Room Images In MeshAgent cloud rooms, the room host precaches these image refs at startup so the first use is already warm: * `meshagent/cli:default` * `meshagent/python:default` * `meshagent/node:default` * `meshagent/python-sdk:default` * `meshagent/python-sdk-slim:default` * `meshagent/node-sdk:default` If one of those images fits your runtime, use it first. In practice: * Use `meshagent/cli:default` for most CLI, process, meeting-transcriber, or VoiceBot containers that do not need bundled browser automation. * Use `meshagent/python:default` when you want a slim Python runtime and will install or layer your own app dependencies. * Use `meshagent/python-sdk-slim:default` or `meshagent/python-sdk:default` when you want MeshAgent Python packages preinstalled. * Use `meshagent/node:default` or `meshagent/node-sdk:default` for JS/TS runtimes depending on whether you want a plain runtime or the SDK workspace scaffold. Images such as `meshagent/cli-playwright`, `meshagent/shell`, `meshagent/dotnet-sdk`, and `meshagent/flutter` are still published, but they are not part of the default cloud-room precache list today. For those images, and for custom images, the `-esgz` variants still matter more for cold-start performance. ## Tags & Cold Starts * Tags: use `:default` inside MeshAgent manifests and room workflows when you want MeshAgent to resolve the image to the runtime-recommended tag for the current server version. You can also pin explicit version tags (for example `0.8.x`) when you want an exact image version. * Stargz: every base image also has a `*-esgz` variant. In MeshAgent cloud rooms these matter most for custom images and for stock images outside the prewarmed set above. On environments without the stargz snapshotter they still run normally, just without the lazy-pull speedup. If you are building your own container we recommend [creating a stargz-optimized image](./optimizing_containers), because that is still the main way to improve cold-start pull time for custom images. * Platform: images are published for `linux/amd64`. ## Related Topics * [Using Containers](./containers_api): Learn how to run containers through the MeshAgent Containers API. This is very helpful for running code on demand inside a Room. * [Optimizing Containers](./optimizing_containers): Learn how to optimize your container when deploying a custom service. # Build and Deploy Images Source: https://docs.meshagent.com/services/containers/meshagent_image Use `meshagent build` and `meshagent deploy` to build images inside a room and deploy them as room services. ## Overview `meshagent build` and `meshagent deploy` are the main CLI commands for working with OCI images in MeshAgent. Use them when you want to: * build an image inside a room from a local directory streamed as build context * publish that image into a project registry repository * deploy an image directly as a room service * build and deploy from a local directory in one command These commands are useful both for developers working from the CLI and for agent workflows running inside a room. They give MeshAgent a room-native way to build, package, and ship images without requiring Docker on the local machine that triggers the workflow. Before using a `registry.meshagent.com//:` tag, make sure the target repository exists in the project. See [Registries](../../project_admin/registries). ## How image build and deploy fit into MeshAgent The image workflow sits between source files and a deployable MeshAgent service: 1. `meshagent build PATH --tag ...` streams a local directory into a room and builds an image there. 2. `meshagent deploy --tag ...` creates or updates a room service from an existing image. 3. `meshagent deploy PATH --tag ...` does both in one command. This complements the normal service packaging flow. In practice, a room-connected agent can: * prepare files in the room * build an image from those files inside the room * deploy a service that uses that image That makes this workflow especially useful for cases where an agent is expected to build, test, and ship a containerized service for you from inside MeshAgent. ## Commands ### `meshagent build` Use `build` when you want MeshAgent to build an image inside a room. `meshagent build` streams a local directory into the room as the build context. If that directory contains a `Dockerfile`, MeshAgent uses it during the room-side build. The build runs in MeshAgent rather than requiring a local Docker daemon on the machine that started the command. Example: ```bash theme={null} meshagent build ./my-app \ --room myroom \ --tag registry.meshagent.com/myproject/my-app:dev ``` Key things to know: * `PATH` is required and becomes the streamed build context * `-t` or `--tag` is required * `--room` is required unless `MESHAGENT_ROOM` is already set * `-f` or `--file` selects a Dockerfile relative to `PATH`; otherwise MeshAgent uses `PATH/Dockerfile` or `PATH/Containerfile` * build logs stream back through the CLI while the build runs * this is a good fit for agent-driven build workflows inside a room because the build happens in MeshAgent, not on the local machine For example, use a Dockerfile in a subdirectory with the same flags as Docker: ```bash theme={null} meshagent build ./my-app \ --room myroom \ -t registry.meshagent.com/myproject/my-app:dev \ -f refresher/Dockerfile ``` ### `meshagent deploy` Use `deploy` when you already have an image and want to create or update a room service from it, or when you want to build and deploy from a local directory in one step. Example deploying an existing image: ```bash theme={null} meshagent deploy \ --room myroom \ --tag registry.meshagent.com/myproject/my-app:dev \ --env APP_ENV=dev ``` Example building and deploying from a local directory: ```bash theme={null} meshagent deploy ./my-app \ --room myroom \ --tag registry.meshagent.com/myproject/my-app:dev \ --file refresher/Dockerfile \ --env APP_ENV=dev ``` When deploying, you can also: * mount room storage with `--room-mount` * mount project storage with `--project-mount` * mount another image with `--image-mount` * mount scratch storage with `--empty-dir-mount` * inject a `MESHAGENT_TOKEN` with `--meshagent-token` * run the deployed container as a service account with `--run-as` * inject a service-account secret-backed environment variable with `--env-secret NAME=SECRET_ID`; this requires `--run-as` * publish a route with `--domain` when the service exposes exactly one published port When you pass `PATH`, `meshagent deploy` builds first and then deploys the resulting image tag. When you omit `PATH`, it deploys the image tag directly. In both cases the service name is derived from the image tag, and MeshAgent updates the existing room service when one already exists. ## How image build and deploy work with service packaging `meshagent build` and `meshagent deploy` are complementary to service packaging. Use this workflow when: * your workflow is image-first * you want to build inside a room * you want a fast path from image tag to room service * you want an agent in the room to participate in building and shipping the service Use the service packaging docs when: * you are writing or reviewing a `meshagent.yaml` * you need a fuller service spec with more explicit deployment structure * you are working with ServiceTemplates or broader service configuration In other words, `meshagent build` and `meshagent deploy` are the room-native image workflow, while service manifests are the broader service-definition workflow. ## Related guides * [Deploy a Web App](../deployment/deploy_web_app) * [Registries](../../project_admin/registries) * [Service YAML](../deployment/deploy_services) * [MeshAgent Base Images](./meshagent_base_images) * [Optimizing Containers](./optimizing_containers) * [MeshAgent CLI Reference](../../reference/meshagent_cli_help) # Optimizing Containers Source: https://docs.meshagent.com/services/containers/optimizing_containers MeshAgent runs room and project services as containers. You can also point to external services if you host them yourself. When you deploy a service that uses a container image, MeshAgent will pull, start, and keep that image in sync with the room or project it belongs to. **How fast a service becomes available depends primarily on how quickly its container image can be pulled and started.** To make startup faster and more reliable, we publish [eStargz (“stargz”)](https://github.com/containerd/stargz-snapshotter?tab=readme-ov-file) optimized images that allow for **lazy pulling**, a technique that can reduce pull-to-start time by up to \~75% for common workloads. If you are deploying custom services with your own container image we highly encourage you to optimize them with stargz to ensure the services start as quickly as possible. **Use MeshAgent base images when possible.** They are optimized and include eStargz variants: * [Docker Hub](https://hub.docker.com/r/meshagent/) * [Google Artifact Registry](https://console.cloud.google.com/artifacts/docker/meshagent-public/us-central1/images) In MeshAgent cloud rooms, the room host already precaches `meshagent/cli:default`, `meshagent/python:default`, `meshagent/node:default`, `meshagent/python-sdk:default`, `meshagent/python-sdk-slim:default`, and `meshagent/node-sdk:default` at startup. For those stock images, the `:default` reference is usually the right first choice. The `-esgz` variants still matter most for custom images and for published images outside that default warm set. ## Why optimization matters (and how lazy pulling helps) How fast an agent or service starts is directly related to how long it takes to pull and start its container image. Images that are large, slow to decompress, have unnecessary files or dependencies can take significantly longer to start. Stargz improves startup time by enabling **lazy pulling**. This allows the container to start before the full image is downloaded. Only the files needed during initial setup are fetched and the rest of the image is streamed on demand if/when needed. ## How MeshAgent uses your images * When a room starts, MeshAgent pulls and runs the images for every room service attached to that room. Pull time directly affects time-to-ready. * If you redeploy a **room service**, MeshAgent detects the change and reconciles the running container automatically. * If you redeploy a **project service**, restart the room for the change to take effect in that room. * If you are deploying a CLI process agent or VoiceBot, use the `meshagent/cli` base image by default. If the container needs bundled Playwright browsers for in-container browser automation, use `meshagent/cli-playwright` instead. Both are already optimized and support the standard flags (tools, rules, room-rules, etc.), so you usually do not need to build a custom image. * If you reference an **external service** you host yourself, MeshAgent skips pulling/running a container and just routes to your endpoint. Container optimizations only matter for services you package with a container image. ## What Stargz is and how we use it We publish images in an **eStargz/stargz** format and run with the [stargz snapshotter](https://github.com/containerd/stargz-snapshotter?tab=readme-ov-file) (a containerd plugin). This makes image layers *seekable* (the runtime can jump directly to specific files instead of downloading the whole layer first): * Instead of downloading and decompressing an entire layer before start, the runtime lazily fetches just the files that are actually touched at startup. * Startup is faster (lower cold-start latency) and data transfer is smaller, especially for larger Python/Node/ML stacks. * Lazy pulling requires the containerd stargz-snapshotter; if it is not present, the image pulls and runs like a normal OCI/Docker image (just without the lazy-pull speedup). * MeshAgent does not need a special tag or flag: the runtime decides. If the host has the stargz snapshotter, your stargz-compressed image is lazily pulled; if not, it is pulled normally. We publish **`-esgz` image variants** that are optimized for lazy pulling via the stargz snapshotter. On environments without the snapshotter, these `-esgz` images behave like normal images; they just don’t get the lazy-pull speedup. What we do on our images: * Build stargz variants alongside the normal tags. * Provide prefetch lists (the small set of files the agent touches during boot: entrypoint, deps, config) so the snapshotter pulls only what is needed up front. ## When deploying custom services 1. Use MeshAgent base images when possible (they already include stargz builds with `-esgz` tag). If building your own image, we recommend optimizing it using stargz so your service can start quickly. 2. Keep images slim: install only what you need, clean caches, and avoid large unused assets. 3. You can either publish only a stargz-optimized image (recommended -- avoids storing two images in your registry) or publish both a standard and an optimized version. To create stargz images we recommend using [nerdctl here](https://github.com/containerd/nerdctl) and [ctr-remote here](https://github.com/containerd/stargz-snapshotter/blob/main/docs/ctr-remote.md). **Sample Steps** ```bash theme={null} # Option 1: Build → optimize → push only the eStargz image (recommended) # 1. Build your app image locally (no push yet) docker buildx build \ -t YOUR_REPO/YOUR_IMAGE:build-temp \ --load \ . # 2. Convert the image to eStargz nerdctl image convert --estargz --oci \ YOUR_REPO/YOUR_IMAGE:build-temp \ YOUR_REPO/YOUR_IMAGE:esgz # 3. Push only the optimized image nerdctl push YOUR_REPO/YOUR_IMAGE:esgz # MeshAgent manifest: # container: # image: "YOUR_REPO/YOUR_IMAGE:esgz" ``` ```bash theme={null} # Option 2: Build & push a standard image + a stargz-optimized version # 1. Build and push your standard image (any tag) docker buildx build \ --tag YOUR_REPO/YOUR_IMAGE:latest \ --platform linux/amd64 \ --push # 2a: Convert to stargz with nerdctl nerdctl image pull YOUR_REPO/YOUR_IMAGE:latest nerdctl image convert --estargz --oci YOUR_REPO/YOUR_IMAGE:latest YOUR_REPO/YOUR_IMAGE:esgz nerdctl push YOUR_REPO/YOUR_IMAGE:esgz # OR 2b: Convert to stargz with ctr-remote # Then optimize to eStargz and push (needs access to your containerd socket, e.g., /run/containerd/containerd.sock) ctr-remote image pull YOUR_REPO/YOUR_IMAGE:latest ctr-remote image optimize --oci YOUR_REPO/YOUR_IMAGE:latest YOUR_REPO/YOUR_IMAGE:esgz ctr-remote image push YOUR_REPO/YOUR_IMAGE:esgz # Reference the tag you prefer in your service manifest: # container: # image: "YOUR_REPO/YOUR_IMAGE:esgz" ``` ## Related Topics * [Service YAML](../deployment/deploy_services): write and deploy service manifests with the MeshAgent CLI. # Deploy a built in Agent Source: https://docs.meshagent.com/services/deployment/deploy_builtin_agent Deploy a process-backed agent from MeshAgent CLI flags, or generate a starting service manifest from those flags. Deploy a process-backed agent with [`meshagent process`](../../reference/meshagent_cli_help#meshagent-process). Use `meshagent process deploy` when the CLI flags describe the agent you want to run. Use `meshagent process spec` when you want MeshAgent to generate a starting service manifest that you can review, edit, and deploy with `meshagent service`. ## Deploy directly with `meshagent process deploy` ```bash bash theme={null} meshagent process deploy \ --service-name my-chatbot \ --agent-name my-chatbot \ --channel chat \ --web-search \ --storage \ --room myroom ``` `meshagent process deploy` generates the starting service manifest and deploys it immediately. Use this when: * the built-in CLI flags describe the agent * the manifest does not need changes before deployment * you want to deploy the agent to a room or project from one command Pass `--room myroom` for a room service. Omit `--room` to deploy the service project-wide. ## Generate a service manifest with `meshagent process spec` `meshagent process spec` generates the starting service manifest for a process-backed service and writes it to stdout. ```bash bash theme={null} meshagent process spec \ --service-name my-chatbot \ --agent-name my-chatbot \ --channel chat \ --web-search \ --storage > meshagent.yaml # Deploy into one room meshagent service create --file meshagent.yaml --room myroom # Deploy across the whole project meshagent service create --file meshagent.yaml --global ``` Use this when: * you want to review the service manifest before deployment * you need to customize fields that are not exposed as `meshagent process` flags * you want to keep the service definition in source control ## Read next * [Service YAML](./deploy_services): write, validate, deploy, update, and delete services from a manifest. * [Process Agents Overview](../../agents/process/overview): understand how process agents run. * [Deploy a Process Agent](./process_agent_service): deploy a process-backed agent with chat, email, and scheduled queue entry points. # Service YAML Source: https://docs.meshagent.com/services/deployment/deploy_services Write, validate, deploy, update, and delete MeshAgent services from a service manifest. Write a service manifest when you want to review, customize, validate, deploy, update, or delete the service configuration yourself. Use [`meshagent service`](../../reference/meshagent_cli_help#meshagent-service) with service manifests. Use [Deploy a built in Agent](./deploy_builtin_agent) when you want to deploy a process-backed agent from CLI flags instead. In MeshAgent, you can deploy fixed or templated services project-wide or to specific rooms, either as MeshAgent-managed `container` services or as `external` services that MeshAgent routes to; for more detail, see [Intro to Services](../intro). The examples below show three common cases: * a `Service` with a `container` * a `ServiceTemplate` with a `container` * a `Service` with an `external` runtime ### Example 1: `Service` with `container` Use `kind: Service` when the configuration is fixed at deploy time. ```yaml Yaml theme={null} kind: Service version: v1 metadata: name: my-chatbot description: "A chatbot with web search and storage" annotations: meshagent.service.id: "my-chatbot" agents: - name: my-chatbot description: "A helpful chatbot" annotations: meshagent.agent.type: "ChatBot" container: image: "meshagent/cli:default" command: >- meshagent process join --agent-name my-chatbot --channel chat --web-search --storage --rule "You are a helpful assistant. Use web search to find current information and save important findings to storage." --room-rules "agents/my-chatbot/rules.md" environment: - name: MESHAGENT_TOKEN token: identity: my-chatbot storage: room: - path: /data read_only: false ``` This example uses `kind: Service` with a `container`. MeshAgent runs the `meshagent/cli:default` image, and the container starts `meshagent process join ...` inside it. Validate and deploy it: ```bash bash theme={null} meshagent service validate --file meshagent.yaml meshagent service create --file meshagent.yaml --room myroom ``` Use `--global` instead of `--room myroom` to deploy the same manifest as a project service. ### Example 2: `ServiceTemplate` with `container` Use `kind: ServiceTemplate` when the manifest shape stays the same but some values should be supplied during deployment or install. ```yaml Yaml theme={null} kind: ServiceTemplate version: v1 metadata: name: my-language-chatbot description: "A chatbot with web search and storage that responds in your chosen language" annotations: meshagent.service.id: "my-language-chatbot" variables: - name: language description: "The language the chatbot should respond in (e.g. English, Spanish, French)" agents: - name: my-language-chatbot description: "A helpful chatbot" annotations: meshagent.agent.type: "ChatBot" container: image: "meshagent/cli:default" command: >- meshagent process join --agent-name my-language-chatbot --channel chat --web-search --storage --rule "You are a helpful assistant. Always respond in {{ language }}. Use web search to find current information and save important findings to storage." --room-rules "agents/my-language-chatbot/rules.md" environment: - name: MESHAGENT_TOKEN token: identity: my-language-chatbot storage: room: - path: /data read_only: false ``` This example adds a `language` variable and uses `{{ language }}` inside the `container.command`. Validate and deploy it: ```bash bash theme={null} meshagent service validate-template --file meshagent.yaml meshagent service create-template \ --file meshagent.yaml \ --value language=Spanish \ --room myroom ``` Use `--global` instead of `--room myroom` to deploy the rendered service project-wide. If you want to inspect the rendered YAML first, use `meshagent service render-template --file meshagent.yaml --value language=Spanish`. ### Example 3: `Service` with `external` Use `external` when MeshAgent should route to a service you already host elsewhere instead of running a container for you. ```yaml Yaml theme={null} kind: Service version: v1 metadata: name: mcp-deepwiki description: "Expose the DeepWiki MCP server" ports: - num: 443 type: http endpoints: - path: /mcp mcp: label: "mcp-deepwiki" description: "MCP DeepWiki tools" allowed_tools: - tool_names: ["search", "read_page"] read_only: true external: url: "https://mcp.deepwiki.com" ``` This example is a fixed `Service` that routes to an MCP server hosted outside MeshAgent. MeshAgent does not run the MCP server. It uses the `external.url` and `ports.endpoints` config to register that server's tools in the room. Validate and deploy it: ```bash bash theme={null} meshagent service validate --file mcp-service.yaml meshagent service create --file mcp-service.yaml --room myroom ``` If you need installer-provided values such as a URL, label, or OAuth settings, you can use `external` inside a `ServiceTemplate` too. For a longer walkthrough, see [Connect to an External MCP Server](./external_mcp_service). ## Manage deployed services Use `meshagent service` after deployment to inspect and manage what you deployed. ```bash bash theme={null} # List project services meshagent service list # List room services meshagent service list --room myroom # View details for one service meshagent service get SERVICE_ID # Update a deployed Service meshagent service update --file meshagent.yaml --room myroom --id SERVICE_ID # Update a deployed ServiceTemplate meshagent service update-template --file meshagent.yaml --value key=value --room myroom --id SERVICE_ID # Stop a service and prevent it from starting meshagent service disable SERVICE_ID --room myroom # Allow a disabled service to start again meshagent service enable SERVICE_ID --room myroom # Delete a deployed service meshagent service delete SERVICE_ID --room myroom ``` Omit `--room myroom` when you are updating, listing, or deleting a project service instead. ## Service configuration field reference ### Top-level fields | Field | Required | Description | | ----------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | `version` | Yes | Schema version. Always `v1`. | | `kind` | Yes | `Service` or `ServiceTemplate`. | | `enabled` | No | `Service` only. Whether the service should run. Defaults to `true`; setting it to `false` stops a running managed service and prevents future starts. | | `metadata` | Yes | Service identity and display information. | | `agents` | No | Agent identities exposed by this service. | | `files` | No | Files MeshAgent should seed into room storage if they do not already exist. | | `ports` | No | Network ports and HTTP endpoints MeshAgent can route to. | | `container` | \* | Container configuration. Mutually exclusive with `external`. | | `external` | \* | External service URL. Mutually exclusive with `container`. | | `variables` | No | User-provided inputs for templating. `ServiceTemplate` only. | \* Either `container` or `external` is required, but not both. ### metadata Identifies the service and provides information displayed in the UI. | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------------------------------- | | `name` | string | Yes | Unique service name. | | `description` | string | No | Description shown in UI. | | `repo` | string | No | Source code repository URL. | | `icon` | string | No | Icon or emoji for UI display. | | `annotations` | object | No | Key-value metadata. See [Annotations](#annotations). | ### agents Declares the participant identities this service provides. MeshAgent uses this to route requests, apply policies, and display agents in the UI. | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------------------------------------- | | `name` | string | Yes | Unique agent identity within the service. | | `description` | string | No | Display text describing the agent. | | `annotations` | object | No | Key-value metadata. See [Annotations](#annotations). | | `channels` | object | No | Channel-specific routing config for mail, messaging, queues, and toolkits. | | `email` | object | No | Mailbox settings for this agent identity. | | `heartbeat` | object | No | Recurring queue turn for this agent. | #### agents.channels Use `channels` when one deployed agent should participate in more than one entry point. | Field | Type | Required | Description | | ----------- | ---- | -------- | ---------------------------------------------- | | `email` | list | No | Inbound email channels for the agent. | | `messaging` | list | No | Messaging channels and optional named prompts. | | `queue` | list | No | Queue channels the agent should consume. | | `toolkit` | list | No | Toolkits the agent should register or expose. | Queue channel entries support: | Field | Type | Required | Description | | ---------------- | ------ | -------- | --------------------------------------------------------------- | | `queue` | string | Yes | Queue name the agent should consume. | | `threading_mode` | string | No | Threading mode for queue-delivered work, such as `default-new`. | | `message_schema` | object | No | JSON schema describing expected queue payload shape. | Messaging channel entries support: | Field | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------------------------- | | `protocol` | string | No | Messaging protocol. Defaults to `meshagent.agent-message.v1`. | | `prompts` | list | No | Named prompts available on that messaging channel. | #### agents.email Use `email` when the agent identity itself should have mailbox settings attached to it. | Field | Type | Required | Description | | --------- | ------- | -------- | --------------------------------------------------- | | `address` | string | Yes | Email address for the agent. | | `public` | boolean | No | Whether anyone can send to it. Defaults to `false`. | #### agents.heartbeat Use `heartbeat` when the agent should enqueue a recurring turn for itself without creating a separate scheduled-task resource by hand. | Field | Type | Required | Description | | ----------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `queue` | string | Yes | Queue that receives the recurring work item. | | `thread_id` | string | No | Optional thread path or template. Time tokens such as `{year}`, `{month}`, `{day}`, `{hour}`, and `{minute}` are expanded at runtime. Token matching is case-insensitive, so `{YYYY}/{MM}/{DD}/{HH}/{mm}` also works. | | `prompt` | list | Yes | Prompt content for each heartbeat turn. Uses typed content items such as `text` and `file`. | | `minutes` | integer | Yes | Interval, in minutes, between heartbeats. | Heartbeat `prompt` items use the same typed content model as agent turns: | Field | Type | Required | Description | | ------ | ------ | -------- | --------------------------------------------------------------- | | `type` | string | Yes | `text` or `file`. | | `text` | string | No | Text content when `type: text`. | | `url` | string | No | File URL when `type: file`, including `room:///...` references. | Example: ```yaml theme={null} agents: - name: assistant annotations: meshagent.agent.type: ChatBot meshagent.chatbot.threading: "default-new" meshagent.chatbot.thread-dir: agents/assistant/threads email: address: assistant@example.com public: true heartbeat: queue: assistant-scheduled-tasks thread_id: /agents/assistant/threads/heartbeats/{year}/{month}/{day}/{hour}.{minute}.thread prompt: - type: file url: room:///agents/assistant/heartbeat.md minutes: 60 files: - path: /agents/assistant/heartbeat.md text: | # Assistant Heartbeat Review recent room activity, unresolved requests, and any obvious follow-up work. If there is clear useful work to do, do it directly. If there is nothing useful to add, end the turn quietly without posting a filler message. Previous threads can be found looking at the threads in the path format based on the time: /data/agents/assistant/threads/heartbeats/{year}/{month}/{day}/{hour}.{minute}.thread Read the last few heartbeat threads to make sure you are up to date with what has been done so far ``` This mirrors the built-in assistant service template: each heartbeat run is queued to the assistant, uses the heartbeat prompt file from room storage, and writes the run into a timestamped thread under the assistant thread directory. ### files Top-level `files` seed room storage before the service starts. MeshAgent creates each file only if it does not already exist, which makes this useful for editable starter content such as prompts, rules, or templates. | Field | Type | Required | Description | | ------ | ------ | -------- | ---------------------------- | | `path` | string | Yes | Room-storage path to create. | | `text` | string | Yes | Initial file contents. | Use top-level `files` when the content should live in room storage and remain editable after deploy. Use `container.storage.files` when the file should be mounted inside the running container itself. ### container Defines a container for MeshAgent to run. Fields marked **†** are only available in `Service`, not `ServiceTemplate`. | Field | Type | Required | Description | | ------------------ | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------ | | `image` | string | Yes | Container image (for example `meshagent/cli:default`). | | `template` | `"agent"` or `"none"` | No | Runtime defaults to apply when the container starts. Defaults to `"agent"`. | | `command` | string | No | Command to execute when the container starts. | | `working_dir` | string | No | Absolute working directory used when starting the container command. | | `environment` | list | No | Environment variables to set in the container. | | `run_as` | object | No | Service account identity and runtime scopes. Required when using `SecretValue` environment variables. | | `storage` | object | No | Storage volumes to mount into the container. | | `on_demand` | boolean | No | When true, the container runs only when explicitly invoked. | | `writable_root_fs` | boolean | No | Allow writes to the container's root filesystem for the life of that container instance. Default: read-only. | | `private` | boolean | No | Advanced setting that keeps interactive container access private to the owning service. Default: true. | #### container.template `container.template` controls the MeshAgent runtime defaults added when the container starts: * `"agent"` (default): mount room storage at `/data`, create a participant token for the container name with role `agent` and default agent API permissions, and inject MeshAgent/OpenAI/Anthropic runtime environment variables. * `"none"`: do not add those defaults. Only values explicitly configured in the manifest or container start request are passed through. The `"agent"` template sets defaults only when the environment variable is not already configured. Values in `container.environment` override template defaults. The `"agent"` template may set: | Variable | Description | | ----------------------- | --------------------------------------------------------------------------------------------------- | | `MESHAGENT_TOKEN` | Room participant token for the container name, with role `agent` and default agent API permissions. | | `OPENAI_API_KEY` | Same participant token, for OpenAI-compatible clients using MeshAgent's proxy. | | `ANTHROPIC_API_KEY` | Same participant token, for Anthropic-compatible clients using MeshAgent's proxy. | | `SMTP_PASSWORD` | Same participant token, for SMTP authentication. | | `SMTP_USERNAME` | Container name, for SMTP authentication. | | `SMTP_HOSTNAME` | MeshAgent SMTP hostname, set from `MESHAGENT_MAIL_DOMAIN` when available. | | `SMTP_PORT` | SMTP port. Defaults to `587`. | | `OPENAI_BASE_URL` | OpenAI-compatible MeshAgent proxy URL injected into the runtime. | | `ANTHROPIC_BASE_URL` | Anthropic-compatible MeshAgent proxy URL injected into the runtime. | | `MESHAGENT_API_URL` | MeshAgent API URL reachable from the container. | | `MESHAGENT_ROOM_URL` | MeshAgent room API base URL reachable from the container. | | `MESHAGENT_ROOM` | Current room name. | | `MESHAGENT_PROJECT_ID` | Current project ID, when available. | | `MESHAGENT_SESSION_ID` | Current session ID, when available. | | `OTEL_ENDPOINT` | OpenTelemetry collector endpoint reachable from the container. | | `OTEL_PYTHON_LOG_LEVEL` | Python OpenTelemetry log level forwarded from the room runtime, when available. | | `MESHAGENT_MAIL_DOMAIN` | MeshAgent mail domain forwarded from the room runtime, when available. | #### container.run\_as `container.run_as` selects the service account identity used by the container. The default scope list grants access to the HTTP/MCP secret proxy without granting broad project administration. | Field | Type | Required | Description | | -------- | --------------- | -------- | ------------------------------------------------------------------------------ | | `email` | string | Yes | Service account email the container runs as. | | `scopes` | list of strings | No | Runtime scopes for the service-account token. Defaults to `["secrets:proxy"]`. | #### container.environment Each entry sets an environment variable in the container. A variable can come from a literal `value`, a MeshAgent `token`, or a service-account `secret`. | Field | Type | Required | Description | | -------- | ------ | -------- | ------------------------------------------------------------------------------------------------ | | `name` | string | Yes | Environment variable name. | | `value` | string | No | Literal string value. | | `token` | object | No | Request a participant token to be generated and injected as the value. | | `secret` | object | No | Load a secret available to the service account in `container.run_as` and inject it as the value. | Use: * `value` for plain configuration * `token` for MeshAgent API access * `secret` for service-account credentials. `container.run_as` is required when any environment variable uses `secret`. `token` fields: | Field | Type | Required | Description | | ---------- | ------ | -------- | ---------------------------------------------------------------------------- | | `identity` | string | Yes | Participant identity the token is issued for. | | `api` | object | No | API scope granted to the token. See [API Scopes](../../rest_api/api_scopes). | | `role` | string | No | Participant role (for example `user`, `agent`, or `tool`). | `secret` fields: | Field | Type | Required | Description | | ----- | ------ | -------- | ---------------------------------------------------------------- | | `id` | string | Yes | Secret ID to load for the service account in `container.run_as`. | This pattern is common for services: `token` gives the service access to MeshAgent, while `secret` gives it an external credential through its service account. #### container.storage Mounts storage volumes into the container. | Field | Type | Description | | ------------ | ---- | ----------------------------------------------------------------------- | | `room` | list | Per-room storage. Read/write by default. | | `project` | list | Project-wide shared storage. Read-only by default. | | `images` | list | Content from another container image. Read-only by default. | | `files` | list | Inline text content mounted as a file. Read-only by default. | | `empty_dirs` | list | Writable temporary directories mounted into the container. | | `configs` | list | MeshAgent runtime config mounts such as `spec.json` and `members.json`. | Room and project mount fields: | Field | Type | Required | Description | | ----------- | ------- | -------- | --------------------------------------- | | `path` | string | Yes | Mount path inside the container. | | `subpath` | string | No | Subdirectory within the storage volume. | | `read_only` | boolean | No | Whether the mount is read-only. | Image mount fields: | Field | Type | Required | Description | | ----------- | ------- | -------- | -------------------------------- | | `image` | string | Yes | Source container image. | | `path` | string | Yes | Mount path inside the container. | | `subpath` | string | No | Subdirectory within the image. | | `read_only` | boolean | No | Whether the mount is read-only. | File mount fields: | Field | Type | Required | Description | | ----------- | ------- | -------- | -------------------------------- | | `path` | string | Yes | Mount path inside the container. | | `text` | string | Yes | File contents. | | `read_only` | boolean | No | Whether the mount is read-only. | Empty directory mount fields: | Field | Type | Required | Description | | ----------- | ------- | -------- | --------------------------------------------- | | `path` | string | Yes | Mount path inside the container. | | `read_only` | boolean | No | Whether the temporary directory is read-only. | Config mount fields: | Field | Type | Required | Description | | ------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ | | `path` | string | Yes | Directory inside the container where MeshAgent runtime config files should be mounted. Defaults to `/var/run/meshagent`. | Config mounts are useful when a shell tool or helper process inside the container needs access to runtime files such as `spec.json` and `members.json`. ### external Routes traffic to a service running outside MeshAgent. Requires `ports` to define how MeshAgent reaches the service. | Field | Type | Required | Description | | ----- | ------ | -------- | --------------------------------- | | `url` | string | Yes | URL where the service is running. | ### ports Defines network ports the service listens on and how MeshAgent routes HTTP traffic to them. | Field | Type | Required | Description | | ------------- | ------------ | -------- | ------------------------------------------------------ | | `num` | `"*"` or int | Yes | Port number, or `"*"` for auto-assignment. | | `type` | string | No | Protocol: `http` or `tcp`. | | `liveness` | string | No | HTTP path for health checks. | | `endpoints` | list | No | Endpoints served on this port. | | `published` | boolean | No | Expose the port to the internet. | | `public` | boolean | No | When false, requests must include a participant token. | | `annotations` | object | No | Key-value metadata. | For HTTP ports, set `liveness` to the path MeshAgent should poll to decide whether the service port is ready. For example, `liveness: /healthz` tells MeshAgent to request that path on the running service. A `2xx` response reports the port as `ready`; failed checks report `not ready`; ports without a liveness path report `no liveness` in `meshagent room service list`. #### ports.endpoints Each endpoint maps a URL path to either a MeshAgent-native service or an MCP server. | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------------------------- | | `path` | string | Yes | URL path for this endpoint. | | `meshagent` | object | No | MeshAgent-native endpoint. Mutually exclusive with `mcp`. | | `mcp` | object | No | MCP server endpoint. Mutually exclusive with `meshagent`. | | `annotations` | object | No | Key-value metadata. | ##### meshagent endpoint Connects the endpoint to a MeshAgent participant identity. | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------------------------- | | `identity` | string | Yes | Participant identity for this endpoint. | | `api` | object | No | API scope overrides. See [API Scopes](../../rest_api/api_scopes). | ##### mcp endpoint Registers an MCP server as a toolkit in the room. | Field | Type | Required | Description | | --------------------- | ------ | -------- | ------------------------------------------- | | `label` | string | Yes | Toolkit display name. | | `description` | string | No | Description of what the toolkit provides. | | `allowed_tools` | list | No | Filters which tools are exposed. | | `headers` | object | No | Custom HTTP headers to include in requests. | | `require_approval` | string | No | `always` or `never`. | | `oauth` | object | No | OAuth client configuration. | | `openai_connector_id` | string | No | OpenAI connector ID. | `allowed_tools` entries: | Field | Type | Required | Description | | ------------ | ------- | -------- | ----------------------------- | | `tool_names` | list | Yes | Tool names to allow. | | `read_only` | boolean | No | Treat the tools as read-only. | `oauth` fields: | Field | Type | Required | Description | | ------------------------ | ------- | -------- | ------------------------------------------- | | `client_id` | string | Yes | OAuth client ID. | | `client_secret` | string | No | OAuth client secret. | | `authorization_endpoint` | string | Yes | Authorization endpoint URL. | | `token_endpoint` | string | Yes | Token endpoint URL. | | `no_pkce` | boolean | No | Disable PKCE (Proof Key for Code Exchange). | | `scopes` | list | No | OAuth scopes to request. | ### variables (ServiceTemplate only) Defines user-provided inputs for a `ServiceTemplate`. Values are substituted into the YAML using `{{ variable_name }}` syntax. Template values are rendered into the manifest before validation, so they can be used anywhere the resulting YAML remains valid. | Field | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------------------------------- | | `name` | string | Yes | Variable identifier. Referenced as `{{ name }}` in templates. | | `title` | string | No | Human-readable label shown in install UI. | | `description` | string | No | Help text shown in UI and Powerboards. | | `enum` | list | No | Restricts input to specific values. Displayed as a dropdown. | | `optional` | boolean | No | Whether the variable can be left blank. | | `obscure` | boolean | No | Hides the value in UI. Use for sensitive data. | | `type` | string | No | Type hint (for example `email`). | | `annotations` | object | No | Key-value metadata. See [Annotations](#annotations). | ### Annotations Annotations are key-value strings attached to services, agents, or variables. MeshAgent and Powerboards use specific annotation keys to control behavior. You can also define custom annotations. #### Service annotations Set in `metadata.annotations`. | Key | Description | | -------------------------- | ---------------------------------------------------- | | `meshagent.service.id` | Unique identifier for the service. | | `meshagent.service.readme` | URL or inline content for the service documentation. | #### Agent annotations Set in `agents[].annotations`. | Key | Description | | -------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `meshagent.agent.type` | Internal agent type metadata used by service manifests and generated specs. | | `meshagent.agent.widget` | UI widget to display for this agent. | | `meshagent.agent.schedule` | JSON string defining a `ScheduledTaskSpec`. Use either `queue: { name, payload }` or `container`, not both. | | `meshagent.agent.shell.command` | Shell command for `Shell`-type agents. | | `meshagent.agent.dataset.schema` | Dataset schema metadata for the agent. | #### Variable annotations Set in `variables[].annotations`. | Key | Description | | ----------------------- | ------------------------------------------------------------------------- | | `meshagent.secret.id` | Suggested secret identifier for installer-collected credential variables. | | `meshagent.secret.name` | Display name for installer-collected credential variables. | | `meshagent.secret.type` | Credential content type for installer-collected variables. | #### Event annotations Set in `agents[].annotations`. Subscribe an agent to room events. The value is the name of a queue that a queue-consuming agent can process. | Key | Description | | ----------------------------------------- | -------------------------------------------- | | `meshagent.events.service.created` | Fires when a service is created in the room. | | `meshagent.events.service.updated` | Fires when a service is updated. | | `meshagent.events.room.user.grant.create` | Fires when a user is added to the room. | | `meshagent.events.room.user.grant.delete` | Fires when a user is removed from the room. | | `meshagent.events.room.user.grant.update` | Fires when a user's room grant is updated. | ## Read next * [Build and Deploy Images](../containers/meshagent_image): build and deploy images with `meshagent build` and `meshagent deploy` * [Secrets and Credentials](../../secrets/overview): manage user-owned and service-account-owned secrets * [Observability](../../observability/overview): inspect logs, traces, metrics, and custom OpenTelemetry output * [Webhook Handoffs](../../services/webhooks): handle `room.call` webhook handoffs in your own services # Deploy a Web App Source: https://docs.meshagent.com/services/deployment/deploy_web_app Deploy a Node.js web app to a MeshAgent room with a private or public meshagent.app domain. Use `meshagent deploy` to build a local web app, deploy it as a room service, and attach a stable domain such as `YOUR_SITE.meshagent.app`. This guide starts from an empty directory. By the end, the app is running in a MeshAgent room, protected by MeshAgent sign-in, writing files to room storage, and calling the MeshAgent LLM router. `meshagent deploy` reads the Dockerfile, builds the container image in MeshAgent, creates or updates the room service, and creates or updates the route when you pass `--domain`. MeshAgent rooms run agents and services in containers. That means the same deployment pattern works for apps written in Node.js, Python, Go, .NET, Rust, or any other language that can run in a container. This guide uses Node.js because it is a popular choice for building web applications. ## Create a Node.js web server Create a `package.json` file: ```json package.json theme={null} { "name": "meshagent-web-hello", "version": "1.0.0", "type": "module", "scripts": { "start": "node server.js" } } ``` `package.json` tells Node.js that this project uses JavaScript modules and that `npm start` should run `server.js`. Create the dependency lockfile: ```bash theme={null} npm install ``` This app does not have external dependencies yet, but `npm install` creates `package-lock.json`. The lockfile records the exact dependency versions for the project. The Dockerfile below uses `npm ci`, which expects a lockfile and installs from it reproducibly. Create `server.js`: ```js server.js theme={null} import http from "node:http"; const port = Number(process.env.PORT || 8080); const server = http.createServer((req, res) => { if (req.url === "/healthz") { res.writeHead(200, { "content-type": "text/plain" }); res.end("ok\n"); return; } res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); res.end(` MeshAgent Web App

Hello from MeshAgent

This app is running inside a MeshAgent room.

`); }); server.listen(port, "0.0.0.0", () => { console.log(`listening on ${port}`); }); ``` This server listens on the port from `PORT`, or `8080` when `PORT` is not set. The `/healthz` path is a simple health check. MeshAgent can call it to confirm the app is ready before sending browser traffic to the service. Add a Dockerfile: ```dockerfile Dockerfile theme={null} FROM node:22-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY server.js ./ ENV NODE_ENV=production ENV PORT=8080 EXPOSE 8080 CMD ["node", "server.js"] ``` A Dockerfile is the build recipe for the app. It tells Docker and MeshAgent which runtime to start from, which files to copy into the image, which install commands to run, and which command starts the app. The Dockerfile above does the following: * `FROM node:22-alpine` starts from a small Linux image with Node.js installed. * `WORKDIR /app` sets the working directory inside the image. * `COPY package*.json ./` copies `package.json` and `package-lock.json`. * `RUN npm ci --omit=dev` installs production dependencies from the lockfile. * `COPY server.js ./` copies the application code. * `ENV PORT=8080` gives the app the HTTP port used by this guide. * `EXPOSE 8080` marks the container port that serves HTTP traffic. * `CMD ["node", "server.js"]` starts the server when the container runs. A container image is a packaged version of the app and its runtime. A container is a running instance of that image. `meshagent deploy` builds the image and runs it as a service in the room. ## Deploy it Deploy the current directory to a room and attach a `meshagent.app` domain: ```bash theme={null} meshagent deploy . \ --room my-room \ --tag web-hello:v1 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz ``` The command uses: * `.` as the source directory to build. * `--room my-room` as the room where the service will run. * `--tag web-hello:v1` as the image tag for this version of the app. * `--domain YOUR_SITE.meshagent.app` as the browser URL for the service. * `--liveness /healthz` as the readiness check path. Replace `my-room` and `YOUR_SITE` with your room name and site name. Use a new tag each time you deploy a meaningful update, such as `web-hello:v1`, `web-hello:v2`, and `web-hello:v3`. The tag is the deployable version of the app. If a later deploy has a problem, point the service back at an earlier tag while you fix the new version: ```bash theme={null} meshagent deploy \ --room my-room \ --tag web-hello:v1 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz ``` That command redeploys the already-built `web-hello:v1` image. It does not include `.` because it is not building the current directory again. Open: ```text theme={null} https://YOUR_SITE.meshagent.app ``` A route connects the domain to the room service. By default, `meshagent deploy` creates a private route. A private route is protected by MeshAgent IAP. IAP stands for Identity-Aware Proxy: MeshAgent authenticates the browser user, checks that the user has access to the room, and then forwards the request to the web app. This gives you a private web app without adding login code to the app. The app can focus on the UI and application behavior, while MeshAgent handles sign-in and room access at the route. ## Show the signed-in user For private browser routes, MeshAgent provides the signed-in room identity to the app in the `X-MESHAGENT-USER` request header. Update `server.js` to display that user: ```js server.js theme={null} import http from "node:http"; const port = Number(process.env.PORT || 8080); const server = http.createServer((req, res) => { if (req.url === "/healthz") { res.writeHead(200, { "content-type": "text/plain" }); res.end("ok\n"); return; } const user = req.headers["x-meshagent-user"] || "anonymous"; res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); res.end(` MeshAgent Web App

Hello from MeshAgent

Signed in as ${escapeHtml(String(user))}.

`); }); server.listen(port, "0.0.0.0", () => { console.log(`listening on ${port}`); }); function escapeHtml(value) { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } ``` Deploy the updated app with a new tag: ```bash theme={null} meshagent deploy . \ --room my-room \ --tag web-hello:v2 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz ``` Refresh the page. After sign-in, the app displays the authenticated room identity from the IAP header. The route still uses `YOUR_SITE.meshagent.app`; the service now runs the image tagged `web-hello:v2`. ## Write files to room storage Containers have their own filesystem. When you run the app locally, writes go to your local disk. When you deploy the app into a room, writes go to the container filesystem unless you mount room storage into the container. A mount connects a path inside the container to storage managed outside the container. The app still reads and writes normal files, but the files are stored in the room instead of only inside that one running container. Update `server.js` to append each request to a log file: ```js server.js theme={null} import { mkdir, readFile, appendFile } from "node:fs/promises"; import http from "node:http"; import path from "node:path"; const port = Number(process.env.PORT || 8080); const dataDir = process.env.APP_DATA_DIR || path.join(process.cwd(), "data"); const visitLogPath = path.join(dataDir, "visits.log"); const server = http.createServer(async (req, res) => { if (req.url === "/healthz") { res.writeHead(200, { "content-type": "text/plain" }); res.end("ok\n"); return; } const user = req.headers["x-meshagent-user"] || "anonymous"; await recordVisit(String(user)); const visits = await readVisits(); res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); res.end(` MeshAgent Web App

Hello from MeshAgent

Signed in as ${escapeHtml(String(user))}.

Recent visits

${escapeHtml(visits)}
`); }); server.listen(port, "0.0.0.0", () => { console.log(`listening on ${port}`); console.log(`writing visits to ${visitLogPath}`); }); async function recordVisit(user) { await mkdir(dataDir, { recursive: true }); await appendFile(visitLogPath, `${new Date().toISOString()} ${user}\n`); } async function readVisits() { try { return await readFile(visitLogPath, "utf8"); } catch (error) { if (error.code === "ENOENT") { return ""; } throw error; } } function escapeHtml(value) { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } ``` Test it locally: ```bash theme={null} npm start ``` Open `http://localhost:8080`, then check the file on your machine: ```bash theme={null} cat data/visits.log ``` The file is created locally because the app is running on your machine. The local request displays `anonymous` for the user because the browser is connecting directly to `localhost`, not through the private MeshAgent route. Update the Dockerfile so the container writes app data to `/data`: ```dockerfile Dockerfile theme={null} FROM node:22-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY server.js ./ ENV NODE_ENV=production ENV PORT=8080 ENV APP_DATA_DIR=/data VOLUME /data EXPOSE 8080 CMD ["node", "server.js"] ``` `APP_DATA_DIR=/data` tells the app to write `visits.log` under `/data` after it is deployed. `VOLUME /data` marks `/data` as the writable data directory for the container. Deploy again with a room mount: ```bash theme={null} meshagent deploy . \ --room my-room \ --tag web-hello:v3 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz \ --room-mount /web-hello:/data:rw ``` The room mount format is: ```text theme={null} --room-mount :: ``` In this example, `/web-hello` is the path in room storage, `/data` is the path inside the container, and `rw` means the service can read and write the mounted files. Refresh `https://YOUR_SITE.meshagent.app` a few times, then open [MeshAgent Studio](https://studio.meshagent.com), go to the room, and inspect room storage. The file is written at: ```text theme={null} /web-hello/visits.log ``` Your local `data/visits.log` file is no longer updated by the deployed app. The app is running in the room, and `/data` now points at room storage. ## Call the LLM router Add the OpenAI SDK: ```bash theme={null} npm install openai ``` Update `server.js` to call the MeshAgent LLM router through the OpenAI SDK: ```js server.js theme={null} import { mkdir, readFile, appendFile } from "node:fs/promises"; import http from "node:http"; import path from "node:path"; import OpenAI from "openai"; const port = Number(process.env.PORT || 8080); const dataDir = process.env.APP_DATA_DIR || path.join(process.cwd(), "data"); const visitLogPath = path.join(dataDir, "visits.log"); const openai = new OpenAI({ baseURL: process.env.OPENAI_BASE_URL, apiKey: process.env.OPENAI_API_KEY, }); const server = http.createServer(async (req, res) => { if (req.url === "/healthz") { res.writeHead(200, { "content-type": "text/plain" }); res.end("ok\n"); return; } const user = req.headers["x-meshagent-user"] || "anonymous"; await recordVisit(String(user)); const visits = await readVisits(); const message = await generateMessage(String(user)); res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); res.end(` MeshAgent Web App

Hello from MeshAgent

Signed in as ${escapeHtml(String(user))}.

${escapeHtml(message)}

Recent visits

${escapeHtml(visits)}
`); }); server.listen(port, "0.0.0.0", () => { console.log(`listening on ${port}`); console.log(`writing visits to ${visitLogPath}`); }); async function recordVisit(user) { await mkdir(dataDir, { recursive: true }); await appendFile(visitLogPath, `${new Date().toISOString()} ${user}\n`); } async function readVisits() { try { return await readFile(visitLogPath, "utf8"); } catch (error) { if (error.code === "ENOENT") { return ""; } throw error; } } async function generateMessage(user) { const response = await openai.responses.create({ model: "gpt-5.4", input: `Write one short welcome sentence for ${user}.`, }); return response.output_text; } function escapeHtml(value) { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } ``` The OpenAI SDK normally sends requests to OpenAI. In this example, `OPENAI_BASE_URL` points the SDK at the MeshAgent LLM proxy instead. `OPENAI_API_KEY` is a MeshAgent credential for the room, not a provider key. That lets the app use the standard OpenAI SDK while MeshAgent handles project routing, usage tracking, and access control. Test the app locally through the room: ```bash theme={null} meshagent room connect --room=my-room --identity=web-hello -- npm start ``` Open: ```text theme={null} http://localhost:8080 ``` `meshagent room connect` runs the command on your machine and provides the same MeshAgent environment variables that the app receives in the room. That is why the local app can call the LLM router without hardcoding a proxy URL or token. The local request still does not include `X-MESHAGENT-USER` because your browser is connecting directly to `localhost`; the request is not passing through the MeshAgent IAP route. Deploy the LLM-enabled app with a new tag and the same room mount: ```bash theme={null} meshagent deploy . \ --room my-room \ --tag web-hello:v4 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz \ --meshagent-token agentDefault \ --room-mount /web-hello:/data:rw ``` `--meshagent-token agentDefault` injects `MESHAGENT_TOKEN`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` for the deployed service. The token identity defaults to the service name derived from the image repository, so `web-hello:v4` uses the `web-hello` identity. Refresh `https://YOUR_SITE.meshagent.app`. The page shows the signed-in user, recent visits from room storage, and a sentence generated through the MeshAgent LLM router. ## Deploy a public site A site can also be public. Use `--public` when anyone on the internet should be able to load the site without a MeshAgent room sign-in: ```bash theme={null} meshagent deploy . \ --room my-room \ --tag web-hello:v5 \ --domain YOUR_SITE.meshagent.app \ --liveness /healthz \ --meshagent-token agentDefault \ --room-mount /web-hello:/data:rw \ --public ``` Public sites are useful for demos, static marketing pages, public webhook targets, and other endpoints that are intentionally open. A public route still points at the same room service, but browser requests are not checked against room membership. Do not depend on IAP headers in a public route because public requests are not authenticated by MeshAgent room access. If the public site calls the LLM router, anyone who can reach the site can trigger those requests. ## Optimizing Cold Start Latency Rooms have a lifecycle. When a room is active, MeshAgent starts the services needed by that room. When the room goes idle, those services can be stopped. The next request to a routed web app can start the room again before the app responds. Cold start latency is the extra time before the first response while the service starts. For a web app, the important work is: * preparing the container image * starting the Node.js process * loading application files and dependencies * waiting for the app to listen on its HTTP port The optimizations below reduce the amount of content that must be prepared and the amount of work Node has to do before the first request succeeds. A small, cheap `/healthz` endpoint also helps. It gives MeshAgent a quick readiness check so traffic is sent to the app after the server is listening. ### Use a multistage build A Docker image is built in layers. A normal Dockerfile can leave build tools, source files, package-manager cache, and development dependencies in the final image even though the running app does not need them. A multistage Dockerfile separates the build environment from the runtime environment. The first stage installs dependencies and prepares the app. The final stage copies only the files needed to run the server: ```dockerfile Dockerfile theme={null} FROM node:22-alpine AS build WORKDIR /src COPY package.json package-lock.json ./ RUN npm ci COPY server.js ./ FROM node:22-alpine WORKDIR /app COPY --from=build /src/package.json /src/package-lock.json ./ RUN npm ci --omit=dev COPY --from=build /src/server.js ./ ENV NODE_ENV=production ENV PORT=8080 ENV APP_DATA_DIR=/data VOLUME /data EXPOSE 8080 CMD ["node", "server.js"] ``` This final image still uses Node, but it does not include the first stage's build cache or temporary files. Smaller runtime images are faster to prepare during room startup and have fewer files for the app to scan at runtime. ### Bundle with ncc Node.js usually loads code by resolving imports from your app and from `node_modules`. That is flexible during development, but it can mean the runtime container has thousands of small files and Node has to resolve many paths during startup. `ncc` is a Node.js bundler. It starts from an entry file, follows the imports used by that file, and writes the application plus its dependencies into a small output directory. For this app, the entry file is `server.js` and the output is `dist/index.js`. Install `ncc` as a development dependency and build the bundle: ```bash theme={null} npm install --save-dev @vercel/ncc npx ncc build server.js --target es2022 --out dist ``` Update the Dockerfile to run the bundled output: ```dockerfile Dockerfile theme={null} FROM node:22-alpine AS build WORKDIR /src COPY package.json package-lock.json ./ RUN npm ci COPY server.js ./ RUN npx ncc build server.js --target es2022 --out dist FROM node:22-alpine WORKDIR /app COPY --from=build /src/dist/index.js ./index.js ENV NODE_ENV=production ENV PORT=8080 ENV APP_DATA_DIR=/data VOLUME /data EXPOSE 8080 CMD ["node", "index.js"] ``` This helps cold starts because the runtime container starts Node with one application file instead of a source tree plus `node_modules`. The final image also does not need `ncc` itself, because bundling happened in the build stage. ### Use a scratch runtime image with `meshagent.runtime=node` The previous Dockerfile still ships a full Node base image as part of your app image. For the smallest deployable artifact, use a final `scratch` stage. `scratch` is Docker's empty base image. It contains only the files you copy into it. On its own, a `scratch` image cannot run Node, so add `LABEL meshagent.runtime=node` to tell `meshagent deploy` that this artifact should run on MeshAgent's Node runtime: ```dockerfile Dockerfile theme={null} FROM node:22-alpine AS build WORKDIR /src COPY package.json package-lock.json ./ RUN npm ci COPY server.js ./ RUN npx ncc build server.js --target es2022 --out dist FROM scratch LABEL meshagent.runtime=node WORKDIR /app COPY --from=build /src/dist/index.js ./index.js ENV NODE_ENV=production ENV PORT=8080 ENV APP_DATA_DIR=/data VOLUME /data EXPOSE 8080 CMD ["/app/index.js"] ``` The final image now contains only the bundled application file and metadata. The `meshagent.runtime=node` label tells `meshagent deploy` to run that application content on MeshAgent's prewarmed Node runtime image. This helps because the app artifact stays small while the Node runtime comes from an optimized image MeshAgent can prepare ahead of time. Room services are started as part of the room lifecycle, so reducing the app image size and reusing the optimized runtime layer both reduce the amount of work needed before the first request can complete. ## Related docs * [Routes](../../project_admin/routes): understand private and public routed domains. * [Build and Deploy Images](../containers/meshagent_image): use MeshAgent image workflows from the CLI. * [Optimizing Containers](../containers/optimizing_containers): optimize custom containers for faster startup. # Intro to Services Source: https://docs.meshagent.com/services/intro Understand what deployed services are, when to use project or room services, and how Service, ServiceTemplate, container, and external fit together. In MeshAgent, a deployed service is code MeshAgent saves and starts for you when a room session becomes active. That code can be an agent, a toolkit, an MCP server, an external integration, or other supporting application logic. Use a deployed service when you want something to stay available in a room or across a project. If you only need to run something temporarily, use the [Containers API](../room_api/containers) instead. ## Project services, room services, and on-demand containers | Option | Use it when | | ----------------------- | ----------------------------------------------------------------------------- | | **Project service** | the capability should be available in every room | | **Room service** | the capability should be available in one room only or should vary per room | | **On-demand container** | you want to run something temporarily without saving it as a deployed service | Use a project service for shared functionality, a room service for per-room behavior, and the Containers API for temporary runs you do not want to save. ## Project services vs room services Project services are shared across the whole project. Use them for common capabilities that should always be available, such as a shared toolkit or a project-wide agent. Room services are saved to one room. Use them when the service is room-specific, user-specific, or something people should choose for their room. The same service manifest can be deployed either way. The scope is set when you deploy it: * `--global` creates a project service * `--room myroom` creates a room service ## Service vs ServiceTemplate A `Service` is ready to run as written. A `ServiceTemplate` asks for values during deployment or installation, then renders a concrete `Service`. Use: * **`Service`** when the configuration is already known * **`ServiceTemplate`** when users or installers should provide values such as prompts, API keys, names, addresses, or other settings Both `Service` and `ServiceTemplate` can be used for project services or room services. Service manifests can also describe the supporting runtime details around that service, such as seeded files, container mounts, agent email settings, and agent heartbeat behavior. ## Container vs external Under either `Service` or `ServiceTemplate`, choose how MeshAgent reaches the service: * **`container`**: MeshAgent pulls an image and runs it for you * **`external`**: the service is already running somewhere else and MeshAgent routes traffic to it Use `container` when you want MeshAgent to manage the runtime. Use `external` when you already host the service and just want MeshAgent to connect to it. Both `Service` and `ServiceTemplate` can use either `container` or `external`. ## How deployed services behave Deployed services are tied to room sessions. * When a room becomes active, MeshAgent starts the services that should run there. * When the room goes idle and the session ends, MeshAgent shuts those services down. * Project services are managed at project scope. Changes usually take effect when the room starts a new session. * Room services are managed per room. If the saved room service changes during an active session, MeshAgent can reconcile the running service to match. ## What counts as a service? A service is anything you want MeshAgent to save and make available as part of the room or project runtime. That can include: * a process-based agent * a toolkit or integration * an MCP server * a custom HTTP service * supporting application logic that should run with the room ## Where to go next * [Deploy a built in Agent](./deployment/deploy_builtin_agent): deploy a process-backed agent from CLI flags * [Deploy a Web App](./deployment/deploy_web_app): deploy a Node.js app with a private or public `meshagent.app` domain * [Service YAML](./deployment/deploy_services): write, validate, deploy, update, and delete services from a manifest * [Containers API](../room_api/containers): run on-demand containers instead of deployed services * [Build and Deploy Images](./containers/meshagent_image): build and ship container images for deployed services # Webhook Handoffs Source: https://docs.meshagent.com/services/webhooks Handle `room.call` webhook handoffs in your own service with WebhookServer. Use this page when MeshAgent needs to call your service or toolkit over the webhook transport. ## When to use `WebhookServer` Use `WebhookServer` when your endpoint needs: * built-in signature verification * a default `GET /` health check * a default `POST /webhook` handler * support for `room.call` handoffs, including websocket upgrades ## What `room.call` sends For `room.call`, MeshAgent sends: * `room_name` * `room_url` * `token` * optional `arguments` That is the handoff MeshAgent uses when it calls your own service endpoint. ## Configure webhook verification Set the webhook secret if you want the server to verify signed requests: ```bash theme={null} export MESHAGENT_WEBHOOK_SECRET=your-secret ``` For local development, you can disable verification with `validate_webhook_secret=False`. ## Run `WebhookServer` The built-in server listens on port `8080` by default and exposes: * `GET /` for health checks * `POST /webhook` for webhook delivery * `GET /webhook` for websocket upgrades used by `room.call` Use the SDK to create the server and handle `room.call`: ```python Python theme={null} from meshagent.api.webhooks import ( WebhookServer, CallEvent, ) import asyncio class CustomWebhookServer(WebhookServer): async def on_call(self, event: CallEvent): print(f"room call for {event.room_name}") print(f"arguments: {event.arguments}") async def main(): server = CustomWebhookServer() await server.run() asyncio.run(main()) ``` ## Related docs * [Service YAML](../services/deployment/deploy_services) * [MeshAgent CLI Commands](../reference/meshagent_cli_help)