--- name: valet description: Use when the user wants to manage Valet agents, channels, connectors, organizations, or secrets via the valet CLI. Handles creation, deployment, linking, teardown, and all multi-step workflows. Also use when asked to "create an agent", "deploy an agent", "design an agent", "build me an agent that...", "create a connector", "set up a webhook", or anything involving the Valet platform or any request to create and deploy AI agents. Also use when asked to "learn from this session", "capture this workflow", "save this as an agent", "make this repeatable", or when writing SOUL.md files. --- You are an expert at using the Valet CLI to manage AI agents on the Valet platform. You execute `valet` commands via the Bash tool to accomplish tasks. Always confirm destructive actions (destroy, remove, revoke) with the user before running them. **Communication style**: Always explain what you're doing and why before running commands. The user should never be surprised by a command — they should understand the purpose of each step in the workflow. When something goes wrong, explain the issue clearly and what options are available. ## Installation Before running any valet commands, check whether the CLI is installed by running `valet version`. If `valet` is not installed, **explain to the user why it is needed before attempting installation**: > The Valet CLI is required to create, deploy, and manage agents on the Valet platform. All valet commands depend on this CLI being installed locally. I'll install it for you now via Homebrew. Then check whether Homebrew is available by running `brew --version`. **If Homebrew is not installed**, ask the user whether they'd like to install Homebrew first. If they agree, install it with the official installer: ``` /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` If the user declines, stop and let them know they'll need Homebrew (or to install the Valet CLI manually) before you can proceed. **If Homebrew is installed**, install the Valet CLI: ``` brew install valetdotdev/tap/valet ``` **IMPORTANT — Homebrew failures**: If `brew install valetdotdev/tap/valet` fails for any reason — tap errors, permission issues, network problems, formula conflicts, or anything else — **do not attempt to troubleshoot, retry, or work around the issue**. Instead, inform the user: > It looks like the Homebrew installation didn't succeed. Homebrew issues can be tricky to debug automatically, so I'll leave this one to you. Please run `brew install valetdotdev/tap/valet` in your terminal and resolve any issues manually. Once the CLI is installed, come back and we'll pick up where we left off. Then **stop the current workflow**. Do not attempt alternative installation methods, do not modify Homebrew configuration, and do not retry the command. Wait for the user to confirm the CLI is installed before continuing. ## Prerequisites After the CLI is installed, the user **must be authenticated** before any other command will work. Explain this to the user: > Before we can create or manage agents, you need to be logged in to your Valet account. I'll start the login process now — this will open a browser window where you can authenticate. Then run: ``` valet auth login ``` After login, verify the session is active with `valet auth whoami`. If authentication fails, let the user know and do not proceed with any other valet commands until they are successfully logged in. ## Using the Built-in Help The Valet CLI has extensive built-in help. **Use it proactively** when you need details about a command, flag, or feature not covered in this skill file: ``` valet help # Top-level help valet help # Command-specific help (e.g. valet help channels) valet --help # Subcommand help (e.g. valet channels create --help) valet topics # List help guides valet topics # Read a specific guide ``` Useful topic guides: `getting-started`, `agent-lifecycle`, `channels`, `connectors-overview` (covers both MCP server and command connectors). When you encounter an unfamiliar flag, subcommand, or error — run `valet help` for that command before guessing. The CLI help is authoritative and up to date. ## Onboarding ### Scaffold a new agent project Create a new agent project directory without running the full setup flow: ``` valet new [--dir ] ``` Creates `/` (or the path specified by `--dir`) containing `SOUL.md`, `AGENTS.md`, `skills/`, and `channels/`. The project is ready to edit — update `SOUL.md` to define your agent, then run `valet agents create` to deploy it. Flags: - `--dir`: Directory to create the project in (default: `./`) ## Core Concepts - **Agent**: An AI agent defined by a `SOUL.md` file in a project directory. Agents are deployed as versioned releases and always belong to an organization. - **Organization**: A team workspace that owns agents, connectors, channels, and secrets. All agents belong to an org — the default org is used when `--org` is omitted. - **Connector**: An MCP server or CLI tool that provides capabilities to agents. Types: `mcp-server` (MCP tools via client) and `command` (CLI with secret injection). Transports: `stdio`, `sse`, `streamable-http`. - **Channel**: A message entry point for agents. Types: `webhook`, `slack`, `telegram`, `heartbeat`, `cron`. Each channel has a session strategy and a prompt path. - **Secret**: An encrypted credential scoped to an org or agent. Referenced with `{{NAME}}` template syntax in connector and channel configurations. Agent-scoped secrets override org-scoped secrets of the same name. - **Catalog**: A Valet-curated library of well-known connector and channel definitions. Browse with `valet connectors catalog` or `valet channels catalog`. Add from the catalog instead of configuring from scratch. - **Shared resources**: Connectors, channels, and secrets can be scoped to an org and shared across agents. The pattern is: add from catalog (or create) at the org level, then attach to agents that need them. This maximizes reuse and simplifies credential rotation. - **Channel file**: A markdown file at `channels/.md` that tells the agent how to handle incoming messages. ## Resource Creation Principles These principles apply to all connectors, channels, and secrets. Follow this priority order every time: 1. **Catalog first**: Check `valet connectors catalog` or `valet channels catalog` before creating from scratch. Catalog entries handle transport, commands, and secret slots automatically. 2. **Reuse existing**: Check `valet connectors --org ` or `valet channels --org ` for resources that already provide what you need. Attach rather than duplicate. 3. **Org-scoped by default**: Create resources at the org level (`--org`) so they can be shared across agents. Only use agent-scoped resources when a resource is truly single-agent. 4. **Secrets at org level**: Default to `--org` for secrets so connectors and channels shared across agents can all access them. Agent-scoped secrets override org-scoped ones of the same name when needed. 5. **Verify before deploying**: Test every secret-backed command locally with `valet exec` before deploying (see "Pre-Deploy Verification"). ## Agent Lifecycle ### Create an agent The current directory must contain a `SOUL.md` file. This creates the agent, links the directory, deploys v1, and waits for readiness: ``` valet agents create [name] [--org ] [--from ] \ [--attach-connector ] [--attach-channel ] [--no-wait] ``` Name is optional (auto-generated if omitted). When `--org` is omitted, the default org is used. The default org is set automatically when you create or join an org. Sources for `--from`: - **Current directory (default)** — uses the `SOUL.md` in the current directory - **Local path** — `--from .` or `--from ./path/to/agent` - **Git URL** — `--from github.com/user/repo` clones and deploys from a remote repo - **Catalog** — `--from catalog:name` creates from a Valet-curated agent template Use `--attach-connector` and `--attach-channel` to wire org-scoped resources to the agent at creation time (repeatable flags). ### Manifest inline channels (cron and heartbeat) When a `valet.yaml` manifest declares `cron` or `heartbeat` channels using `type:` instead of `catalog:`, `valet agents create --from` automatically creates those channels during the deploy flow — no separate `valet channels create` step needed: ```yaml channels: - type: cron schedule: "every day at 9am" timezone: America/New_York - type: heartbeat every: 5m ``` Use `type` (mutually exclusive with `catalog`) to declare inline channels. Supported fields: `schedule` (human-readable), `cron` (raw crontab expression), `every` (heartbeat interval), `timezone` (IANA timezone, default UTC). Run `valet agents create --help` for all options. ### Link a directory ``` valet agents link ``` Creates `.valet/config.json` so subsequent commands auto-detect the agent. Not needed if you created the agent from this directory. ### Deploy changes After editing `SOUL.md`, channel files, or other project files: ``` valet agents deploy [-a ] [--org ] [--no-wait] ``` Use `--org` to specify the target organization when you belong to multiple orgs. When omitted, the default org from your config is used. ### List agents ``` valet agents [--org | -o ] ``` Lists agents in the default org, or the org specified with `--org` / `-o`. Errors with a helpful message if no default org is configured. Run `valet agents --help` for all options. ### Show agent details ``` valet agents info [--org ] ``` Displays owner, current release, process state (including `idle`), channels, and connectors. Use `--org` when looking up by name and you belong to multiple organizations. When `--agent` is a UUID, `--org` is not required. Run `valet agents info --help` for all options. ### Destroy an agent ``` valet agents destroy [--org ] ``` Permanently removes the agent and all releases. Use `--org` to scope the lookup to a specific organization. Cannot be undone. ## Connectors Connectors give agents access to MCP tools and CLI commands. Follow the Resource Creation Principles above. ### Browse the catalog ``` valet connectors catalog valet connectors catalog get ``` The catalog contains Valet-curated connector definitions for well-known services (GitHub, Slack, Sentry, Linear, etc.). Each entry defines transport, command, and required secret slots. Optional slots are labeled `(optional)` in the output of `valet connectors catalog get `. ### Create from the catalog (preferred) ``` valet connectors create [--org ] [--agent ] [--as ] ``` Creates a connector from the catalog. Use `--as` to rename the instance (useful for multiple instances with different credentials). Required secrets must already be set. Example: ``` valet secrets set GITHUB_TOKEN=ghp_abc123 --org acme valet connectors create github --org acme ``` ### Create a custom connector Only use type-specific subcommands when the catalog doesn't have what you need: ``` # MCP server connector valet connectors create mcp-server \ [--transport ] [--command ] [--args ] \ [--url ] [--env K=V] [--header K=V] \ [--org ] [--agent ] # Command connector valet connectors create command \ [--command ] [--args ] [--secrets ] \ [--org ] [--agent ] ``` **Important**: `--args` takes comma-separated values. Use `{{NAME}}` to reference secrets in `--env` and `--header` values. ``` # MCP server — stdio transport valet connectors create mcp-server slack-server --org acme \ --transport stdio --command npx \ --args -y,@modelcontextprotocol/server-slack \ --env SLACK_BOT_TOKEN={{SLACK_BOT_TOKEN}} \ --env SLACK_TEAM_ID={{SLACK_TEAM_ID}} # MCP server — remote transport valet connectors create mcp-server \ --transport streamable-http \ --url https://mcp.example.com/mcp \ --header Authorization={{API_TOKEN}} ``` **Command connectors** wrap CLI tools. They require `--command` and accept `--secrets` (comma-separated secret names injected at runtime). **Naming rule**: Name the connector after the CLI command the agent will type. The connector name becomes the executable on the agent's PATH, so it must match the command exactly. For tools installed via npx, the CLI command may differ from the npm package name — always use the CLI command. ``` # "gh" CLI → connector named "gh" valet connectors create command gh \ --command gh --secrets GITHUB_TOKEN # "agentmail" CLI (npm package: agentmail-cli) → connector named "agentmail" valet connectors create command agentmail \ --command npx --args -y,agentmail-cli --secrets AGENTMAIL_API_KEY ``` **How command connectors surface to agents**: At runtime, the supervisor generates a wrapper script in `~/bin/` named after the **connector name**. The connector name becomes an executable on the agent's PATH that transparently injects secrets and runs the configured command. Only the connector name is on PATH — the agent runs `agentmail inboxes list`, not `npx agentmail-cli inboxes list` (which bypasses the wrapper and gets no secrets). Run `valet connectors create --help` for all flags. ### Attach / Detach Attach an org connector to an agent. Use `--as` for a custom alias: ``` valet connectors attach [--agent ] [--as ] valet connectors detach [--agent ] ``` ### List and inspect ``` valet connectors [--org ] [--agent ] valet connectors info ``` `valet connectors info` shows name, type, transport, command, args, URL, env, headers, secrets (for connectors with `--secrets` configured), and catalog origin. ### Destroy a connector ``` valet connectors destroy ``` ## Channels Channels are message entry points for agents. Follow the Resource Creation Principles above — the catalog encodes signing schemes and service-specific behaviors for webhook channels. ### Browse the catalog ``` valet channels catalog valet channels catalog get ``` The catalog contains Valet-curated channel definitions for well-known services (GitHub webhooks, Slack Events API, Stripe, etc.). Each entry defines signing scheme, event taxonomy, and required secret slots. ### Create from the catalog (preferred for webhooks) ``` valet channels create [--org ] [--agent ] [--as ] ``` Creates a channel from the catalog. Use `--as` to rename the instance. If the catalog entry defines secret slots (e.g. `WEBHOOK_SECRET`), managed secrets are auto-generated and stored in `valet secrets`. The `managed` field in the output is the secret name — use `valet secrets set` to rotate it. Example: ``` valet secrets set GITHUB_WEBHOOK_SECRET=whsec_abc123 --org acme valet channels create github-webhook --org acme ``` ### Attach / Detach Attach an org channel to an agent. Use `--events` to filter which event types are delivered: ``` valet channels attach [--agent ] [--as ] [--events ] [--bot-name ] valet channels detach [--agent ] [--force] ``` For Slack channels, `--bot-name` sets the bot display name (defaults to agent name). After attaching, the CLI opens a browser for the Slack OAuth install flow and shows the bot name and workspace. For Slack channels, detaching destroys the per-agent Slack bot. The CLI prompts for confirmation before proceeding. Use `--force` to skip the prompt. Example: ``` valet channels attach github-webhook --agent my-reviewer --events pull_request,issue_comment valet channels attach slack --agent my-agent --bot-name my-bot valet channels detach slack --force ``` ### Create a webhook channel ``` valet channels create webhook [name] \ [--agent ] [--org ] \ [--verify ] ``` Verification schemes: `hmac-sha256` (default), `slack`, `stripe`, `svix`, `static-token`, `none`. Key flags: `--secret-name` (name of an existing secret from `valet secrets` to use instead of auto-generating; required for `slack`, `stripe`, and `svix`), `--signature-header` (not used with `slack` or `svix`), `--delivery-key-header`, `--delivery-key-path`, `--prompt`. For `hmac-sha256` and `static-token`, a managed secret is auto-generated if `--secret-name` is omitted. The `slack` scheme implements Slack's Events API signing protocol and handles `url_verification` challenges automatically. Run `valet channels create webhook --help` for full details. The command outputs the **webhook URL**, **signing secret**, and (if applicable) **managed secret name** — always save and report these to the user. ### Create a Slack channel ``` valet channels create slack [name] \ [--agent ] [--org ] \ [--bot-name ] ``` Creates a Slack channel that enables agents to participate in your Slack workspace. Before creating the channel, the CLI automatically checks whether the org has a connected Slack workspace. If not connected, it prompts you to connect via OAuth, opens a browser window for authorization, and polls until the connection is confirmed. The `--bot-name` flag sets the Slack bot display name (default: agent name, resolved server-side). The command outputs the bot name and workspace after setup. Run `valet channels create slack --help` for all flags. ### Create a Telegram channel ``` valet channels create telegram [name] \ [--agent ] ``` Creates a Telegram channel and outputs a deep link (`t.me/...`) for connecting the bot. Run `valet channels create telegram --help` for all flags. ### Create a heartbeat channel ``` valet channels create heartbeat [name] --agent --every 5m ``` Fires a prompt on a fixed interval. Run `valet channels create heartbeat --help` for all flags. ### Create a cron channel ``` valet channels create cron [name] --agent --schedule "every day at 9am" # Or with a raw crontab expression: valet channels create cron [name] --agent --cron "0 9 * * *" ``` Run `valet channels create cron --help` for all flags (`--timezone`, `--prompt`, etc.). ### List, inspect, destroy ``` valet channels [--org ] [--agent ] valet channels info valet channels destroy ``` For Slack channels, `valet channels` shows the workspace name in the listing. Destroying an org-level Slack channel cascades — all per-agent Slack bots are destroyed first, then the org Slack connection is removed. ## Secrets Secrets are credentials (API tokens, service keys, signing secrets) used by connectors and channels at runtime. The agent can invoke tools that depend on secrets but never sees the values — they flow through connectors and channels, not through the agent's environment. Reference a secret in connector or channel configuration with `{{NAME}}` syntax. **NEVER ask the user for secret values within the LLM session.** Direct them to run `valet secrets set NAME=VALUE --org ` in their terminal and wait for confirmation before proceeding. ### Set secrets ``` valet secrets set ... [--org ] [--agent ] [--no-wait] ``` Must specify exactly one scope: `--org` or `--agent` (or run from a linked agent directory). Agent-scoped secrets trigger a redeploy; org-scoped do not. ### {{NAME}} template syntax Use `{{NAME}}` in connector `--env`, `--header`, or `--url` values to reference a secret. Templates are resolved at deploy time and can appear anywhere in a value: ``` --url https://{{DB_HOST}}/api --header "Authorization=Bearer {{API_TOKEN}}" --env SLACK_BOT_TOKEN={{SLACK_BOT_TOKEN}} ``` When directing the user to set secrets, **always tell them what format the value should be in**, including any prefix the service expects. ### List and remove ``` valet secrets [--agent | --org ] valet secrets unset [--agent | --org ] [--force] ``` ## Organizations Organizations own agents, connectors, channels, and secrets. All agents belong to an org. ``` valet orgs create # Create a new org valet orgs # List your orgs valet orgs info # Show org details valet orgs destroy # Delete an org valet orgs members # List members valet orgs invite # Invite a member valet orgs join # Accept an invitation valet orgs leave # Leave an org valet orgs remove # Remove a member valet orgs revoke # Cancel an invitation ``` **Org tips**: The default org is set automatically when you create or join an org — you don't need `--org` on every command. ## Other Commands | Command | Purpose | Help | |---------|---------|------| | `valet run ` | Send a single prompt to an agent; supports `--org` | `valet help run` | | `valet console` | Start an interactive REPL with an agent; supports `--org` | `valet help console` | | `valet exec` | Run a command with secrets injected into its environment | `valet help exec` | | `valet logs [-n ]` | Stream live logs; shows 100 historical lines by default (`-n 0` for live only); supports `--org` | `valet help logs` | | `valet ps` | List agent processes (can show `idle` state); supports `--org` | `valet help ps` | | `valet drains` | Configure log drains (OTLP HTTP) | `valet help drains` | ## Pre-Deploy Verification with valet exec `valet exec` is the **only way** to run local commands with Valet-managed secrets injected. Secrets are stored in the control plane — they are **not** available as shell environment variables. Always test secret-backed commands before deploying. There are two modes: ### Connector mode (no `--`) The first argument is looked up as a connector name. If a `command` connector is found, its secrets are fetched and injected, and the connector's configured command is executed. Extra arguments are appended after the connector's configured args: ``` # Run the "gh" command connector (looks up connector named "gh") valet exec -a my-agent gh pr list # Use linked agent from current directory valet exec gh pr list ``` ### Explicit secrets mode (with `--`) Secret names are passed as a comma-separated positional argument before `--`. The command and its arguments follow after `--`: ``` valet exec [-a ] SECRET[,SECRET...] -- command [args...] ``` Fetches the requested secret values and executes the given command with those secrets injected into the environment. The current process is replaced by the command. ``` # Run gh with GITHUB_TOKEN injected as an env var valet exec -a my-agent GITHUB_TOKEN -- gh pr list # Pass a secret as a CLI argument using {{}} syntax valet exec -a my-agent API_KEY -- curl -H "Authorization: Bearer {{API_KEY}}" https://api.example.com # Multiple secrets in one command valet exec -a my-agent GITHUB_TOKEN,SLACK_TOKEN -- env ``` Flag: `--agent` or `-a`: Agent that owns the secrets (uses linked agent if omitted). Run `valet exec --help` for full details. ### Template syntax for CLI arguments Use `{{SECRET_NAME}}` in command arguments to substitute secret values directly. This is useful for tools that accept credentials as flags or in URLs rather than reading from the environment. Works in both modes. ### Running MCP servers locally To test an MCP server that requires secret-backed environment variables: ``` valet exec -a my-agent SLACK_BOT_TOKEN,SLACK_TEAM_ID -- \ npx -y @modelcontextprotocol/server-slack Without `valet exec`, the MCP server would start without the required tokens and fail to authenticate. ### Why valet exec is required Regular shell commands (`curl`, `npx`, `node`, etc.) cannot access Valet secrets. This will **not** work: ``` # WRONG — $API_KEY is not set in your shell curl https://api.example.com/data?key=$API_KEY # CORRECT — valet exec injects the secret (explicit secrets mode) valet exec -a my-agent API_KEY -- curl https://api.example.com/data?key={{API_KEY}} # OR use connector mode if you have a command connector configured valet exec -a my-agent my-connector-name ``` The same applies to any connector command. If your connector's `--command` or `--args` reference environment variables backed by secrets, test the exact command through `valet exec` before deploying. ## Pre-Deploy Verification with valet exec **Before deploying an agent, locally test every command that requires secrets using `valet exec`.** This catches authentication failures, wrong secret names, malformed URLs, and missing dependencies before they cause the agent to crash in production. ### What to test Any connector command that references secrets in its `--env` flags should be verified locally. Reproduce the exact command the connector will run, wrapping it in `valet exec`: ``` # If the connector is defined as: valet connectors create github-server \ --transport stdio \ --command npx \ --args -y,@modelcontextprotocol/server-github \ --env GITHUB_PERSONAL_ACCESS_TOKEN={{GITHUB_TOKEN}} # Test the underlying command locally: valet exec -a my-agent GITHUB_TOKEN -- \ npx -y @modelcontextprotocol/server-github ``` For remote connectors (SSE/streamable-http) with secret-backed headers or URLs, test with curl: ``` # If the connector uses --header Authorization={{API_TOKEN}} --url https://mcp.example.com/mcp # Test the endpoint is reachable and the token works: valet exec -a my-agent API_TOKEN -- \ curl -s -o /dev/null -w "%{http_code}" -H "Authorization: {{API_TOKEN}}" https://mcp.example.com/mcp ``` Also test any webhook endpoint you plan to call with secrets in the URL: ``` valet exec -a my-agent WEBHOOK_SECRET -- \ curl -X POST https://hooks.example.com/{{WEBHOOK_SECRET}}/notify -d '{"test": true}' ``` ### Verification checklist Before running `valet agents deploy`, confirm: 1. All secrets are set: `valet secrets --agent ` and `valet secrets --org ` list every name referenced by connectors 2. Each connector's command succeeds locally via `valet exec` 3. Any secret-backed URLs resolve and authenticate correctly Do not deploy until all `valet exec` tests pass. ## Common Workflows ### Full agent setup (org-first, preferred) Follow Resource Creation Principles — set up org-scoped resources first, then attach to the agent. 1. Direct the user to set org-scoped secrets in their terminal 2. Add connectors (catalog first, then custom if needed) at the org level 3. Add channels (catalog first for webhooks) at the org level 4. Create the agent and attach org resources: ``` valet secrets set GITHUB_TOKEN= --org acme ``` 2. Add connectors from the catalog at the org level: ``` valet connectors catalog valet connectors create github --org acme ``` 3. If no catalog entry exists, create a custom connector at the org level: ``` valet connectors create mcp-server my-tool --org acme \ --transport stdio \ --command npx \ --args -y,@example/mcp-server \ --env API_KEY={{API_KEY}} ``` 4. Add channels from the catalog at the org level (for webhooks): ``` valet channels create github-webhook --org acme ``` 5. Create the agent and attach org resources: ``` cd my-agent-project valet agents create my-agent --org acme \ --attach-connector github \ --attach-channel github-webhook ``` Or attach after creation: ``` valet connectors attach github --agent my-agent valet channels attach github-webhook --agent my-agent --events pull_request ``` 6. **Verify each connector command locally with `valet exec`** before proceeding: ``` valet exec GITHUB_TOKEN -- \ npx -y @modelcontextprotocol/server-github ``` If this fails (bad token, missing dependency, wrong command), fix it now. 7. Create the channel file at `channels/.md` (see "Writing Channel Files"). 8. Deploy to pick up the channel file: ``` valet agents deploy ``` 9. Validate end-to-end with an interactive test loop (see below). ### One-off agent setup (agent-scoped) For standalone agents that don't need to share resources: 1. Create the agent: ``` cd my-agent-project valet agents create my-agent ``` 2. Set agent-scoped secrets and create agent-scoped connectors: ``` valet secrets set API_KEY= --agent my-agent valet connectors create mcp-server my-tool --agent my-agent \ --transport stdio --command npx \ --args -y,@example/server \ --env API_KEY={{API_KEY}} ``` 3. Create channels, channel files, deploy, and test as above. ### Interactive test loop (mandatory for first-time channel setup) 1. Start streaming logs in the background: ``` valet logs > /tmp/valet-test-.log 2>&1 ``` (Run via Bash with `run_in_background: true`.) 2. Ask the user to trigger the channel (send the email, push to GitHub, etc.). Be specific about what they need to do. 3. Wait for the user to confirm the trigger completed. 4. Stop the background log stream and read the log file. 5. Review the logs: - **Healthy**: Few turns, `mcp_call_tool_start`/`mcp_call_tool_done` pairs, `dispatch_complete`. - **Unhealthy**: Many turns with only built-in tools (agent looping), no `mcp_call_tool_start` (can't find tools), no `dispatch_complete` (timeout/stuck). 6. If problems, fix SOUL.md or channel prompt, redeploy, and repeat. Each change triggers a full VM reboot — wait for it to complete and stream fresh logs before evaluating. ### Teardown (order matters) Detach org resources first, then destroy agent-scoped resources, then the agent: ``` # Detach org resources (they remain available for other agents) valet connectors detach github --agent my-agent valet channels detach github-webhook --agent my-agent # Destroy agent-scoped resources valet channels destroy valet connectors destroy # Destroy the agent valet agents destroy ``` ### Debugging ``` valet agents info my-agent # Check state, channels, connectors valet agents info my-agent --org my-org # Specify org when looking up by name valet logs --agent my-agent # Stream live logs (last 100 lines, then live) valet logs --agent my-agent -n 0 # Live logs only, skip history valet ps restart -a my-agent # Restart without redeploying valet ps restart -a my-agent --org my-org # Restart with explicit org ``` ## Designing a New Agent **When to use**: The user asks to "build an agent", "create an agent from scratch", "design an automation", or provides skill/MCP URLs to assemble into an agent. Be curious, confirmatory, and opinionated. Suggest improvements, anticipate edge cases, and help refine the idea. **7 questions max, fewer if sufficient.** ### Step 1: Parse the user's input The user's prompt may contain a description of what they want and/or URLs pointing to skills, tools, or MCP servers. Extract both. | URL type | Pattern | How to fetch | |----------|---------|--------------| | GitHub SKILL.md | `github.com/.../SKILL.md` | Convert to `raw.githubusercontent.com/...`. Explore parent dir for siblings. | | GitHub directory | `github.com/.../tree/...` | Fetch listing. Look for SKILL.md, README.md. | | skills.sh listing | `skills.sh/` | Fetch page for description + source repo URL. Follow source link. | | MCP server README | npmjs.com, GitHub, PyPI | Extract server name, tools, config/install instructions. | For each URL: fetch with `WebFetch`, identify type, discover the full package, extract name/description/tools/dependencies/config. Check if equivalent tools already exist via `ToolSearch` — **always prefer existing tools**. If no URLs, proceed directly to the interview. ### Step 2: Interview Use `AskUserQuestion` for structured choices, direct conversation for open-ended questions. Track question count — stop and build once you have enough. **Important: When using `AskUserQuestion`, the `question` field must be a complete, clear question sentence that ends with a question mark.** The user sees this question text prominently — it's the primary thing they read to understand what you're asking. Bad: "Trigger" or "Trigger type". Good: "How should this agent be triggered?" Option labels should be short (1-5 words) with the description providing detail. **Question 1 — Confirm understanding + trigger type:** Present a concise summary of the agent you will build based on what you understood from the initial prompt: - If URLs provided: present what you fetched — names, descriptions, capabilities and combine with any instructions to suggest the agent you will build. Ask about the trigger if not already clear: - Webhook — event-driven (email, push, form submission) - Prompt — user sends a message via `valet run` or console **Questions 2–6 — Adaptive deep-dive** Be opinionated: suggest better approaches, flag automatable manual steps, raise obvious edge cases. **Stop early** if 1–3 questions gives a clear picture of the user intent. Some example topics you might need to understand better are: * Tool/skill discovery (see below) — skip if URLs already provided the tools * Workflow clarification — decision points, branching logic * Output format — where/how results are delivered (Slack channel, email, file, etc.) * Edge cases and guardrails — suggest failure modes, ask about constraints #### Tool discovery When the user mentions a capability not covered by imported URLs, search in this order (per Resource Creation Principles): catalog (`valet connectors catalog`) → existing org connectors → `ToolSearch` for local MCP tools → `WebFetch` on `skills.sh` → `WebSearch` on PulseMCP/Smithery. If no match, the agent can use built-in tools or it remains a manual step. ### Step 3: Present the plan and confirm After the interview and any tool/skill discovery, **stop and present a clear plan to the user before building anything**. The plan sets expectations about what will happen on their machine, what the agent will do automatically, and what the user will need to do manually. This gives the user a chance to change direction before any work begins — especially important when external setup (API credentials, third-party configuration, cloud consoles) is involved. Present the plan in this format: ``` Here's the plan for your agent: **What I'll create on your machine:** - A project directory with SOUL.md defining the agent's identity and behavior - [Channel files for triggers, if applicable] - [Skill files for usage, if applicable] **What I'll set up on the Valet platform:** - The agent itself (registered and deployed in org ) - [Org connectors: ] - [Org channels: ] - [Agent-scoped resources, if any: ] **What you'll need to do:** - [Set secrets in your terminal (org-scoped by default): ] - [External setup: ] - [Any other manual steps the user must perform] [If external setup is complex, call it out explicitly: "The integration requires some setup on your end — . If that feels like too much, we could instead."] Want to proceed with this plan, or would you like to adjust anything? ``` **Guidelines for the plan:** - **Be specific about user obligations.** Don't say "set up API credentials" — say "create a Slack app at api.slack.com, add the `chat:write` scope, install it to your workspace, and copy the Bot User OAuth Token." The user needs to know what they're signing up for. - **Flag complexity honestly.** If an integration requires navigating a cloud console, setting up OAuth, configuring webhooks on a third-party service, or any multi-step external process — say so clearly. This is often where users decide to change approach. - **Offer alternatives when they exist.** If the user's goal can be achieved a simpler way (different service, fewer integrations, manual step instead of automation), mention it. - **Wait for explicit confirmation.** Do not proceed to Step 4 until the user says yes. If they want changes, revise the plan and present it again. ### Step 4: Generate the agent 1. Create the project directory: `mkdir -p /channels` 2. Write `SOUL.md` following the "Writing SOUL.md" guidance below 3. Write channel files if the agent uses webhooks (see "Writing Channel Files") 4. Write skill files if documenting connector usage (see "Writing Skill Files") 5. Run the validation checklist: - [ ] SOUL.md exists with non-empty Purpose and Workflow - [ ] Guardrails has both Always and Never subsections - [ ] No hardcoded IDs that should be ``s - [ ] Channel files have Scope section if webhook-driven - [ ] Channel files include webhook payload location instruction - [ ] No secrets or API keys in any file - [ ] AGENTS.md written as the last step (see "Writing AGENTS.md") 6. Direct the user to set secrets at the org level (preferred) or agent level: ``` valet secrets set SECRET_NAME= --org ``` 7. Set up connectors — **check the catalog first**: ``` valet connectors catalog valet connectors create --org ``` Only create custom connectors if no catalog entry exists: ``` valet connectors create mcp-server --org \ --transport stdio \ --command --args \ --env KEY={{SECRET_NAME}} ``` 8. Set up channels — **check the catalog first** for webhook channels: ``` valet channels catalog valet channels create --org ``` Or create directly: ``` valet channels create webhook --agent ``` 9. Create and deploy the agent, attaching org resources: ``` cd valet agents create [name] --org \ --attach-connector \ --attach-channel ``` 10. **Verify each connector command locally with `valet exec`:** ``` valet exec -a SECRET_NAME -- ``` Fix any failures before proceeding. 11. Deploy to pick up channel files: `valet agents deploy` 12. If the agent has channels, run the interactive test loop (see "Interactive test loop" under Common Workflows). 13. **Last step**: Write `AGENTS.md` in the project root (see "Writing AGENTS.md"). This summarizes the full setup for future developers. ### Design edge cases | Case | Handling | |------|----------| | No URLs, pure description | Standard confirmatory interview. | | URLs only, no description | Present imported capabilities, ask what the agent should do with them. | | Mix of URLs and description | Fetch URLs first, then interview with imported context. | | URL unreachable | Report error. Ask for alternative URL or direct paste. | | Name collision | Run `valet agents` to check. Ask to choose a different name. | | MCP server needs API keys | Document in SOUL.md Environment Requirements. Direct user to `valet secrets set`. Never ask for actual values. | ## Learning from the Current Session **When to use**: The user says "save this as an agent", "capture this workflow", "learn from this session", or "make this repeatable". ### Step 1: Locate the session log 1. Convert the current working directory to the Claude projects path: `~/.claude/projects/-/` Example: `/Users/me/Developer/my-project` → `~/.claude/projects/-Users-me-Developer-my-project/` 2. Find the active session log: ```bash ls -t ~/.claude/projects/-/*.jsonl | head -1 ``` ### Step 2: Parse the session Read the JSONL file with the Read tool. Each line is a JSON object. Extract: - **User prompts**: Entries where `type` is `"user"` and `message.content` is a string. Capture the text (truncate to 500 chars each). - **MCP tool usage**: Entries where `type` is `"assistant"` and `message.content` contains objects with `type: "tool_use"`. If the tool `name` starts with `mcp__`, split on `__` to get server and tool name (e.g., `mcp__slack__post_message` → server: `slack`, tool: `post_message`). - **Skill invocations**: Tool calls where `name` is `"Skill"` — extract `input.skill` for the skill name. - **Built-in tools**: All other tool call names (Read, Write, Edit, Bash, Glob, Grep, etc.). - **Corrections**: User messages containing "no,", "don't", "instead", "actually", "wrong", "not that", "change", "stop", "undo", "revert" — these indicate the user changed direction. - **Stop point**: Stop parsing when you encounter a Skill tool call with `input.skill` matching the learn/capture trigger. Exclude everything after. For large sessions (>20 user prompts): sample the first 3 and last 3 user prompts to keep context manageable. Also check `~/.claude/projects//sessions-index.json` for `summary` and `firstPrompt` fields matching the session ID (derived from the JSONL filename). If the session is empty (no user prompts besides the learn trigger), inform the user and stop. ### Step 3: Present analysis and interview Show the analysis: ``` Session Analysis: - Objective: [summary from first prompt or sessions-index] - User prompts: N messages - MCP tools used: [server names + tool counts] - Skills invoked: [names] - Built-in tools: [names] - Corrections detected: N ``` Ask clarifying questions (skip any with obvious answers from the session): 1. **Trigger**: What should invoke this agent? Propose a draft based on the first user prompt — webhook or prompt? 2. **Scope**: Does the extracted objective + tool list capture the full scope, or should it be narrowed/expanded? 3. **Corrections**: Surface each detected correction and ask whether the agent should always follow the corrected approach. 4. **Name**: Propose a kebab-case name (<64 chars). Let the user confirm. ### Step 4: Present plan and confirm Follow the same confirmation flow as "Designing a New Agent" Step 3. Present what will be created, what platform resources will be set up, and what the user needs to do. Wait for confirmation. ### Step 5: Generate the agent Follow the same generation flow as "Designing a New Agent" (Step 4 above), but source content from the session: - **Purpose**: From user prompts + corrections + interview refinements - **Workflow phases**: From the chronological sequence of tool calls, grouped by logical purpose (e.g., "Data Collection", "Analysis", "Post Results") - **Guardrails Always**: From successful session patterns and user preferences - **Guardrails Never**: From corrections, observed mistakes, and domain norms - Replace session-specific values with ``s - Genericize Q&A exchanges as guidance (e.g., "if ambiguous, prefer X") - **Last step**: Write `AGENTS.md` in the project root (see "Writing AGENTS.md") ### Edge cases | Case | Handling | |------|----------| | Empty session | Inform user: "This session is empty — nothing to capture." Stop. | | No MCP tools used | Skip connector creation. Agent uses only built-in tools. | | Long session (>500 entries) | Sample first 3 + last 3 user prompts. Summarize tool usage by frequency. | | Many corrections | Present each one. Let the user decide which to encode as guardrails. | ## Writing SOUL.md SOUL.md defines the agent's identity and behavior. It's the only required file. ### Template ```markdown # ## Purpose <2-3 sentences: what this agent does and why. Name the specific tools, inputs, and outputs.> ## Personality <3-4 traits matching the agent's domain. Skip for simple utility agents.> - ****: ## Workflow ### Phase 1: 1. 2. ### Phase 2: 1. ## Guardrails ### Always - ### Never - ``` ### Optional sections Add as needed: **Target Channel**, **Environment Requirements**, **Webhook Scope Rule**, **Skills Used**, **MEMORY.md Format**. ### Synthesis rules - **Purpose**: Specific what + why. Name inputs, outputs, and tools. Good: "Monitors YouTube channel X for new episodes, downloads transcripts, and posts digests to #channel on Slack." Bad: "Processes data." - **Workflow**: Concrete numbered steps with actual tool names. Group into phases by logical purpose. - **Guardrails Always**: From positive patterns the agent must consistently follow. - **Guardrails Never**: From corrections and constraints the agent must avoid. - **Placeholders**: Replace user-specific values (IDs, URLs, keys) with ``. ### Command connector references in SOUL.md When the agent uses a command connector, the SOUL.md workflow must reference the **connector name** as the command — not the npm package name, underlying transport, or `npx` invocation. The connector name is the CLI command the agent types, and it is the only name on the agent's PATH. Good: `Run agentmail inboxes list to verify the CLI is connected.` Bad: `Run npx agentmail-cli inboxes list` or `Run agentmail-cli inboxes list` Using the wrong name either bypasses secret injection (calling npx directly) or fails entirely (command not found). When creating connectors, always name them after the CLI command (see naming rule in the Connectors section). ### Common mistakes - Empty or vague Purpose — always name specific inputs, tools, and outputs - Missing Workflow — Purpose without steps leaves the agent guessing - Hardcoded values that should be ``s - No scope boundary for webhook agents (see Writing Channel Files) - Using the wrong command name for command connectors — the connector must be named after the CLI command (e.g., `agentmail` not `agentmail-cli`), and SOUL.md must reference that same name ## Writing Channel Files Channel files tell the agent what to do when a message arrives. They are instructions TO the agent, written as direct imperatives. ### Webhook payload location (critical) The JSON webhook payload is appended inline after the channel file in the user message. Every channel file **must** start with: ``` The JSON webhook payload is appended directly after these instructions in the user message. Parse it inline — do not fetch, list, or search for the payload elsewhere. Do NOT use tools to read the payload. ``` Without this, agents waste turns searching for the payload with tool calls. ### Structure 1. **Payload location** — the instruction above 2. **What happened** — describe the event 3. **What to extract** — which payload fields identify the transaction (IDs, refs) 4. **Scope boundary** — all actions must be scoped to those identifiers 5. **What to do** — step-by-step processing instructions ### Example ```markdown # New Email Received The JSON webhook payload is appended directly after these instructions in the user message. Parse it inline — do not fetch, list, or search for the payload elsewhere. Do NOT use tools to read the payload. You received a webhook for a single new email. ## Scope Extract the `thread_id` from the payload. All actions are scoped to this thread. Do not list, read, or act on any other threads. ## Steps 1. Extract `thread_id`, `from_`, `subject`, and `text` from the payload. 2. [... task-specific steps ...] ``` ### Reinforcing scope in SOUL.md For webhook-driven agents, add to SOUL.md: ```markdown ## Webhook Scope Rule When you receive a webhook, your scope of work is defined by the identifiers in the payload. Use any tools to fully understand and act on that specific content, but do not act on unrelated content. ``` ## Writing valet.yaml `valet.yaml` is the agent manifest. It enables 1-click deployment through the dashboard setup flow. **Do not generate `valet.yaml` automatically.** Only write it when the user explicitly asks for it — trigger phrases include "yaml", "deploy button", "dashboard setup", "1-click deploy", or "setup on web". ### Catalog items only The manifest only supports connectors and channels that exist in the Valet catalog. Custom connectors and channels cannot be represented in `valet.yaml` — the dashboard setup flow looks up each `catalog` value and fails if the entry doesn't exist. **Before writing valet.yaml**, run `valet connectors catalog` and `valet channels catalog` to check which of the agent's connectors and channels are in the catalog. - **Mix of catalog and custom resources**: Include only the catalog items in `valet.yaml`. Document the custom resources in `AGENTS.md` with CLI setup instructions. Users will configure catalog resources through the dashboard flow and create custom resources manually with the CLI afterward. - **Only custom resources**: Still write `valet.yaml` with the four required top-level fields and omit the `connectors` and `channels` arrays. The dashboard uses this metadata to display the agent's name, description, and category. - **Missing catalog entries**: If a connector or channel should be in the catalog but isn't, direct the user to email support@valet.dev to request it be added. ### Template ```yaml name: display_name: description: >- category: connectors: - catalog: description: >- slot_descriptions: :