Reference

CLI reference

On this page

The valet command line tool publishes and manages your organization's skills, artifacts, apps and agents. Coding agents run it for you when they have a terminal, and you can run it yourself. See Skills for creating, publishing, cloning, deleting and attaching skills.

Install

On macOS or Linux:

curl -fsSL https://valet.dev/install.sh | sh

In Windows PowerShell:

irm https://valet.dev/install.ps1 | iex

Then run valet auth login to sign in. On a new machine, run valet setup instead. It signs you in, creates an organization if you have none, installs the Valet plugin for Claude Code, and offers to create and deploy a first agent. valet update installs the latest version of the CLI.

Git 2.32 or later must be on your PATH for valet deploy, valet agents create, valet setup, and the valet skills commands that create, publish or clone skills.

Valet refuses some commands from CLIs older than 0.1.89 with cli.upgrade_required. Run valet update to fix it.

Commands

The reference below is the CLI's own help text for the current release. Run valet <command> --help to see the same text for the version you have installed.

valet agents

List agents

valet agents [flags]

List, create, rename, share, and destroy agents, and set who can open them.

Running "valet agents" with no subcommand lists agents in the default organization. Use --org to list agents in a different organization. The default org is set automatically when you create or join an org.

Deploying is a top-level command: run "valet deploy" from the agent directory.

-o, --org string
Org to list agents for
$ valet agents
org-agent

$ valet agents --org other-org
my-agent

valet agents access

Show or set who can open an agent's address

valet agents access <name> [public|private|password] [flags]

Show or set who can open an agent at its address.

With no mode, prints the agent's access mode and address. With a mode, moves the agent to it:

  private   Members of the owning org, after a Valet login. Every
            agent is private when it is created.
  password  Org members sign in with Valet, or any visitor enters the
            agent password.
  public    Anyone with the link can open it.

Password mode prompts for a hidden password; pass --password in scripts or agent runs where stdin is not a terminal. Switching away from password mode clears the stored password. Any change signs every current visitor out.

An agent can hold connectors that reach the org's systems, so a visitor who opens it can use what those connectors let it do. Public and password access are off until the Valet server enables them. While they are off, the server's refusal is printed and the command exits 1.

-o, --org string
Org that owns the agent
--password string
Password to set (password mode; prompts with hidden input when omitted)

Example

$ valet agents access support
support access: private
URL: https://support.acme.valet.run

$ valet agents access support private
Setting support access to private in acme org... done
Only members of the owning org can open this agent, after a Valet login.

valet agents create

Create an agent and deploy it

valet agents create [name] [flags]

Create a new agent and deploy it.

The source must contain a SOUL.md file. By default, the current directory is used. Pass --from to use a local directory, Git URL, or catalog reference as the source.

A local source deploys the way valet deploy does: the CLI creates a push, commits the directory on top of the agent's source, pushes that commit with Git, and publishes it. Git 2.32 or later must be on your PATH; the CLI checks before it creates the agent. The commit holds every regular file under the directory, walked recursively. Only .git and .valet are skipped, and there is no ignore file, so keep build output and dependency trees out of it. Any single file over 25 MiB is refused before anything is pushed. Run valet deploy --help for the details.

Sources for --from:
  Local path:    --from . or --from ./my-agent
  Git URL:       --from github.com/user/repo
  Catalog ref:   --from catalog:code-reviewer

When --from points to a Git URL or catalog reference, the repo is cloned and the project files are scaffolded to a local directory (default ./<name>/, override with --path).

When the source contains a valet.yaml manifest, it is validated before proceeding. If the manifest declares a channel with catalog: slack, the CLI checks the org's Slack connection, prompts for a bot name, and creates the Slack channel inline. The --attach-connector and --attach-channel flags name org-scoped resources to attach to the agent after creation.

If the manifest declares connectors or channels the agent does not have yet, the deploy stops and lists them. The agent exists and the directory is linked by then: attach them and run valet deploy, or run valet deploy --allow-unsatisfied to deploy without them.

The agent name is optional — if omitted, the server generates one. After deploying, waits for the agent runtime to become ready. Use --no-wait to skip the readiness check.

When --org is not specified, the default org is used. The default org is set automatically when you create or join an org.

--attach-channel stringSlice
Org channel to attach (repeatable)
--attach-connector stringSlice
Org connector to attach (repeatable)
--from string
Source: local path, Git URL, or catalog:name
--no-wait
Skip waiting for the agent to become ready
-o, --org string
Org that owns the agent
--path string
Where to scaffold project (default: ./<name>/)

Example

$ valet agents create my-agent
Creating agent... done, my-agent agent
Linking directory... done
Reading files... done, 4 files
Creating push for my-agent agent... done
Fetching source... done
Pushing source... done
Deploying my-agent agent... done, v1
Waiting for agent to start... done

$ valet agents create my-reviewer --from catalog:code-reviewer --org acme
Fetching catalog:code-reviewer... done
Creating agent... done, my-reviewer agent in acme org
Deploying my-reviewer agent in acme org... done, v1
Scaffolding ./my-reviewer... done
Linking directory... done
Waiting for agent to start... done

$ valet agents create my-bot --org acme --attach-connector github --attach-channel gh-webhook
Creating agent... done, my-bot agent in acme org
Linking directory... done
Attaching connector github... done
Attaching channel gh-webhook... done
Reading files... done, 4 files
Creating push for my-bot agent in acme org... done
Fetching source... done
Pushing source... done
Deploying my-bot agent in acme org... done, v1
Waiting for agent to start... done

$ valet agents create support-bot --from ./support-source --org acme
Creating agent... done, support-bot agent in acme org
Linking directory... done
Checking Slack connection... connected (My Workspace)
Bot name [support-bot]: support-bot
Creating Slack channel... done, support-bot-slack
Reading files... done, 5 files
Creating push for support-bot agent in acme org... done
Fetching source... done
Pushing source... done
Deploying support-bot agent in acme org... done, v1
Waiting for agent to start... done

valet agents destroy

Destroy an agent

valet agents destroy <name> [flags]

Permanently destroy an agent and all its releases.

This action cannot be undone.

The command asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

-o, --org string
Org that owns the agent
--yes
Skip the confirmation prompt

Example

$ valet agents destroy my-agent
This destroys my-agent and all its releases. It cannot be undone. Continue? (y/N) y
Destroying my-agent agent in acme org... done

$ valet agents destroy my-agent --yes
Destroying my-agent agent in acme org... done

valet agents info

Show agent details

valet agents info [name] [flags]

Show detailed information about an agent.

Displays the agent's org, its role in the org, current release, process state, channels, connectors, and effective environment. Environment rows show each env var's kind and scope; plain values are shown inline, secret values are masked. The agent is determined by the positional argument, the --agent flag, or the linked agent in the current directory.

-a, --agent string
Agent to show info for (uses linked agent if omitted)
-o, --org string
Org that owns the agent

Example

$ valet agents info my-agent
=== Agent: my-agent (acme org)
  org:        acme-corp
  role:       Developer
  release:    v3
  process:    up for 3h22m
  channels:   slack-channel, support-webhook
  connectors: github-mcp, linear-mcp
  environment:
    GITHUB_TOKEN  secret  ******     agent (overrides org)
    REGION        plain   us-east-1  org (inherited)

valet agents rename

Rename an agent

valet agents rename <new-name> [flags]

Rename an agent.

The new name follows the same validation as 'agents create': it must be a DNS label (lowercase letters, digits, hyphens) and not a reserved word. Renaming is safe at any point in an agent's lifecycle — webhook URLs are keyed by channel UUID, Slack and runtime routing are keyed by agent UUID, and the dashboard URL slug redirects on rename.

An agent rename does not rename or recycle channel routes. Webhook and MCP URLs keep their generated handles and continue to use channel UUIDs.

The agent to rename is determined by --agent or, when omitted, the linked agent in the current directory. If a .valet/config.json above the current directory points at the renamed agent, it is updated in place to the new name.

-a, --agent string
Agent to rename (uses linked agent if omitted)
-o, --org string
Org that owns the agent

Example

$ valet agents rename better-name --agent my-agent
Renaming my-agent agent to better-name... done

$ cd ./my-agent && valet agents rename better-name
Renaming my-agent agent in acme org to better-name... done
Updating .valet/config.json... done

valet agents role

Give an agent a role in its org

valet agents role [agent] <admin|developer> [flags]

Keep an agent's org role at Developer.

Agents have the Developer role. The server refuses requests to assign Admin. The admin argument remains accepted so the server can report that refusal.

The agent is determined by the positional argument, the --agent flag, or the linked agent in the current directory.

Requires the Admin role.

-a, --agent string
Agent to give the role (uses linked agent if omitted)
-o, --org string
Org that owns the agent

Example

$ valet agents role fixer developer
fixer is now a Developer of acme.

valet agents share

Share an agent by email

valet agents share <name> <email>... [flags]

Share an agent with one or more email addresses.

Each address gets an email with a link that opens the agent without a Valet account of its own — possession of the mailbox is the credential. The link is a bearer credential: anyone holding the email can open the agent, so forwarding it forwards access. Remove a person's access with "valet agents unshare".

An agent can hold connectors that reach the org's systems, so a person you share it with can use what those connectors let it do.

Sharing an address that already has a live share re-sends its existing link rather than minting a new one. --message attaches a short note the recipient reads before they click through.

Deadlines are optional and never default. --expires-in stops the link working a fixed time after it is sent; --expires-after-open stops it a fixed time after the recipient first opens it. Durations take forms like 7d, 48h, or 90m ("d" means 24 hours) or a Go duration like 1h30m0s.

Agent sharing is off until the Valet server enables it. While it is off, the server's refusal is printed and the command exits 1.

--expires-after-open string
Stop the link working this long after it is first opened (e.g. 48h); default: never
--expires-in string
Stop the link working this long after it is sent (e.g. 7d, 48h); default: never
--message string
A short note the recipient reads before they click through (<= 500 characters)
-o, --org string
Org that owns the agent

Example

$ valet agents share support alice@example.com bob@example.com --message "Try it out"
Sharing support agent with 2 people in acme org... done
Anyone with a share email can open the agent — forwarding it forwards access.
Remove a person with "valet agents unshare support <email>".

$ valet agents share support alice@example.com --expires-in 7d

valet agents shares

List who an agent is shared with by email

valet agents shares <name> [flags]

List an agent's live and expired email shares.

STATE is "invited" for a share nobody has opened yet, "opened" once the recipient has, and "not delivered" when the most recent send attempt failed. OPENED is how long ago the recipient last opened the link. EXPIRES shows the remaining deadline and any window after first open. "-" means unset. Revoked shares never appear here. When the server has sharing by email off, the list still prints, followed by a line saying so.

Use "valet agents share" to add a share or re-send an existing one, and "valet agents unshare" to remove one. While the Valet server has agent sharing off, "share" prints its refusal and exits 1.

-o, --org string
Org that owns the agent

Example

$ valet agents shares support
EMAIL               STATE    OPENED  EXPIRES
alice@example.com   opened   3d ago  -
bob@example.com     invited  -       in 6d

valet agents unshare

Remove one person's access to a shared agent

valet agents unshare <name> <email|share-id> [flags]

Revoke an agent share, so the address's link stops working.

Name the share by the address it went to or by its share ID. The revocation is permanent: a revoked share is never resurrected by sharing the address again, which starts a new share instead. The address stops seeing the agent once the change replicates to the gateway, within seconds.

-o, --org string
Org that owns the agent

Example

$ valet agents unshare support alice@example.com
Removing alice@example.com from support agent in acme org... done

valet apps

List apps

valet apps [flags]

List, create, rename, and destroy apps.

An app is a Procfile application built with buildpacks and served over HTTPS at a name-derived hostname. Create an app, then run "valet deploy" from the linked directory to build and run it. The URL is live (failing closed) before the first deploy.

Running "valet apps" with no subcommand lists apps in the default organization. Use --org to list apps in a different organization. Share an app by email with "valet apps share", and list or remove shares with "valet apps shares" and "valet apps unshare". Let a script call a private app with a service token from "valet apps token".

-o, --org string
Org to list apps for
$ valet apps
NAME      URL                                     VERSION  ACCESS
my-app    https://my-app.acme.valet.run           3        private

valet apps access

Show or change an app's access mode

valet apps access <name> [public|private|password] [flags]

Show or change an app's access mode.

Private admits members of the owning org after Valet login, and is the default for a new app. Password also admits visitors with the password. Public admits anyone.

Omit the mode to show current access. Password mode uses a hidden prompt on a terminal, or --password in scripts. Access changes need no deploy.

-o, --org string
Org that owns the app
--password string
Password for password mode; no default

Example

$ valet apps access reports
$ valet apps access reports public --org acme
$ valet apps access reports password --password example --org acme

valet apps create

Create an app

valet apps create [name] [flags]

Create a new app.

The app's name becomes the first label of its hostname. If the name is omitted, the server generates one. The URL is live immediately and fails closed until the first deploy builds and runs the app. The current directory is linked to the new app so "valet deploy" builds and releases it.

The app name is optional — if omitted, the server generates one. App, site, and agent names share one namespace within an org: an app cannot take the name of an existing agent or site.

When --org is not specified, the default org is used. The default org is set automatically when you create or join an org.

-o, --org string
Org that owns the app

Example

$ valet apps create my-app
Creating app... done, my-app
Linking directory... done
URL: https://my-app.acme.valet.run
Access: private
Run "valet deploy" to build and run this directory.

valet apps destroy

Destroy an app

valet apps destroy <name> [flags]

Permanently destroy an app and all its releases.

The app's hostname stops serving within seconds. A later app or site in the same organization may reuse its name and hostname. This action cannot be undone.

The command asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

-o, --org string
Org that owns the app
--yes
Skip the confirmation prompt

Example

$ valet apps destroy my-app
This destroys my-app and all its releases. It cannot be undone. Continue? (y/N) y
Destroying my-app app in acme org... done

$ valet apps destroy my-app --yes
Destroying my-app app in acme org... done

valet apps rename

Rename an app and its hostname

valet apps rename <name> <new-name> [flags]

Rename an app and move it to the new name-derived hostname.

The old hostname stops serving and does not redirect. A later app or site in the same organization may reuse the old name and hostname. Generated channel hostnames are unaffected.

-o, --org string
Org that owns the app

Example

$ valet apps rename ledger-api accounting-api --org acme
Renaming ledger-api app in acme org to accounting-api... done, https://accounting-api.acme.valet.run

valet apps share

Share an app by email

valet apps share <name> <email>... [flags]

Share an app with one or more email addresses.

Each address gets an email with a link that opens the app without a Valet account of its own — possession of the mailbox is the credential. The link is a bearer credential: anyone holding the email can open the app, so forwarding it forwards access. Remove a person's access with "valet apps unshare".

An app runs server code, so a person you share it with can use everything the app does, including anything that changes data.

Sharing an address that already has a live share re-sends its existing link rather than minting a new one. --message attaches a short note the recipient reads before they click through.

Deadlines are optional and never default. --expires-in stops the link working a fixed time after it is sent; --expires-after-open stops it a fixed time after the recipient first opens it. Durations take forms like 7d, 48h, or 90m ("d" means 24 hours) or a Go duration like 1h30m0s.

App sharing is off until the Valet server enables it. While it is off, the server's refusal is printed and the command exits 1.

--expires-after-open string
Stop the link working this long after it is first opened (e.g. 48h); default: never
--expires-in string
Stop the link working this long after it is sent (e.g. 7d, 48h); default: never
--message string
A short note the recipient reads before they click through (<= 500 characters)
-o, --org string
Org that owns the app

Example

$ valet apps share reports alice@example.com bob@example.com --message "Q3 numbers"
Sharing reports app with 2 people in acme org... done
Anyone with a share email can open the app — forwarding it forwards access.
Remove a person with "valet apps unshare reports <email>".

$ valet apps share reports alice@example.com --expires-in 7d

valet apps shares

List who an app is shared with by email

valet apps shares <name> [flags]

List an app's live and expired email shares.

STATE is "invited" for a share nobody has opened yet, "opened" once the recipient has, and "not delivered" when the most recent send attempt failed. OPENED is how long ago the recipient last opened the link. EXPIRES shows the remaining deadline and any window after first open. "-" means unset. Revoked shares never appear here. When the server has sharing by email off, the list still prints, followed by a line saying so.

Use "valet apps share" to add a share or re-send an existing one, and "valet apps unshare" to remove one. While the Valet server has app sharing off, "share" prints its refusal and exits 1.

-o, --org string
Org that owns the app

Example

$ valet apps shares reports
EMAIL               STATE    OPENED  EXPIRES
alice@example.com   opened   3d ago  -
bob@example.com     invited  -       in 6d

valet apps token

Manage service tokens for an app

valet apps token [command]

Mint, list, and revoke service tokens for an app.

A service token lets a script, daemon, or CLI call a private app. Send it as "Authorization: Bearer <token>". The app sees the request as a visitor of kind "service" that names the token. The plaintext value is shown exactly once, at mint time.

When no --app flag is provided, uses the linked app in the current directory.

--app string
App that owns the token (uses linked app if omitted)
-o, --org string
Org that owns the app

Example

$ valet apps token mint ci --app billing
$ valet apps token list --app billing
$ valet apps token revoke ci --app billing

valet apps token list

List service tokens for an app

valet apps token list [flags]

List an app's service tokens.

Shows each token's name, expiry, creation date, and the member who minted it. EXPIRES is "never" for a token with no expiry and "expired" for one whose expiry has passed. Revoked tokens never appear. Plaintext token values are never shown after minting.

When no --app flag is provided, uses the linked app in the current directory.

--app string
App that owns the token (uses linked app if omitted)
-o, --org string
Org that owns the app

Example

$ valet apps token list --app billing
=== billing app tokens (acme org)
NAME    EXPIRES                   CREATED       BY
ci      Feb 9, 2027 12:00 PM UTC  Nov 11, 2026  jo@acme.com
worker  never                     Nov 11, 2026  jo@acme.com

valet apps token mint

Mint a service token for an app

valet apps token mint <token-name> [flags]

Mint a service token for an app.

A service token lets a script, daemon, or CLI call a private app. Send it as "Authorization: Bearer <token>". The app sees the request as a visitor of kind "service" that names this token.

The token is printed exactly once; store it securely. The value goes to stdout and the progress lines to stderr, so a script can capture the value.

When no --app flag is provided, uses the linked app in the current directory.

--expires string
Expiry as a Go duration (e.g. 720h) or an RFC 3339 timestamp (default: never)
--app string
App that owns the token (uses linked app if omitted)
-o, --org string
Org that owns the app

Example

$ valet apps token mint ci --app billing --expires 2160h
Minting token for billing app in acme org... done, ci
  expires: Tue Feb 9, 2027 12:00 PM UTC

This token will not be shown again. Store it securely:
vsvc_3q2-7wEAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRo

valet apps token revoke

Revoke a service token for an app

valet apps token revoke <token-name> [flags]

Revoke a service token for an app.

Revocation is immediate and permanent: the app refuses the token on its next request. Mint a new token to restore access.

When no --app flag is provided, uses the linked app in the current directory.

--app string
App that owns the token (uses linked app if omitted)
-o, --org string
Org that owns the app

Example

$ valet apps token revoke ci --app billing
Revoking token ci for billing app in acme org... done

valet apps unshare

Remove one address's access to a shared app

valet apps unshare <name> <email> [flags]

Revoke an app share, so the address's link stops working.

The revocation is permanent: a revoked share is never resurrected by sharing the address again, which starts a new share instead. The address stops reaching the app once the change replicates to the gateway, within seconds.

-o, --org string
Org that owns the app

Example

$ valet apps unshare reports alice@example.com
Removing alice@example.com from reports app in acme org... done

valet auth

Manage authentication

Log in, log out, and check authentication status.

Valet uses OAuth device flow for authentication. Credentials are stored locally in the Valet config directory.

valet auth login

Log in to Valet

valet auth login [flags]

Authenticate with Valet using the OAuth device flow.

Opens a browser to complete login. If the browser cannot be opened automatically, the URL and confirmation code are printed for manual entry.

Example

$ valet auth login
Open this URL to log in: https://auth.valet.dev/verify?code=ABCD-1234
Confirmation code: ABCD-1234
Waiting for browser login...
Logged in.

valet auth logout

Log out of Valet

valet auth logout [flags]

Log out of Valet and revoke the stored credentials.

Revokes the access token with the auth provider and deletes locally stored credentials. Safe to run when already logged out.

Example

$ valet auth logout
Logged out.

valet auth whoami

Show the current user

valet auth whoami [flags]

Display the currently authenticated user.

Shows the email address and name associated with the stored credentials. Also surfaces your default org and any linked project so you can see what "valet <command>" will target. If the access token has expired, whoami transparently refreshes it before reporting. Exits with code 1 if not logged in or if the refresh token is no longer valid.

Example

$ valet auth whoami
Logged in as: alice@example.com (Alice Smith)
Default org: acme (from ~/.config/valet/config.json)
Linked project: /Users/alice/src/reviewer-agent
  Agent: reviewer
  Org:   acme

valet builds

List and show app builds

valet builds [<app>] [flags]

List an app's builds, newest first, or show one build.

"valet deploy" starts a build for an app and follows it. "valet deploy --no-wait" prints the build's id and returns; "valet builds show <id>" reads that build later, and --follow follows it as deploy would.

Run without a subcommand, builds lists the app's newest builds to stdout: each build's id, status, the release it made, its commit, and when it was created. A build that started says when, and one that settled says when and how long its attempt took. A build on a later attempt names it, and a failed or superseded build's error follows on its own line. Status is pending, running, succeeded, failed, or superseded, which means a newer deploy replaced the build. The positional argument, --app, or the directory's link names the app.

-a, --agent string
App name (overrides project link)
--app string
App name (same as --agent)
-n, --num int32
Number of builds to list, newest first, up to 100
-o, --org string
Org the app belongs to
$ valet builds checkout
=== Builds of checkout
  0192f1d4-0b6e-7a31-8c2f-5e4d3c2b1a09  running     -   3fa91c2  2026-11-01T12:03:00Z  started 2026-11-01T12:03:02Z
  0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b  succeeded   v4  abc1234  2026-11-01T12:00:00Z  started 2026-11-01T12:00:01Z  finished 2026-11-01T12:00:49Z (48s)
  0192f1a0-55c2-7e10-9d3a-1b2c3d4e5f60  superseded  -   def5678  2026-11-01T11:59:40Z  finished 2026-11-01T11:59:58Z
      build.superseded: A newer deploy replaced this build, so nothing was deployed from it.

$ valet builds --app checkout -n 1

valet builds show

Show an app build's log and status

valet builds show <build-id> [flags]

Show an app build: its log so far, then its status, the release it made, the app's processes on that release, and the release evaluation that holds or held it. The log goes to stdout and the rest to stderr. Show reads the build once and exits 0 whatever state it is in. A build still in progress ends with how to follow it.

Pass --follow to follow the build to its end as "valet deploy" does. It streams the log, prints each policy and each process as it changes, and exits 0 once the release is up or idle, or a later release replaced it. It exits 1 if the build fails, a newer deploy replaced the build before its release, a process crashes, policies refuse the release, or --wait-timeout passes.

"valet deploy --no-wait" prints the id of the build it starts. Policy hints name the app the build's release evaluation names, in the org --org or the linked directory gives.

-f, --follow
Follow the build until its release is up or fails (default: false)
-o, --org string
Org that owns the app, for policy hints with --follow (uses linked or default org if omitted)
--wait-timeout duration
With --follow, how long to wait for the app's processes to come up, and for policies to decide (default 15m for policies)

Example

$ valet builds show 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b
-----> Fetching source
-----> Building
=== Build 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b
  Status:   running
  Deploy:   running
Follow it with "valet builds show 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b -f".

$ valet builds show 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b
=== Build 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b
  Status:   succeeded
  Release:  v4
  URL:      https://checkout.acme.valet.run
  Deploy:   up
=== Processes
  web.1     up       v4

$ valet builds show 0192f1c3-7d1e-7c4a-9b1f-3c2d1e0f9a8b -f
-----> Exporting bundle
-----> Uploading bundle
web.1     starting v3 → v4
web.1     up       v4
Deployed v4
URL: https://checkout.acme.valet.run

valet channels

List channels

valet channels [flags]

List, create, and manage channels.

Channels bring messages and scheduled work into your agents and apps. Each channel has a type, such as webhook or slack, and belongs to an org, an app, or an agent.

A channel on an agent starts a turn with the prompt in its channels/<name>.md. A channel on an app is a webhook, cron, or heartbeat: Valet posts each delivery to the --path you give, so a private app can take webhooks and scheduled work.

Create a webhook or slack channel with --org and attach it to several agents with "valet channels attach". Apps take no org channels.

Running "valet channels" with no subcommand lists all channels.

-a, --agent string
Filter channels by agent name
--app string
Filter channels by app name (same as --agent)
-o, --org string
Org to list channels for

valet channels attach

Attach an org channel to an agent

valet channels attach <channel-name> [flags]

Attach an org channel to an agent.

Makes an org-level channel available to the specified agent. Incoming messages on the channel will be routed to the agent. Use --as to give the attachment a custom alias (useful when attaching the same channel to multiple agents with different names). Use --events to filter which event types are routed to the agent.

For Slack channels, attaching provisions a per-agent Slack bot with its own identity in the workspace. The --bot-name flag sets the bot's display name (defaults to the agent name).

An app takes no org channels. Create a webhook, cron, or heartbeat channel on the app with "valet channels create <type> --app <app>".

Use "valet channels detach" to remove the attachment.

-a, --agent string
Agent to attach the channel to
--as string
Custom alias for the attachment
--bot-name string
Slack bot display name (slack channels only, defaults to agent name)
--events stringSlice
Event types to filter (comma-separated)
-o, --org string
Org that owns the channel

Example

$ valet channels attach github
Attaching github to my-agent agent in acme org... done, github

$ valet channels attach github --as gh-events --events push,pull_request
Attaching github to my-agent agent in acme org... done, gh-events (events: push, pull_request)

$ valet channels attach slack --agent my-agent --bot-name my-bot
Attaching slack to my-agent agent in acme org... done, slack
  type:      slack
  bot:       @my-bot
  workspace: My Workspace (T12345)

valet channels catalog

List channel catalog entries

valet channels catalog [flags]

List available channel catalog entries.

The channel catalog contains Valet-curated channel definitions for well-known services. Use "valet channels catalog get <name>" for details on a specific entry. Use "valet channels create <name>" to provision a channel from the catalog.

Example

$ valet channels catalog
github-webhook  webhook   WEBHOOK_SECRET  GitHub webhook (HMAC-SHA256)
slack-events    webhook   WEBHOOK_SECRET  Slack Events API

valet channels catalog get

Show catalog entry details

valet channels catalog get <name> [flags]

Show detailed information about a channel catalog entry.

Displays the entry's type, verification scheme, event header, and required secret slots.

Example

$ valet channels catalog get github-webhook
Name:         github-webhook
Type:         webhook
Verify:       hmac-sha256 (X-Hub-Signature-256)
Event Header: X-GitHub-Event
Slots:
  WEBHOOK_SECRET  Shared secret for signature validation

valet channels create

Create a channel

valet channels create <entry> [flags]

Create a channel from the catalog or by type.

If the argument matches a catalog entry, provisions a channel using that entry's default configuration. Managed secrets are auto-generated for any secret slots the entry defines. Use --as to give the channel a custom name.

For type-specific creation, use a subcommand:

  valet channels create webhook [name]
  valet channels create cron [name]
  valet channels create heartbeat [name]
  valet channels create slack [name]
  valet channels create telegram [name]
  valet channels create email [name]
  valet channels create mcp [name]

Name an app with --app on the webhook, cron, or heartbeat subcommand. When no --agent, --app, or --org flag is provided, uses the linked agent or app in the current directory.

Use "valet channels catalog" to browse available catalog entries.

-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
--as string
Custom name for a catalog channel
-o, --org string
Org that owns this channel

Example

# Add a channel from the catalog:
$ valet channels create github-webhook
Creating webhook channel on my-agent agent in acme org... done, github-webhook
  url:     https://gateway.valet.dev/webhook/abc123
  secret:  whsec_abc123
  managed: GITHUB_WEBHOOK_WEBHOOK_SECRET

# Catalog entry with a custom name:
$ valet channels create github-webhook --as my-gh-hook
Creating webhook channel on my-agent agent in acme org... done, my-gh-hook
  url:     https://gateway.valet.dev/webhook/def456
  secret:  whsec_def456
  managed: MY_GH_HOOK_WEBHOOK_SECRET

# Type-specific subcommands:
$ valet channels create webhook my-channel
$ valet channels create cron daily-report --schedule "every day at 9:00am"
$ valet channels create heartbeat health-check --every 5m
$ valet channels create slack my-bot --bot-name support-bot
$ valet channels create telegram tg-channel
$ valet channels create email inbox --sender-policy org
$ valet channels create mcp my-mcp

valet channels create cron

Create a cron channel

valet channels create cron [name] [flags]

Create a cron channel that triggers on a schedule.

Provide either --schedule with a human-readable description (e.g. "every day at 9:00am") or --cron with a raw crontab expression (e.g. "0 9 * * *"). The two flags are mutually exclusive. Use --timezone to specify an IANA timezone (default: UTC).

To deliver to an app, name it with --app (or --agent) and give --path, the path in the app that handles each delivery. Valet posts there with a channel visitor token; the app is not restarted and needs no prompt.

--app string
App that owns this channel (same as --agent)
--cron string
Raw crontab expression (e.g. "0 9 * * *")
--path string
Path in an app that handles each delivery (required for an app, such as /webhooks/stripe)
--prompt string
Prompt path (default: channels/<name>.md; not used for an app)
--schedule string
Human-readable schedule (e.g. "every day at 9:00am")
--timezone string
IANA timezone (default: UTC)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

# Human-readable schedule:
$ valet channels create cron daily-report --schedule "every day at 9:00am"
Creating cron channel on my-agent agent in acme org... done, daily-report
  type:     cron
  schedule: Every Day at 9:00 AM
  cron:     0 9 * * *
  timezone: UTC
  next:     Mon Mar 2, 2026 9:00 AM UTC
  agent:    my-agent
  prompt:   channels/daily-report.md

# Raw crontab expression:
$ valet channels create cron weekly --cron "0 9 * * 1" --timezone US/Eastern

valet channels create email

Create an email channel

valet channels create email [name] [flags]

Create an email channel backed by a @valet.run mailbox.

By default a new mailbox is minted with a randomly generated address in the org's namespace. Pass --local-part to choose the address's local part, or --mailbox to bind the exact existing address of an org-owned mailbox instead. The --sender-policy flag controls which senders may reach the agent: open (any sender passing the gates), allowlist, or org (org members only).

The printed status reports the org email identity's readiness: provisioning (records pending), inbound_ready (mail is received and wakes the agent; sending unlocks once the identity verifies), or ready (receiving and sending).

An agent may have several named email channels, each bound to a distinct mailbox and prompt. When no --agent or --org flag is provided, uses the linked agent in the current directory.

--local-part string
Chosen local part for the minted address (default: a generated haiku; not with --mailbox)
--mailbox string
Existing mailbox address to bind (default: mint a new address)
--prompt string
Prompt path (default: channels/<name>.md)
--sender-policy string
Sender policy (open, allowlist, org; default: open)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

$ valet channels create email inbox
Creating email channel on my-agent agent in acme org... done, inbox
  type:     email
  address:  wandering-brook-7h3k@acme.valet.run
  policy:   open
  agent:    my-agent
  prompt:   channels/inbox.md

$ valet channels create email support --sender-policy org
$ valet channels create email intake --local-part intake
$ valet channels create email executed --mailbox executed@acme.valet.run

valet channels create heartbeat

Create a heartbeat channel

valet channels create heartbeat [name] [flags]

Create a heartbeat channel that triggers at a fixed interval.

The --every flag is required and specifies the interval (e.g. 5m, 1h, 30s). Use --timezone to specify an IANA timezone (default: UTC).

To deliver to an app, name it with --app (or --agent) and give --path, the path in the app that handles each delivery. Valet posts there with a channel visitor token; the app is not restarted and needs no prompt.

--app string
App that owns this channel (same as --agent)
--every string
Heartbeat interval (e.g. 5m, 1h)
--path string
Path in an app that handles each delivery (required for an app, such as /webhooks/stripe)
--prompt string
Prompt path (default: channels/<name>.md; not used for an app)
--timezone string
IANA timezone (default: UTC)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

$ valet channels create heartbeat health-check --every 5m
Creating heartbeat channel on my-agent agent in acme org... done, health-check
  type:     heartbeat
  every:    5m
  timezone: UTC
  next:     Mon Mar 2, 2026 9:05 AM UTC
  agent:    my-agent
  prompt:   channels/health-check.md

valet channels create mcp

Create an MCP channel

valet channels create mcp [name] [flags]

Create an MCP channel that exposes the agent as an MCP server.

The channel serves MCP over Streamable HTTP at the endpoint URL shown in the output. It exposes a built-in "ask_<agent>" tool that takes a message and returns the agent's response, so the channel is usable as soon as a credential is minted — no tool files required. Define additional tools by adding mcp/<tool>.md files to the agent.

Clients authenticate with bearer credentials minted via "valet channels token mint".

--prompt string
Prompt path (default: channels/<name>.md)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

$ valet channels create mcp my-mcp
Creating mcp channel on my-agent agent in acme org... done, my-mcp
  type:     mcp
  url:      https://gateway.valet.dev/mcp/abc123
  agent:    my-agent
  prompt:   channels/my-mcp.md

Mint a credential with: valet channels token mint my-mcp <token-name>

valet channels create slack

Create a Slack channel

valet channels create slack [name] [flags]

Create a Slack channel for bidirectional messaging.

Setup is two-phase. The first phase is per-org: run with --org to connect Slack to the org, which prompts for a Slack app access token and refresh token (generate them at https://api.slack.com/apps under "Your App Configuration Tokens"). The second phase is per-agent: run with --agent (or from a linked project directory) to create a dedicated Slack app for that agent. The per-agent phase requires an existing org-level Slack connection.

Use --bot-name to customize the Slack bot display name. The default is the agent name.

Connecting Slack to the org (--org) requires the Admin role. Creating an agent's app on a connected workspace does not.

--bot-name string
Slack bot display name (default: agent name)
--prompt string
Prompt path (default: channels/<name>.md)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

$ valet channels create slack --org acme
Checking Slack connection... not connected

Connecting Slack to acme org.
Generate a Slack app access token and refresh token at
  https://api.slack.com/apps (under "Your App Configuration Tokens")
and paste them when prompted.
Slack app access token: ********
Slack app refresh token: ********
Connected to Acme (T12345)

$ valet channels create slack my-slack-bot --bot-name support-bot
Checking Slack connection... connected (Acme)
Creating slack channel on my-agent agent in acme org... done, my-slack-bot
  type:     slack
  bot:      @support-bot
  workspace: Acme (T12345)
  agent:    my-agent
  prompt:   channels/my-slack-bot.md

valet channels create telegram

Create a Telegram channel

valet channels create telegram [name] [flags]

Create a Telegram channel for bidirectional messaging.

After creating the channel, connect it by visiting the Telegram deep link shown in the output.

--prompt string
Prompt path (default: channels/<name>.md)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

$ valet channels create telegram tg-channel
Creating telegram channel on my-agent agent in acme org... done, tg-channel
  type:     telegram
  telegram: https://t.me/valetdotdevbot?start=tok123
  agent:    my-agent
  prompt:   channels/tg-channel.md

valet channels create webhook

Create a webhook channel

valet channels create webhook [name] [flags]

Create a webhook channel with signature verification.

Generates a webhook URL and a managed signing secret used to verify inbound requests. The managed secret is stored as a secret-kind env var ("valet env") and can be rotated with "valet env set". The "managed" field in the output is the secret name.

When --secret-name is provided, the channel references an existing secret by that name instead of auto-generating one. Use this for services like Stripe or Svix where you control the signing key.

Webhook signature verification schemes:

  hmac-sha256   HMAC-SHA256 of raw body.
                Default header: X-Webhook-Signature.
                Supports sha256=<hex>, v1=<hex>, raw hex, raw base64.
                Use --signature-header to change the header.
  stripe        HMAC-SHA256 of "{timestamp}.{body}".
                Default header: Stripe-Signature.
                Parses t=<ts>,v1=<hex> from the header value.
                Use --signature-header for providers that use the same
                format with a different header (e.g. WorkOS).
                Requires --secret-name.
  svix          HMAC-SHA256 of "{msg_id}.{timestamp}.{body}".
                Reads svix-id, svix-timestamp, svix-signature headers,
                falling back to webhook-id, webhook-timestamp,
                webhook-signature (Loops.so and other standard-webhooks
                senders). Secret must be base64-encoded (optionally
                whsec_ prefixed). Requires --secret-name.
  slack         Slack Events API signature verification.
                HMAC-SHA256 of "v0:{timestamp}:{body}".
                Reads X-Slack-Request-Timestamp and X-Slack-Signature.
                Handles url_verification challenges automatically.
                Requires --secret-name.
  static-token  Constant-time comparison of a bearer token.
                Default header: X-Webhook-Signature.
                Use --signature-header to change the header.
  none          No verification. Use for testing or trusted networks.

To deliver to an app, name it with --app (or --agent) and give --path, the path in the app that handles each delivery. Valet posts there with a channel visitor token; an app channel must verify (not "none").

--app string
App that owns this channel (same as --agent)
--delivery-key-header string
HTTP header containing a unique delivery ID for dedup (e.g. X-GitHub-Delivery)
--delivery-key-path string
Dot-notation path to a unique delivery ID in the JSON body for dedup (e.g. event.id)
--path string
Path in an app that handles each delivery (required for an app, such as /webhooks/stripe)
--prompt string
Prompt path (default: channels/<name>.md; not used for an app)
--secret-name string
Name of an existing secret-kind env var to use for webhook verification (from valet env)
--signature-header string
Header for signature (hmac-sha256: X-Webhook-Signature, stripe: Stripe-Signature, mercury: Mercury-Signature, static-token: X-Webhook-Signature)
--verify string
Verification scheme (none, hmac-sha256, slack, svix, stripe, mercury, static-token; default: hmac-sha256)
-a, --agent string
Agent that owns this channel (an app for webhook, cron, and heartbeat)
-o, --org string
Org that owns this channel

Example

# Default hmac-sha256 verification (auto-generates managed secret):
$ valet channels create webhook my-channel
Creating webhook channel on my-agent agent in acme org... done, my-channel
  type:     webhook
  url:      https://gateway.valet.dev/webhook/abc123
  secret:   whsec_abc123
  managed:  MY_CHANNEL_WEBHOOK_SECRET
  verify:   hmac-sha256 (X-Webhook-Signature)
  agent:    my-agent
  prompt:   channels/my-channel.md

# Stripe webhooks with a managed secret reference:
$ valet channels create webhook stripe-events \
    --verify stripe \
    --secret-name STRIPE_WEBHOOK_SECRET

valet channels destroy

Destroy a channel

valet channels destroy <name> [flags]

Permanently destroy a channel.

This action cannot be undone. When no --agent, --app, or --org flag is provided, uses the linked agent or app in the current directory.

Destroying an org-level Slack channel cascades: all per-agent Slack bots are destroyed first, then the org Slack connection is removed.

-a, --agent string
Agent that owns this channel
--app string
App that owns this channel (same as --agent)
-o, --org string
Org that owns this channel

Example

$ valet channels destroy my-channel
Destroying my-channel on my-agent agent in acme org... done

$ valet channels destroy stripe --app my-app
Destroying stripe on my-app app in acme org... done

$ valet channels destroy slack --org my-org
Destroying slack in my-org org... done

valet channels detach

Detach a channel from an agent

valet channels detach <alias> [flags]

Detach a channel from an agent.

Removes an org channel attachment from the specified agent. Messages on the channel will no longer be routed to the agent. The org channel itself is not deleted.

For Slack channels, detaching destroys the per-agent Slack bot. Use --force to skip the confirmation prompt.

Use "valet channels attach" to re-attach the channel.

-a, --agent string
Agent to detach the channel from
--force
Skip confirmation for Slack channel detach
-o, --org string
Org that owns the channel

Example

$ valet channels detach github
Detaching github from my-agent agent in acme org... done

$ valet channels detach slack --force
Detaching slack from my-agent agent in acme org... done

valet channels info

Show channel details

valet channels info <name> [flags]

Show detailed information about a channel.

Displays the channel's type, webhook URL, signing secret, managed secret name, verification scheme, status, owning org, app, or agent, and prompt path.

A channel on an app also shows its delivery path and its last five deliveries: each one's outcome (delivered, retrying, pending, or failed), attempts, the status the app answered, and the error. A channel whose deliveries keep failing shows why under health.

When no --agent, --app, or --org flag is provided, uses the linked agent or app in the current directory.

-a, --agent string
Agent that owns this channel
--app string
App that owns this channel (same as --agent)
-o, --org string
Org that owns this channel

Example

$ valet channels info my-channel
=== Channel: my-channel on my-agent agent in acme org
  type:     webhook
  url:      https://gateway.valet.dev/webhook/abc123
  status:   active
  secret:   whsec_abc123
  verify:   hmac-sha256 (X-Webhook-Signature)
  agent:    my-agent
  prompt:   channels/my-channel.md

$ valet channels info stripe --app my-app
=== Channel: stripe on my-app app in acme org
  type:     webhook
  url:      https://gateway.valet.dev/webhook/def456
  status:   active
  verify:   stripe (Stripe-Signature)
  app:      my-app
  path:     /webhooks/stripe

valet channels reauthorize

Mint a fresh authorization URL for a channel

valet channels reauthorize <name> [flags]

Mint a fresh authorization URL for a channel that holds third-party credentials and open it in your browser.

For Slack channels, this pushes the current bot scopes to the Slack app's manifest (so a scope widen self-heals on the next install) and returns the reinstall URL. For Telegram channels, it regenerates the deep link. Channels with no credentials (cron, heartbeat, webhook) cannot be reauthorized.

The channel keeps its identity and configuration -- only the underlying credentials are refreshed.

-a, --agent string
Agent that owns the channel
-o, --org string
Org that owns the channel
--print-url
Print the URL to stdout instead of opening a browser

Example

# Reauthorize a slack channel after a scope widen:
$ valet channels reauthorize team-bot --agent my-agent
Reauthorizing team-bot on my-agent agent... done

Reauthorize the channel:
  https://slack.com/oauth/v2/authorize?...

# Print the URL without opening a browser (for SSH or CI):
$ valet channels reauthorize team-bot --agent my-agent --print-url
https://slack.com/oauth/v2/authorize?...

valet channels slack

Manage Slack activity levels

valet channels slack [flags]

List and manage how actively the agent participates in each Slack conversation.

An activity level controls what wakes the agent in a conversation: "mentions" (only @-mentions), "emails" (@-mentions and forwarded emails), or "all" (every message). The channel default is a template stamped onto each conversation when the bot joins it; changing the default never re-points conversations the bot is already in.

Running "valet channels slack" with no subcommand lists the bot's conversations with each conversation's effective level.

-a, --agent string
Agent that owns the Slack channel
-o, --org string
Org that owns the Slack channel

Example

$ valet channels slack --agent my-agent
=== Slack conversations on my-agent agent
  #general	C0123456789	public	mentions
  #ops	G0234567890	private	all

valet channels slack add

Add the agent's bot to a Slack conversation

valet channels slack add <#conversation> [flags]

Add the agent's Slack bot to a conversation.

For a public channel the bot self-joins. A private channel or DM cannot be self-joined: the command prints the /invite hint to run from inside the conversation instead. The conversation may be given as "#name" (resolved against joinable channels) or as a raw Slack ID.

Use --activity to stamp a starting level; without it the conversation inherits the channel default.

--activity string
Starting activity level (mentions, emails; default: channel default)
-a, --agent string
Agent that owns the Slack channel
-o, --org string
Org that owns the Slack channel

Example

$ valet channels slack add '#support' --agent my-agent
Added the bot to #support (activity: mentions)

$ valet channels slack add '#leadership' --activity all --agent my-agent
#leadership is private -- the bot can't self-join.
Invite it from the conversation with: /invite @<your-bot>

valet channels slack set

Set one conversation's activity level

valet channels slack set <#conversation> <level> [flags]

Set the agent's activity level for a single Slack conversation, overriding the channel default for it alone.

The conversation may be given as "#name" or as a raw Slack ID; a name is resolved against the bot's current conversations. Valid levels are "mentions" (only @-mentions), "emails" (@-mentions and forwarded emails), and "all" (every message).

-a, --agent string
Agent that owns the Slack channel
-o, --org string
Org that owns the Slack channel

Example

$ valet channels slack set '#support' all --agent my-agent
Set #support activity to all

valet channels slack set-default

Set the channel default activity level

valet channels slack set-default <level> [flags]

Set the default activity level for the agent's Slack channel.

The default is a template stamped onto each conversation when the bot joins it. Changing the default does not re-point conversations the bot is already in -- use "valet channels slack set" for those.

Valid levels are "mentions" (only @-mentions wake the agent), "emails" (@-mentions and forwarded emails), and "all" (every message).

-a, --agent string
Agent that owns the Slack channel
-o, --org string
Org that owns the Slack channel

Example

$ valet channels slack set-default emails --agent my-agent
Set default activity to emails for team-bot

valet channels token

Manage MCP channel tokens

valet channels token [command]

Mint, list, and revoke bearer tokens for MCP channels.

MCP channels authenticate clients with bearer credentials. Each token carries an optional tool grant, expiry, and rate limit. The plaintext value is shown exactly once, at mint time.

-a, --agent string
Agent that owns the channel
-o, --org string
Org that owns the channel

Example

$ valet channels token mint my-mcp ci
$ valet channels token list my-mcp
$ valet channels token revoke my-mcp ci

valet channels token list

List tokens on an MCP channel

valet channels token list <channel> [flags]

List the bearer credentials minted for an MCP channel.

Shows each token's name, tool grant, rate limit, expiry, status (active, expired, or revoked), and creation time. Plaintext token values are never shown after minting.

When no --org or --agent flag is provided, uses the linked agent in the current directory.

-a, --agent string
Agent that owns the channel
-o, --org string
Org that owns the channel

Example

$ valet channels token list my-mcp
Tokens for my-mcp on my-agent agent in acme org:
NAME	TOOLS	RATE LIMIT	EXPIRES	STATUS	CREATED
ci	all	-	-	active	Fri May 1, 2026 9:00 AM UTC
zapier	search,fetch	30	Fri Jul 10, 2026 12:00 AM UTC	active	Fri May 1, 2026 9:00 AM UTC

valet channels token mint

Mint a bearer token for an MCP channel

valet channels token mint <channel> <token-name> [flags]

Mint a bearer credential for an MCP channel.

The plaintext token is printed exactly once; store it securely. Use --tools to narrow the credential to specific tools, --expires to set an expiry, and --rate-limit to cap tool calls per minute. Tool names include the built-in "ask_<agent>" tool and any tools the agent defines in mcp/<tool>.md.

When no --org or --agent flag is provided, uses the linked agent in the current directory.

--expires string
Expiry as a Go duration (e.g. 720h) or an RFC 3339 timestamp (default: never)
--rate-limit int32
Tool calls per minute (default: 0, unlimited)
--tools stringSlice
Tools the token may call, comma-separated or repeated (default: all tools)
-a, --agent string
Agent that owns the channel
-o, --org string
Org that owns the channel

Example

$ valet channels token mint my-mcp ci --tools search,fetch --expires 720h
Minting token for my-mcp on my-agent agent in acme org... done, ci
  expires: Fri Jul 10, 2026 12:00 PM UTC

This token will not be shown again. Store it securely:
vlt_abc123...

valet channels token revoke

Revoke a token on an MCP channel

valet channels token revoke <channel> <token-name> [flags]

Revoke a bearer credential on an MCP channel.

Revocation is immediate and permanent: clients holding the token lose access on their next request. Mint a new token to restore access.

When no --org or --agent flag is provided, uses the linked agent in the current directory.

-a, --agent string
Agent that owns the channel
-o, --org string
Org that owns the channel

Example

$ valet channels token revoke my-mcp ci
Revoking token ci for my-mcp on my-agent agent in acme org... done

valet channels update

Change a channel's cadence or an app channel's path

valet channels update <name> [flags]

Change a heartbeat or cron channel's cadence, or move a channel on an app to another path.

--path moves the channel's deliveries to another path in the app. The app is not restarted. --every, --schedule, --cron, and --timezone replace a heartbeat's or cron channel's cadence, for an agent or an app.

When no --agent or --app flag is provided, uses the linked agent or app in the current directory.

-a, --agent string
Agent that owns this channel
--app string
App that owns this channel (same as --agent)
--cron string
New raw crontab expression
--every string
New heartbeat interval, such as 15m
-o, --org string
Org that owns this channel
--path string
New path in the app that handles each delivery
--schedule string
New human-readable cron schedule
--timezone string
New IANA timezone

Example

$ valet channels update stripe --app my-app --path /webhooks/stripe-v2
Updating stripe on my-app app in acme org... done
  path:     /webhooks/stripe-v2

$ valet channels update tick --every 2h

valet connectors

List connectors

valet connectors [flags]

List, create, and manage connectors.

Connectors extend agents with external capabilities. There are two types:

  mcp-server  Provides tool access via MCP. Defines a transport
              (stdio, sse, or streamable-http) and optionally a
              command or URL.
  command     Wraps a CLI tool as a callable command. Defines a
              command, optional args, and secret names. Secrets
              are injected into the command's environment at
              runtime -- the agent never sees the values.

Each connector is scoped to an org or agent. Running "valet connectors" with no subcommand lists connectors for the linked agent.

-a, --agent string
Agent to list connectors for
-o, --org string
Org to list connectors for
--sites
List only connectors a site can hold (HTTP MCP servers)

valet connectors attach

Attach an org connector to an agent or site

valet connectors attach <connector-name> [flags]

Attach an org connector to an agent or site.

Makes an org-level connector available to the target. An agent can use the connector's tools during sessions; a site serves the connector's tools to anyone who can open the page, so attaching hands the connector's full reach to everyone the page reaches. Use --agent or --site to name the target -- they are mutually exclusive. Use --as to give the attachment a custom alias (useful when attaching the same connector to multiple targets with different names).

A site holds only HTTP MCP servers -- an mcp-server connector on the sse or streamable-http transport. Attaching anything else to a site is refused; "valet connectors list --sites" shows the connectors a site can hold.

Use "valet connectors detach" to remove the attachment.

-a, --agent string
Agent to attach the connector to
--as string
Custom alias for the attachment
-o, --org string
Org that owns the connector
--site string
Site to attach the connector to

Example

$ valet connectors attach slack
Attaching slack to my-agent agent in acme org... done, slack

$ valet connectors attach slack --site reports
Attaching slack to reports site in acme org... done, slack

$ valet connectors attach slack --as slack-readonly
Attaching slack to my-agent agent in acme org... done, slack-readonly

valet connectors call

Run one of a connector's tools and print the answer

valet connectors call <connector-name> <tool> [flags]

Run one of a connector's tools and print the answer.

Sample a connector before you build against it. A tool's schema says what it accepts; only a real call says what it answers, and the answer is usually the part that decides how a page or an agent has to parse it -- a markdown table, a single meta-tool taking a "command" string, or a 401 from a credential whose scope covers only some of the tools.

The loop is: "valet connectors list --sites" to see what the org has, "valet connectors attach" to give the target one, "valet sites info --schemas" (or the list_connector_tools MCP tool, for an MCP caller) to read the attached tools and their argument schemas, then this command to see one tool's real answer. "valet sites info" without --schemas prints each attachment's status and its tool names, but not the schemas. Use --agent or --site to name the target -- they are mutually exclusive, and the target must already hold the connector.

Only an HTTP MCP server can be called: a command connector and a stdio MCP server run inside an agent's container, where Valet cannot reach them. The connector's answer is printed to stdout verbatim. A tool that answers with an error prints that error and exits 1.

-a, --agent string
Agent holding the connector
--args string
JSON object of arguments for the tool (default: {})
-o, --org string
Org that owns the connector
--site string
Site holding the connector

Example

$ valet connectors call posthog exec --args '{"command":"docs"}' --site reports
| path        | views |
| ----------- | ----- |
| /pricing    |  1204 |
| /docs       |   871 |

$ valet connectors call linear search --agent triage
No issues match.

valet connectors catalog

List connector catalog entries

valet connectors catalog [flags]

List available connector catalog entries.

The connector catalog contains Valet-curated connector definitions for well-known services. Use "valet connectors catalog get <name>" for details on a specific entry. Use "valet connectors create <name>" to provision a connector from the catalog.

Example

$ valet connectors catalog
github  mcp-server  GITHUB_TOKEN  GitHub MCP server (stdio)
slack   mcp-server  SLACK_TOKEN   Slack MCP server (stdio)

valet connectors catalog get

Show catalog entry details

valet connectors catalog get <name> [flags]

Show detailed information about a connector catalog entry.

Displays the entry's transport, command, arguments, and required secret slots.

Example

$ valet connectors catalog get github
Name:       github
Type:       mcp-server
Transport:  stdio
Command:    npx
Args:       -y @modelcontextprotocol/server-github
Slots:
  GITHUB_TOKEN  GitHub personal access token

valet connectors create

Create a connector

valet connectors create <entry> [flags]

Create a connector from the catalog or by type.

If the first argument matches a catalog entry, provisions a connector using that entry's default configuration. Use --as to give the connector a custom name.

If the first argument is not a catalog entry, use one of the type-specific subcommands to create a connector:

  valet connectors create mcp-server <name>
  valet connectors create command <name>

When no --agent or --org flag is provided, uses the linked agent in the current directory.

An entry's secret slots resolve to env vars in the connector's scope. An agent-scoped connector reads each slot under the slot's own name. An org-scoped connector binds each slot to an env var named for the connector, so a second connector from the same entry can hold its own credentials. Before creating anything, this command asks the server which of those env vars it requires and refuses when one is unset, naming the "valet env set" command that fills it. An OAuth or Composio entry needs none, because its credential comes from the provider.

Use "valet connectors catalog" to browse available catalog entries.

-a, --agent string
Agent to create the connector for
--as string
Custom name for a catalog connector
-o, --org string
Org to create the connector for
--secret-name string
Name of an existing secret-kind env var (from valet env) whose value an API-key connector forwards to the provider at connect time

Example

# Add a connector from the catalog:
$ valet connectors create github --agent my-agent
Creating mcp-server connector on my-agent agent in acme org... done, github

# Catalog entry with a custom name:
$ valet connectors create github --as github-readonly --org acme
Creating mcp-server connector in acme org... done, github-readonly

# A second connector from an entry with a secret slot, in an org:
# the create refuses until the bound secret exists.
$ valet connectors create luma-mcp --as luma-mcp-2 --org acme
Error: luma-mcp-2 needs a secret before it can be created.
  valet env set LUMA_MCP_2_LUMA_API_KEY=... --org acme
$ valet env set LUMA_MCP_2_LUMA_API_KEY=sk_live_... --org acme
$ valet connectors create luma-mcp --as luma-mcp-2 --org acme
Creating mcp-server connector in acme org... done, luma-mcp-2

# API-key catalog connector: reference a secret env var set beforehand
# (its value is forwarded to the provider, not stored on the connector):
$ valet env set EXA_API_KEY=exa_live_... --agent my-agent
$ valet connectors create exa-composio --agent my-agent --secret-name EXA_API_KEY
Creating mcp-server connector on my-agent agent in acme org... done, exa-composio

# MCP server connector with stdio transport:
$ valet connectors create mcp-server slack --transport stdio \
    --command npx --args=-y,server-slack \
    --env SLACK_BOT_TOKEN={{SLACK_BOT_TOKEN}} \
    --env SLACK_TEAM_ID={{SLACK_TEAM_ID}}
Creating mcp-server connector on my-agent agent in acme org... done, slack

# Command connector:
$ valet connectors create command gh \
    --command gh --secrets GITHUB_TOKEN
Creating command connector on my-agent agent in acme org... done, gh

valet connectors create command

Create a command connector

valet connectors create command <name> [flags]

Create a command connector that wraps a CLI tool.

Command connectors require --command and accept --args and --secrets. The --secrets flag takes a comma-separated list of secret names that are injected when the command runs. The agent never sees secret values directly.

When no --agent or --org flag is provided, uses the linked agent in the current directory.

--args stringSlice
Command arguments
--command string
Command to run
--secrets stringSlice
Secret names for command connectors (comma-separated)
-a, --agent string
Agent to create the connector for
-o, --org string
Org to create the connector for

Example

# Command connector:
$ valet connectors create command gh \
    --command gh --secrets GITHUB_TOKEN
Creating command connector on my-agent agent in acme org... done, gh

# Command connector with args and multiple secrets:
$ valet connectors create command aws \
    --command aws --args s3,ls \
    --secrets AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY
Creating command connector on my-agent agent in acme org... done, aws

valet connectors create mcp-server

Create an MCP server connector

valet connectors create mcp-server <name> [flags]

Create an MCP server connector with the specified transport and connection details.

Use --transport=stdio with --command for local processes, or --transport=sse/streamable-http with --url for remote servers.

Environment variables and headers can reference env vars using the {{NAME}} template syntax instead of embedding literal values. The connector stores the reference, and the control plane resolves it to the actual value at deploy time. Templates can appear anywhere in a value (e.g. https://{{HOST}}/api). Use "valet env set" to create env vars before referencing them.

An OAuth-protected remote server needs no credential flags. The control plane discovers the server's authorization endpoints, creates the connector in pending status, and this command opens your browser to complete the grant, then waits for the connector to go active.

When no --agent or --org flag is provided, uses the linked agent in the current directory.

--args stringSlice
Command arguments
--command string
Command to run
--env stringSlice
Environment variables as KEY=VAL pairs (use {{NAME}} to reference a secret)
--header stringSlice
HTTP headers as KEY=VAL pairs (use {{NAME}} to reference a secret)
--transport string
Transport type (stdio, sse, streamable-http)
--url string
Server URL (sse or streamable-http transport)
-a, --agent string
Agent to create the connector for
-o, --org string
Org to create the connector for

Example

# MCP server connector with stdio transport:
$ valet connectors create mcp-server slack --transport stdio \
    --command npx --args=-y,server-slack \
    --env SLACK_BOT_TOKEN={{SLACK_BOT_TOKEN}} \
    --env SLACK_TEAM_ID={{SLACK_TEAM_ID}}
Creating mcp-server connector on my-agent agent in acme org... done, slack

# MCP server connector with SSE transport:
$ valet connectors create mcp-server api \
    --transport sse --url https://example.com/sse \
    --header Authorization={{API_KEY}}
Creating mcp-server connector on my-agent agent in acme org... done, api

# OAuth-protected MCP server: authorize in the browser:
$ valet connectors create mcp-server research --org acme \
    --transport streamable-http --url https://mcp.example.com/mcp
Creating mcp-server connector in acme org... done, research (pending authorization)

Authorize the connector:
  https://mcp.example.com/oauth/authorize?...

Waiting for authorization... done

valet connectors destroy

Destroy a connector

valet connectors destroy <name> [flags]

Permanently destroy a connector.

Removes the connector from the agent. This action cannot be undone.

-a, --agent string
Agent that owns the connector
-o, --org string
Org that owns the connector

Example

$ valet connectors destroy slack
Destroying slack on my-agent agent in acme org... done

valet connectors detach

Detach a connector from an agent or site

valet connectors detach <alias> [flags]

Detach a connector from an agent or site.

Removes an org connector attachment from the target. The target will no longer be able to use the connector's tools -- for a site, that means every page it serves loses access. The org connector itself is not deleted. Use --agent or --site to name the target -- they are mutually exclusive.

Use "valet connectors attach" to re-attach the connector.

-a, --agent string
Agent to detach the connector from
-o, --org string
Org that owns the connector
--site string
Site to detach the connector from

Example

$ valet connectors detach slack
Detaching slack from my-agent agent in acme org... done

$ valet connectors detach slack --site reports
Detaching slack from reports site in acme org... done

valet connectors info

Show connector details

valet connectors info <name> [flags]

Show detailed information about a connector.

Displays the connector's type, transport, status, command or URL, arguments, environment variables (with {{NAME}} secret references), HTTP headers, secrets and whether each is set, and catalog origin.

Status is "active" or "pending"; a pending connector is still waiting for its first OAuth authorization and every tool call fails until the grant lands. Auth status reports credential health for a connector that holds credentials: pending, active, needs_reauth, or revoked. A connector with nothing to authorize omits the line. Auth reason carries the provider's diagnostic when the grant broke. Run "valet connectors reauthorize <name>" to restore a grant that was revoked or never finished.

A "Secrets" section lists each env var the connector reads, marked "set" or "not set" in the connector's scope. An agent-scoped connector counts a variable set on the agent or on its org. The section is absent for a connector that reads no secrets.

-a, --agent string
Agent that owns the connector
-o, --org string
Org that owns the connector

Example

$ valet connectors info slack
=== Connector: slack on my-agent agent in acme org
Name:        slack
Type:        mcp-server
Transport:   stdio
Status:      active
Command:     npx
Args:        -y server-slack

# A connector whose OAuth authorization never completed:
$ valet connectors info research --org acme
=== Connector: research in acme org
Name:        research
Type:        mcp-server
Transport:   streamable-http
Status:      pending
Auth status: pending
URL:         https://mcp.example.com/mcp

# A second Luma connector in the same org, with its own bound secret:
$ valet connectors info luma-mcp-2 --org acme
=== Connector: luma-mcp-2 in acme org
Name:        luma-mcp-2
Type:        mcp-server
Transport:   streamable-http
Status:      active
URL:         https://mcp.lumalabs.ai/mcp
Secrets:
  LUMA_MCP_2_LUMA_API_KEY  set

valet connectors reauthorize

Restart the OAuth flow for a connector

valet connectors reauthorize <name> [flags]

Restart the OAuth authorization flow for an OAuth-backed connector.

Use this to restore a connector whose grant was revoked by the provider (so its tools stopped working) or whose first-time authorization never completed. The connector keeps its identity and configuration -- only fresh OAuth tokens are issued.

The command opens your browser to the provider's consent screen, then waits for the authorization to complete. When no --agent or --org flag is provided, uses the linked agent in the current directory.

Only OAuth-backed catalog connectors can be reauthorized; the command fails for static-secret and command connectors.

-a, --agent string
Agent that owns the connector
-o, --org string
Org that owns the connector

Example

# Reauthorize an org-scoped connector:
$ valet connectors reauthorize airtable-mcp --org acme
Reauthorizing airtable-mcp in acme org... done

Authorize the connector:
  https://airtable.com/oauth2/v1/authorize?...

Waiting for authorization... done

# Reauthorize an agent-scoped connector:
$ valet connectors reauthorize google-sheets --agent my-agent
Reauthorizing google-sheets on my-agent agent in acme org... done

valet console

Start an interactive console session

valet console [flags]

Start an interactive console session with an agent.

Opens a REPL-style session connected to the agent via the gateway's console channel. The agent is determined by the --agent flag or the linked agent in the current directory. If the agent is still starting, waits for it to become ready before opening the session.

Use --resume <session-id> to continue an existing session; the CLI verifies the session exists before opening the REPL.

-a, --agent string
Agent to connect to (uses linked agent if omitted)
-o, --org string
Org that owns the agent
-r, --resume string
Resume an existing session by ID
$ valet console --agent my-agent
$ valet console --agent my-agent --resume sess-abc

valet deploy

Deploy an agent

valet deploy [flags]

Deploy the current directory as a new release for an agent, app, site, or skill.

Creates a push on the service, commits the directory on top of the service's source, pushes that commit with Git, and publishes it. The service is determined by the --agent flag or the linked service in the current directory. Git 2.32 or later must be on your PATH.

The bundle is every regular file under the current directory, walked recursively. Only .git and .valet are skipped at any depth, symbolic links and other special files are skipped, and there is no ignore file. Build output, node_modules, vendored dependencies, datasets, and media all ship to the service's repo if they sit in the directory. Move them out first. Deploy refuses a file over the service's per-file limit, naming it, before it pushes anything.

Deploy never touches a repository in the directory and ignores your Git configuration, hooks, attributes, and filters. It keeps a cache of the service's source in your user cache directory, so a deploy pushes only what changed. Deleting the cache is always safe.

After deploying an app, waits for its processes: it prints a line each time one changes state, then exits 0 once every process is up on the new release, and exits 1 if one crashes or --wait-timeout passes. An app whose processes are all idle exits 0 and starts on its next request. If a later release replaces this one, deploy says so and exits 0: the later release builds on this commit. If a newer deploy replaces the build before it makes a release, deploy says nothing was deployed and exits 1. --no-wait returns after the build starts and prints its id; "valet builds show <id> -f" follows it later.

For a skill, deploy publishes the directory as the skill's next release, as "valet skills publish" does, and prints the release number. It needs the directory's SKILL.md and waits for nothing else.

After deploying an agent, waits for the agent runtime to become ready. Use --no-wait to skip the readiness check and return immediately after the release is activated.

If your org has a policy that blocks, the release is not live until the policy passes. Deploy prints each policy's status and each blocking finding, then continues once the policies pass. It exits 1 and prints why when a policy blocks or errors, or when --wait-timeout passes. The previous release stays live. --no-wait says where to follow the policies and returns. Run "valet policies show" to follow them later.

If the local source is identical to the service's current source and a release has already deployed it, deploy exits 0 without re-releasing — there's nothing to ship. If nothing has deployed yet (for example an earlier build failed), deploy rebuilds the unchanged source so a retry isn't stuck; pass --force to rebuild unchanged source even when it has already deployed.

If the service changes while deploy runs, deploy builds the same directory on the new source and tries once more.

If the directory is linked to an anonymous site (a link naming the "try" org), deploy publishes through the anonymous-site path instead, authorized by the claim token in that directory's own .valet/config.json rather than by a login. It needs no Git. Claiming is not a precondition: an unclaimed anonymous site updates in place, and deploy prints the earliest moment the site may be removed and how to keep it. If it has since been claimed, the link is rewritten to the site's real org and name, the spent token is dropped in the same write, and the ordinary deploy proceeds.

If the manifest declares connectors or channels that aren't attached yet, deploy stops and lists what's missing. The dependencies are suggestions, not hard requirements — pass --allow-unsatisfied to deploy anyway (the agent runs without them until they're attached). A manifest that fails to parse is always a hard error that --allow-unsatisfied does not bypass. Server validation, required-skill gates, billing requirements, and build failures can still block deployment.

-a, --agent string
Agent, app, site, or skill to deploy (uses linked service if omitted)
--allow-unsatisfied
Deploy even if declared connectors/channels aren't attached yet (default: false)
--app string
App to deploy (same as --agent)
--force
Rebuild even when the source is unchanged (default: false)
--no-wait
Skip waiting for the agent to become ready or a policy to decide
-o, --org string
Org that owns the service
--wait-timeout duration
How long to wait for an app's processes to come up, and for policies to decide (default 15m for policies)
$ valet deploy --agent my-agent
Creating push for my-agent agent in acme org... done
Fetching source... done
Reading files... done, 12 files
Pushing source... done
Deploying my-agent agent in acme org... done, v3
Waiting for agent to start... done

$ valet deploy --agent my-agent --allow-unsatisfied
Creating push for my-agent agent in acme org... done
Fetching source... done
Reading files... done, 12 files
Pushing source... done
Deploying my-agent agent in acme org... done, v4

$ valet deploy --agent checkout
Creating push for checkout app in acme org... done
Fetching source... done
Reading files... done, 38 files
Pushing source... done
Starting build for checkout app in acme org... done
-----> Fetching source
-----> Detecting buildpacks
-----> Building
-----> Exporting bundle
-----> Uploading bundle
web.1     starting v1 → v2
web.1     up       v2
Deployed v2
URL: https://checkout.acme.valet.run

$ valet deploy --agent support-bot
Deploying support-bot agent in acme org... done, v4
Waiting for policies (secrets)…
secrets  running (block at high)
secrets  blocked (block at high)
  high  config.yaml:3  AWS access key found (aws-key)
    Fix: Remove the key and rotate it.
Error: acme's policies blocked support-bot's changes: secrets found 1 finding at high or above. Nothing was deployed; the current release is still live. Fix it and deploy again.

valet drafts

List agent drafts

valet drafts [flags]

List open drafts in scope, or operate on a single draft.

Drafts pair an agent with an editing session. The Architect opens a Blueprint draft when a user starts an edit, edits files via plain git over the URL the server mints, and publishes when done.

Run `valet drafts` with no subcommand to list open drafts in the current org. Pass --agent to filter to a single agent.

--agent string
Filter to drafts for a single agent (by name)
-o, --org string
Org to list drafts in
$ valet drafts
=== Drafts
  drf_01J9...  triage    2026-04-26T10:00:00Z
  drf_01J9...  digester  2026-04-26T11:30:00Z

valet drafts checkout

Clone the draft branch and print the working directory path

valet drafts checkout <draft_id> [flags]

Clone the draft branch to a local working directory and print the absolute path of that directory on stdout.

The working directory is placed under the system temp directory, one directory per draft id:

  $TMPDIR/valet-drafts/<draft-id>/

Keying by draft id gives each draft its own tree, so two concurrent editing sessions for different agents' drafts never collide. The runtime is ephemeral, so /tmp gets reaped along with the container — no cleanup is needed.

Running checkout again lays down a fresh tree at the current branch tip, discarding any uncommitted local drift. Push before re-running checkout if you have work to keep.

Inside the agent runtime the working tree is owned by the valet user (the agent's own identity) so the agent can edit it in place; the git work is performed by the setuid-root valet-draft-git helper, which keeps the org token isolated in the sandboxed valet-worker user. On a developer machine the checkout is owned by the caller.

The branch cloned is draft/<draft-id> on the ephemeral namespace. The server's ephemeral namespace has no main, so a normal clone would fail — this command uses --single-branch --branch to clone only the draft ref.

Designed for shell composition with cd:

  cd "$(valet drafts checkout drf_X)"

Diagnostics (draft id and agent name) go to stderr so stdout contains only the path.

Example

$ valet drafts checkout drf_01J9...
/tmp/valet-drafts/drf_01J9...
draft drf_01J9... on my-agent

$ cd "$(valet drafts checkout drf_01J9...)"

valet drafts create

Open a new draft for an agent

valet drafts create [flags]

Open a fresh editing draft in an agent's source repository and print the new draft id on stdout.

A draft is an ephemeral branch forked from the agent's main HEAD. Use this to start an out-of-band edit that you review before publishing, rather than `valet deploy` (which opens a draft, pushes the current directory, publishes, and deploys in one shot). The draft id this prints feeds the per-draft subcommands:

  drf=$(valet drafts create --agent my-agent)
  cd "$(valet drafts checkout "$drf")"
  $EDITOR skills/some-skill/SKILL.md
  valet drafts push "$drf"
  valet drafts publish "$drf"
  valet deploy --agent my-agent

The agent is determined by the --agent flag or the linked agent in the current directory. An agent may have at most one open draft; if one already exists this errors with the existing draft's id unless you pass --force, which discards it first.

The draft id is the only thing on stdout (so it composes with checkout); status and diagnostics go to stderr.

-a, --agent string
Agent to open a draft for (uses linked agent if omitted)
--force
Discard any existing open draft and proceed (default: false)
-o, --org string
Org that owns the agent

Example

$ valet drafts create --agent my-agent
Opening draft for my-agent agent... done
drf_01J9...
draft drf_01J9... on my-agent (base abc1234)

valet drafts discard

Delete a draft without publishing

valet drafts discard <draft_id> [flags]

Delete the draft and its ephemeral branch. Idempotent at the row level — a missing draft yields NotFound from the server.

Example

$ valet drafts discard drf_01J9...
Discarded.

valet drafts info

Show draft detail

valet drafts info <draft_id> [flags]

Show metadata for a single draft: agent, session, base commit, timestamps. Run `valet drafts checkout` to get a clone URL for editing.

Example

$ valet drafts info drf_01J9...
=== Draft: drf_01J9...
  Agent:       triage (019d...)
  Session:     019d...
  Base commit: abc123
  Created:     2026-04-26T10:00:00Z
  Updated:     2026-04-26T10:00:00Z

valet drafts publish

Promote a draft to main

valet drafts publish <draft_id> [flags]

Promote the draft's ephemeral branch to main and report any catalog dependencies that need installing or attaching before the agent can deploy.

When the manifest declares connectors or channels that aren't yet installed in the org, the response status is "needs_configuration" and the pending lists tell the configure flow what to set up next.

Example

$ valet drafts publish drf_01J9...
Status: deployable

valet drafts push

Ship local files to a draft branch

valet drafts push <draft_id> [flags]

Walk a directory of agent source and ship its contents to the draft branch via the server's PushDraftFiles RPC. The server commits the changed files; nothing is published. Use this to iterate on a draft without promoting it to main — for example, the Architect pushes after each user-visible edit so the dashboard's draft view refreshes.

The directory is walked recursively and every regular file is sent. Only .git and .valet are skipped, and there is no ignore file. Keep build output and dependency trees out of the directory. Push refuses any single file over 25 MiB, naming it, before it uploads anything.

Plain `git push` against a draft clone URL does not work for draft branches: the ephemeral endpoint advertises only ephemeral refs, so a local pack builder cannot enumerate ancestors across the ephemeral / non-ephemeral namespaces. `drafts push` sidesteps the namespace question by sending file contents directly and letting the server build the commit.

When the working directory matches the draft tip exactly, the server returns no_changes and this command exits 0 without publishing a commit.

--dir string
Directory to ship (defaults to the draft's checkout dir in the agent runtime, else the current directory)
-m, --message string
Commit message (defaults to server's "Update draft")

Example

$ valet drafts push drf_01J9... --dir ./my-agent
Pushed, commit abc1234

$ valet drafts push drf_01J9...
No changes.

valet drafts validate

Verify the draft's valet.yaml parses against the manifest schema

valet drafts validate [draft-id] [flags]

Verify the draft's valet.yaml parses against the manifest schema. Run this after editing files and before `valet drafts push`.

When a draft-id is provided the command also checks that the current Git branch matches the draft's branch — "draft/<draft-id>", the branch `valet drafts checkout` lays the working tree down on. A mismatch is reported as an additional error. Validating a copied working tree (one not on the draft branch) should omit the draft-id and pass --dir instead, which runs schema validation only.

Exits 0 when the manifest is valid (and the branch matches, if a draft-id was supplied). Exits 1 and prints each error prefixed with "error:" when validation fails.

--dir string
Directory containing valet.yaml (defaults to current directory)

Example

$ valet drafts validate drf_01J9...
valet.yaml is valid

$ valet drafts validate --dir ./my-agent
error: channels[0]: every is required for heartbeat channels

valet drains

List drains

valet drains [flags]

List, create, and manage drains for an org or a service.

A drain forwards telemetry to an OpenTelemetry endpoint. A drain carries logs and traces. An org drain receives every site, app, agent, and skill in the org. Each drain has a name and can include custom headers for authentication.

Running "valet drains" with no subcommand lists the drains for the linked service, including its org's drains, or for the org with --org alone. Each row shows the endpoint, the signals, the status, and the name. Only an Admin sees an org drain's endpoint and headers; anyone else sees "(hidden)".

-a, --agent string
Agent or app name (uses linked service if omitted)
--app string
App name (same as --agent)
-o, --org string
Org; alone, names the org's drains

valet drains create

Create a drain

valet drains create <url> [flags]

Create a drain for an org or a service.

Give a base URL to store its /v1/logs and /v1/traces endpoints, or a URL ending in /v1/logs to store a logs endpoint alone. The drain carries logs and traces. The endpoints must be https URLs. Use --header to include authentication headers.

Use --name to tell drains apart, such as "Honeycomb". Without it, the drain is named after its endpoint's host. Names are unique in the service or org.

With --org alone, the drain is an org drain: every service in the org sends to it, and only an Admin can create one. Otherwise the drain is the service's.

With --org alone, requires the Admin role.

-a, --agent string
Agent or app name (uses linked service if omitted)
--app string
App name (same as --agent)
--header stringSlice
HTTP headers as Key=Value pairs
--logs-endpoint string
Logs URL, overriding the derived one
--name string
Drain name; defaults to the endpoint's host
-o, --org string
Org; alone, creates an org drain
--signals stringSlice
Signals to send: logs, traces, metrics
--traces-endpoint string
Traces URL, overriding the derived one

Example

$ valet drains create https://otlp.example.com --header Authorization=Bearer\ tok123
Creating drain on my-agent agent in acme org... done
  name:    otlp.example.com
  logs:    https://otlp.example.com/v1/logs
  traces:  https://otlp.example.com/v1/traces
  status:  active
  headers: Authorization

$ valet drains create https://otlp.example.com --org acme --signals logs --name Honeycomb
Creating drain on acme org... done
  name:    Honeycomb
  logs:    https://otlp.example.com/v1/logs
  status:  active

valet drains destroy

Destroy a drain

valet drains destroy <url-or-name> [flags]

Permanently destroy a drain.

Removes the drain the argument names: one of its endpoints, the base URL they derive from, or, when no endpoint matches, the drain's name. With --org alone, destroys an org drain, which only an Admin can do. An org drain cannot be destroyed from a service.

With --org alone, requires the Admin role.

-a, --agent string
Agent or app name (uses linked service if omitted)
--app string
App name (same as --agent)
-o, --org string
Org; alone, destroys an org drain

Example

$ valet drains destroy https://otlp.example.com
Destroying drain on my-agent agent in acme org... done

valet drains info

Show drain details

valet drains info <url-or-name> [flags]

Show detailed information about a drain.

Displays the drain's name, scope, endpoints, status, header names, and creation timestamp. The argument names one of the drain's endpoints, the base URL they derive from, or, when no endpoint matches, the drain's name. A service's drains include its org's.

Only an Admin sees an org drain's endpoints and header names. Anyone else sees its name, scope, signals, status, and creation time.

With --org alone, shows an org drain.

-a, --agent string
Agent or app name (uses linked service if omitted)
--app string
App name (same as --agent)
-o, --org string
Org; alone, names the org's drains

Example

$ valet drains info https://ingest.example.net
=== Drain (acme org)
  name:       ingest.example.net
  scope:      org
  logs:       https://ingest.example.net/v1/logs
  traces:     https://ingest.example.net/v1/traces
  status:     active
  headers:    Authorization
  created at: 2026-11-10T15:57:49Z

valet emails

List email mailboxes

valet emails [flags]

List, create, inspect, and destroy email mailboxes.

An email mailbox is an org-owned primitive that stores email threads and messages. Creating one mints an address on valet.run; mail sent to that address lands in the mailbox, and binding an email channel wakes an agent on inbound mail. Mailboxes are named by their address everywhere — internal UUIDs never surface. Threads and quarantined messages are named by their RFC 5322 Message-ID, accepted with or without the surrounding angle brackets.

Running "valet emails" with no subcommand lists mailboxes for the org.

-o, --org string
Org to list mailboxes for
$ valet emails --org acme
Mailboxes in acme org:
ADDRESS                      DISPLAY NAME  CREATED
quiet-meadow-x7k2@valet.run  Docs inbox    2026-07-21T00:00:00Z

valet emails create

Create an email mailbox and mint its address

valet emails create [flags]

Create an org-owned email mailbox and mint its address.

The address mints inside the org's namespace. Without --local-part a random haiku local-part is generated; with it, you choose the address's local part (subject to the reserved list). The printed status reports the org email identity's readiness: provisioning (records pending), inbound_ready (receiving; sending pending identity verification), or ready (receiving and sending).

Without --name the display name defaults to the local-part. When no --org flag is provided, uses the default org.

Requires the Admin role.

--local-part string
Chosen local part for the address (default: a generated haiku)
--name string
Display name for the mailbox (default: the minted local-part)
-o, --org string
Org that owns the mailbox

Example

$ valet emails create --name "Docs inbox" --org acme
Creating mailbox in acme org... done, quiet-meadow-x7k2@valet.run

valet emails destroy

Destroy an email mailbox

valet emails destroy <address> [flags]

Permanently destroy an email mailbox by its address.

This action cannot be undone. The address is tombstoned forever (never re-minted), inbound mail stops, and a bound email channel is soft-deleted with the mailbox — the two share a lifecycle. When no --org flag is provided, uses the default org.

Requires the Admin role.

-o, --org string
Org that owns the mailbox

Example

$ valet emails destroy quiet-meadow-x7k2@valet.run --org acme
Destroying quiet-meadow-x7k2@valet.run in acme org... done

valet emails info

Show mailbox details

valet emails info <address> [flags]

Show detailed information about an email mailbox by its address.

Displays the mailbox's display name, creation time, and its thread, message, and quarantine counts. When no --org flag is provided, uses the default org.

-o, --org string
Org that owns the mailbox

Example

$ valet emails info quiet-meadow-x7k2@valet.run --org acme
=== Mailbox: quiet-meadow-x7k2@valet.run in acme org
  display name: Docs inbox
  created:      2026-07-21T00:00:00Z
  threads:      3
  messages:     7
  quarantine:   2

valet emails quarantine

List quarantined messages

valet emails quarantine [<address>] [flags]

List the org's quarantined inbound messages — the spam folder.

Pass a mailbox address to narrow the list to one mailbox. Quarantined messages are stored but not delivered to the agent; release one with "valet emails quarantine release" to re-run ingest (the "not spam" button). When no --org flag is provided, uses the default org.

-o, --org string
Org that owns the mailboxes

Example

$ valet emails quarantine --org acme
Quarantined messages in acme org:
MESSAGE-ID  MAILBOX                      FROM                 SUBJECT  CREATED
spam@host   quiet-meadow-x7k2@valet.run  spammer@example.com  You won  2026-07-21T00:00:00Z

valet emails quarantine release

Release a quarantined message

valet emails quarantine release <message-id> [flags]

Release a quarantined message by its RFC 5322 Message-ID, re-running ingest (the "not spam" button).

Releasing re-runs the inbound pipeline for the message: it is threaded, stored, and — if the mailbox has a bound channel — wakes the agent. The Message-ID is accepted with or without the surrounding angle brackets, so shell quoting is never a trap. When no --org flag is provided, uses the default org.

Requires the Admin role.

-o, --org string
Org that owns the mailbox

Example

$ valet emails quarantine release '<spam@host>' --org acme
Releasing message... done

valet emails threads

List a mailbox's threads

valet emails threads <address> [flags]

List the threads in an email mailbox by the mailbox address.

Each row shows the thread's root RFC 5322 Message-ID, subject, message count, and last-message time. Pass a Message-ID to "valet emails threads info" to read a single thread. When no --org flag is provided, uses the default org.

-o, --org string
Org that owns the mailbox

Example

$ valet emails threads quiet-meadow-x7k2@valet.run --org acme
Threads in quiet-meadow-x7k2@valet.run:
MESSAGE-ID  SUBJECT  MESSAGES  LAST
abc@host    Invoice  4         2026-07-21T00:00:00Z

valet emails threads info

Show a thread by its root Message-ID

valet emails threads info <message-id> [flags]

Show a single email thread and its messages by the thread's root RFC 5322 Message-ID.

The Message-ID is accepted with or without the surrounding angle brackets, so shell quoting is never a trap. Messages are listed in delivery order. When no --org flag is provided, uses the default org.

-o, --org string
Org that owns the mailbox

Example

$ valet emails threads info '<abc@host>' --org acme
=== Thread: abc@host
  subject: Invoice
  mailbox: quiet-meadow-x7k2@valet.run
  last:    2026-07-21T00:00:00Z
  MESSAGE-ID  FROM                DIRECTION  STATUS    CREATED
  abc@host    sender@example.com  inbound    ingested  2026-07-21T00:00:00Z

valet env

List env vars

valet env [flags]

Manage environment variables for orgs, agents, and apps.

Env vars come in two kinds. Secret vars (the default) hold credentials used by connectors and channels at runtime -- the agent can invoke tools that depend on them but never sees the values. Plain vars are delivered to the agent's environment as ordinary unix environment variables, readable from bash ($NAME) and from code the agent writes, and their values are displayed in list output.

Reference an env var of either kind in a connector with {{NAME}} syntax:

  valet env set GITHUB_TOKEN=ghp_xxx
  valet connectors create gh --transport command \
    --command gh --env GITHUB_TOKEN={{GITHUB_TOKEN}}

Each env var is scoped to either an org or a service (an agent, app, or site), and a name is unique within its scope across both kinds. Use --org to manage org-scoped env vars. Use --agent or --app (or run from a linked directory) to manage a service's env vars; --app is the same flag under the name an app owner expects.

Running "valet env" with no subcommand lists env vars.

Listing a service shows the effective environment it sees: its own vars plus the org vars it inherits, each tagged with its kind and scope. The scope names the service's kind, so an app's own vars read "app". When a service's var has the same name as an org var, the service value wins and the row is marked "overrides org". Plain values are shown inline; secret values are masked.

-a, --agent string
Agent to list env vars for
--app string
App to list env vars for (same as --agent)
-o, --org string
Org to list env vars for
$ valet env --agent abb-luma-bot
Environment for abb-luma-bot agent in valetdotdev org:
GITHUB_TOKEN    secret  •••        agent (overrides org)
REGION          plain   us-east-1  org (inherited)
STRIPE_API_KEY  secret  •••        org (inherited)

$ valet env --app checkout
Environment for checkout app in acme org:
DATABASE_HOST   secret  •••  app
DATABASE_URL    secret  •••  app
STRIPE_API_KEY  secret  •••  org (inherited)

valet env set

Set env vars

valet env set <NAME=VALUE>... [flags]

Create or update one or more env vars for an org, agent, or app.

Env vars are secret by default: the agent can invoke tools that depend on them but never sees the values. Pass --plain for values the agent should read directly from its environment (a region, a base URL, a customer identifier). Plain values are displayed in list output; secret values never are.

Sets the named env vars in a single atomic operation -- either all are persisted or none are. All vars in one invocation share a kind. Values are encrypted before storage. Setting an env var that already exists overwrites its value, and changes its kind in place when you pass the other kind.

Env vars of either kind can be referenced by connectors and channels via {{NAME}}. Plain vars are additionally delivered to the agent's environment, readable from bash ($NAME) and from code the agent writes.

Use --org to set org-scoped env vars. Use --agent or --app (or run from a linked directory) to set a service's env vars. When you belong to multiple orgs with services of the same name, pass --org as well to disambiguate.

Waits for the agent or app to become ready after setting its env vars. Use --no-wait to skip the readiness check.

With --org, requires the Admin role.

-a, --agent string
Agent to set the env var for
--app string
App to set the env var for (same as --agent)
--no-wait
Skip waiting for the agent or app to become ready
-o, --org string
Org to set the env var for
--plain
Set kind plain: deliver values to the agent environment and display them (default: secret)

Example

$ valet env set GITHUB_TOKEN=ghp_abc123
Setting GITHUB_TOKEN on my-agent agent in acme org... done
Set GITHUB_TOKEN (secret)
Waiting for agent to start... done

$ valet env set REGION=us-east-1 --plain --agent my-agent
Setting REGION on my-agent agent... done
Set REGION (plain)
Waiting for agent to start... done

$ valet env set LOG_LEVEL=debug --plain --app checkout
Setting LOG_LEVEL on checkout app... done
Set LOG_LEVEL (plain)
Waiting for app to start... done

$ valet env set A=1 B=2 C=3 --plain --org my-org
Setting A, B, C in my-org org... done
Set 3 env vars (plain)

valet env unset

Unset an env var

valet env unset <NAME> [flags]

Remove an env var for an org, agent, or app.

Deletes the named env var of either kind and reports the kind that was removed. If the var is referenced by a connector or channel (via {{NAME}}), or an org var by a checker's header, the command fails unless --force is passed.

Use --org to remove an org-scoped env var. Use --agent or --app (or run from a linked directory) to remove a service's env var. When you belong to multiple orgs with services of the same name, pass --org as well to disambiguate.

Waits for the agent or app to become ready after removing its env var. Use --no-wait to skip the readiness check.

With --org, requires the Admin role.

-a, --agent string
Agent to unset the env var for
--app string
App to unset the env var for (same as --agent)
--force
Force unset even if referenced by connectors, channels, or checkers
--no-wait
Skip waiting for the agent or app to become ready
-o, --org string
Org to unset the env var for

Example

$ valet env unset REGION
Unsetting REGION on my-agent agent in acme org... done
Unset REGION (plain)
Waiting for agent to start... done

$ valet env unset SLACK_TOKEN --agent my-agent
Unsetting SLACK_TOKEN on my-agent agent... done
Unset SLACK_TOKEN (secret)
Waiting for agent to start... done

$ valet env unset LOG_LEVEL --app checkout
Unsetting LOG_LEVEL on checkout app... done
Unset LOG_LEVEL (plain)
Waiting for app to start... done

$ valet env unset API_KEY --org my-org
Unsetting API_KEY in my-org org... done
Unset API_KEY (secret)

valet logs

Show recent logs for an agent or app

valet logs [flags]

Show recent log records from an agent or app.

By default, prints the last 100 historical log lines and exits. Use -n to change the number of lines or -n 0 to skip history entirely. Pass -f/--follow to keep the stream open and tail live log records until interrupted with Ctrl+C.

The service is determined by the --agent or --app flag or the linked service in the current directory. --app is the same as --agent.

-a, --agent string
Agent or app to show logs for (uses linked service if omitted)
--app string
App to show logs for (same as --agent)
-f, --follow
Stream log records as they arrive (default: dump and exit)
-n, --num int32
Number of historical log lines to show (0 to skip history; default: 100)
-o, --org string
Org that owns the agent or app
$ valet logs --agent my-agent
2026-02-23T10:15:32Z agent web.1 INFO Starting request handler
2026-02-23T10:15:33Z valet web.1 INFO Request processed

$ valet logs -a my-agent -n 10
$ valet logs -a my-agent -n 1000 -f
Streaming logs for my-agent agent in acme org...
$ valet logs -a my-agent -n 0 -f

$ valet logs --app checkout -n 0 -f
Streaming logs for checkout app in acme org...

valet manifests

Create and inspect agent manifest files

Create, validate, and inspect valet.yaml manifest files.

Run subcommands to generate a manifest for an existing agent or to check that a manifest conforms to the schema (including story and per-service UI copy constraints).

valet manifests create

Generate a valet.yaml for an existing agent

valet manifests create [name] [flags]

Generate a minimal valet.yaml for an existing agent by reading the agent's current configuration from the API.

Writes valet.yaml to the current directory (or --dir). Refuses to overwrite an existing manifest. The agent is determined by the positional argument, the --agent flag, or the linked agent in the current directory.

The generated manifest populates name, connectors, and channels from the API and leaves placeholder values for display_name, description, and category — these are not stored on the agent record and need to be filled in by hand before the manifest can be validated.

Only catalog-backed connectors and channels are emitted. Agent-owned (non-catalog) entries and inline cron/heartbeat channels are skipped and need to be added by hand.

-a, --agent string
Agent to generate a manifest for (uses linked agent if omitted)
--dir string
Directory to write valet.yaml into (default: cwd)
-o, --org string
Org that owns the agent

Example

$ valet manifests create my-agent
Wrote /path/to/valet.yaml
  Fill in display_name, description, and category before publishing.

$ valet manifests create my-agent --dir /tmp/agent-checkout

valet manifests validate

Validate a manifest file

valet manifests validate [path] [flags]

Validate a valet.yaml manifest in two passes.

The schema pass checks syntax, required fields, unknown fields, and the story and per-service UI constraints. The online pass then resolves every connector and channel 'catalog:' reference by name against the control-plane catalog — the same name lookup the attach/deploy path runs. This closes the gap where a manifest passes local validation but fails at deploy because it references a catalog entry that is not there. References are resolved by name, so unlisted entries (kept out of catalog discovery but still referenceable, like the runtime 'valet' connector) are accepted.

When path is omitted, reads valet.yaml from the current directory. Exits 1 and prints errors to stderr when either pass fails.

The online pass requires authentication and network access. Pass --offline to run the schema pass only (useful in CI or offline environments). Manifests that declare no catalog references skip the online pass automatically.

--offline
Validate schema only; skip checking catalog references against the control plane (default: false)

Example

$ valet manifests validate
/path/to/valet.yaml is valid

$ valet manifests validate --offline
/path/to/valet.yaml is valid

$ valet manifests validate ../other-agent/valet.yaml
Error: manifest references unknown catalog entries
  connector "githubb" not found in catalog

valet memories

List memories

valet memories [flags]

Manage durable memories for an agent.

Memories are key/value facts the agent can recall across sessions. The runtime may also write unkeyed memories; those appear in list output for audit, but set and unset operate by key.

Running "valet memories" with no subcommand lists memories.

Use --agent (or run from a linked directory) to choose the agent. Pass --org as well when multiple orgs have an agent with the same name.

-a, --agent string
Agent to list memories for
-o, --org string
Org containing the agent
$ valet memories --agent abb-luma-bot
=== Memories: abb-luma-bot agent

=== schema/users
  ID:      019a...
  Key:     schema/users
  Content: users(id, email)
  Pinned:  yes
  Created: 2026-06-01T12:00:00Z
  Updated: 2026-06-01T12:00:00Z
  Expires: never
  Origin:  none

valet memories set

Set a memory

valet memories set <KEY=VALUE> [flags]

Create or update one keyed memory for an agent.

If the key already exists, content is replaced in place. Passing --pin marks the memory for pinned-context injection. Omitting --pin writes the memory as unpinned.

Pass --ttl to set an expiry in seconds from now. Omitting --ttl creates or replaces the memory without an expiry.

-a, --agent string
Agent to set the memory for
-o, --org string
Org containing the agent
--pin
Pin the memory
--ttl int64
Expire the memory after this many seconds

Example

$ valet memories set schema/users='users(id, email)' --pin --agent my-agent
Setting schema/users on my-agent agent... done
Set schema/users

valet memories unset

Unset a memory

valet memories unset <KEY> [flags]

Remove one keyed memory from an agent.

This removes the memory without restarting the agent. Runtime turns after removal no longer recall or pin that key.

-a, --agent string
Agent to unset the memory for
-o, --org string
Org containing the agent

Example

$ valet memories unset schema/users --agent my-agent
Unsetting schema/users on my-agent agent... done
Unset schema/users

valet new

Scaffold an agent project

valet new <name> [flags]

Create a new agent project directory with starter files.

Scaffolds a directory with SOUL.md, AGENTS.md, CLAUDE.md, a placeholder valet.yaml, and empty skills/ and channels/ subdirectories. The project is ready for customization — edit SOUL.md to define your agent, fill in the manifest's display_name/description/category, then run "valet agents create" to deploy it.

By default, creates the directory under the current working directory. Use --dir to specify a different location.

--dir string
Directory to create the project in (default: ./<name>)
$ valet new my-agent
Created agent project my-agent

  my-agent/
    SOUL.md        Agent personality and behavior
    AGENTS.md      Conventions for coding agents
    CLAUDE.md      Points Claude Code at AGENTS.md
    valet.yaml     Manifest describing connectors and channels
    skills/        Custom skills (add .md files)
    channels/      Channel prompts (add .md files)

$ valet new my-agent --dir ~/projects/my-agent

valet orgs

List organizations

valet orgs [flags]

List, create, and manage organizations.

Organizations let teams share agents and connectors. Running "valet orgs" with no subcommand lists all organizations you belong to.

valet orgs create

Create an organization

valet orgs create <name> [flags]

Create a new organization.

Creates an organization with the given name and adds you as the first member. Organization names must be unique. The new org is automatically set as the default org.

Example

$ valet orgs create my-org
Creating org... done, my-org
Default org set to my-org.

valet orgs destroy

Destroy an organization

valet orgs destroy <name> [flags]

Permanently destroy an organization.

Removes the organization and all of its members and invitations. This action cannot be undone. If the org you destroy is the current default org, the default is cleared.

Destroy asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

Requires the Admin role.

--yes
Skip the confirmation prompt

Example

$ valet orgs destroy my-org
This destroys my-org and everything in it. It cannot be undone. Continue? (y/N) y
Destroying my-org... done
Default org cleared.

$ valet orgs destroy my-org --yes
Destroying my-org... done

valet orgs info

Show organization details

valet orgs info <name> [flags]

Show detailed information about an organization.

Displays the organization's name and creation date.

Example

$ valet orgs info my-org
Name:       my-org
Created:    2025-01-15T10:30:00Z

valet orgs invite

Invite a member to an organization

valet orgs invite <name> <email> [flags]

Invite a user to join an organization by email.

Sends an invitation that the user can accept with "valet orgs join". Where the installation adds people directly, as Valet Dedicated does, the person must already have signed in. Valet adds them at once, sends no invitation, and prints "Added <email> to <org>." Without --role, the invitee joins with the installation's default role: Admin in Valet Cloud, Developer in Valet Dedicated. Inviting an Admin requires the Admin role.

--role string
Role the invitee joins with: admin or developer (default: the installation's default role)

Example

$ valet orgs invite my-org alice@example.com
Inviting alice@example.com to my-org... done

valet orgs join

Join an organization using an invitation code

valet orgs join <code> [flags]

Join an organization using an invitation code.

Accepts a pending invitation and adds you as a member of the organization. The code is provided by an existing member who invited you. The joined org is automatically set as the default org.

Example

$ valet orgs join K3MZQ7XR2VNAW4PJ6TLHB5DYCE
Joined my-org.
Default org set to my-org.

valet orgs leave

Leave an organization

valet orgs leave <name> [flags]

Leave an organization you belong to.

Removes you from the organization. You will lose access to the organization's agents and connectors. If the org you leave is the current default org, the default is cleared.

Example

$ valet orgs leave my-org
Left my-org.
Default org cleared.

valet orgs members

List members and invitations for an organization

valet orgs members <name> [flags]

List members and pending invitations for an organization.

Shows all current members and any outstanding invitations that have not yet been accepted.

Example

$ valet orgs members my-org
=== Members
alice@example.com
bob@example.com

=== Pending Invitations
carol@example.com

valet orgs remove

Remove a member from an organization

valet orgs remove <name> <email> [flags]

Remove a member from an organization by email.

Removal prevents new member-authorized access. Existing scoped tokens and grants keep their own expiration and revocation rules.

Requires the Admin role.

Example

$ valet orgs remove my-org alice@example.com
Removing alice@example.com from my-org... done

valet orgs revoke

Revoke a pending organization invitation

valet orgs revoke <name> <email> [flags]

Revoke a pending invitation to an organization.

Cancels an invitation that has not yet been accepted. The invitation code will no longer be valid.

Requires the Admin role.

Example

$ valet orgs revoke my-org alice@example.com
Revoking invitation for alice@example.com... done

valet orgs role

Give a member of an org a role

valet orgs role <email> <admin|developer> [flags]

Give a member of an org a role.

A Developer builds and runs sites, apps, agents, and skills. An Admin can also manage members, roles, billing, org settings, and secret reveal. An org always keeps at least one Admin.

Requires the Admin role.

-o, --org string
The org (default: the linked or default org)

Example

$ valet orgs role bo@acme.com admin
bo@acme.com is now an Admin of acme.

valet orgs set-default

Set the default organization

valet orgs set-default <name> [flags]

Set the default organization used by subsequent commands.

The named org must be one you already belong to. Use "valet orgs" to see the orgs you are a member of; use "valet orgs join" to accept an invitation. Exits with code 1 if the named org is not in your membership list.

Example

$ valet orgs set-default my-org
Default org set to my-org.

valet policies

List release policies

valet policies [flags]

Manage the release policies of an org.

A policy is a checker, such as a secret scanner or a dependency audit, configured for the org. It evaluates every release before the release goes live. A policy either monitors or blocks. A monitor policy records its findings. A blocking policy holds the release until it passes. If it reports a finding at or above its severity, or fails to run, the release is refused and the previous release stays live. "valet deploy" waits for blocking policies.

Running "valet policies" with no subcommand lists the org's policies. Use "valet policies checkers" to see the checkers you can configure, "valet policies add" and "valet policies remove" to change the list, and "valet policies show" to read the evaluation of one release.

The LAST 30 DAYS column counts the policy's evaluations over the last 30 days. A blocking policy lists its evaluations, then the ones it blocked and the ones that errored, leaving out a zero count. A monitor policy lists its evaluations, then how many a policy blocking at that severity would have held, for critical, high, and medium, leaving out a severity with none, and the evaluations that errored. It reads "-" when the policy has not been evaluated, or the server does not report evaluations.

Below the table, "Last errors in the last 30 days" gives each policy's latest error, the reason the policy could not evaluate a release.

Use --org to pick the org (or run from a linked directory).

-o, --org string
Org to list policies for
$ valet policies
=== Policies in acme org
NAME          CHECKER          ENFORCEMENT    LAST 30 DAYS                                        SETTINGS
secrets       catalog:secrets  block at high  41 evaluations, 3 blocked, 1 errored                -
dependencies  catalog:osv      monitor        41 evaluations, would block 3 at high, 7 at medium  -

valet policies add

Add or replace a policy

valet policies add <name> --checker <checker> [flags]

Add a policy to an org, or replace the one with the same name.

A policy is a checker, configured with settings, that evaluates every release. It either monitors or blocks. A monitor policy records its findings and never holds a release. A blocking policy holds the release until it passes: a finding at or above its severity, or a checker that fails to run, refuses the release.

A policy monitors unless you pass --block-at. Pass --monitor to say so explicitly. Give --block-at a severity (info, low, medium, high, or critical) to block. The two flags are mutually exclusive.

Add checks the name, the checker, and the setting names before it asks for anything. Pass the checker's settings with --set key=value, repeated. Use --set key=@file to read a value from a file. Run "valet policies checkers" to see each checker's settings. When a new policy is missing a required secret setting, add prompts for it on a terminal and does not echo it. Without a terminal, pass it with --set key=@file.

Adding a policy with an existing name replaces it. Pass every non-secret setting again. A secret setting you omit keeps its stored value when the checker is unchanged, so you can change a policy's enforcement without entering its token again.

A change to a policy applies to releases not yet decided. Changing a policy's enforcement or settings never changes a decided evaluation, and a running policy evaluation keeps the checker and enforcement it started with. A running policy evaluation whose checker hasn't started yet uses the current settings. Removing a policy, or changing its checker, cancels its running policy evaluations, so releases that waited only on it go ahead.

Requires the Admin role.

--block-at string
Hold releases with a finding at or above this severity (info, low, medium, high, critical)
--checker string
Checker to run (see "valet policies checkers")
--monitor
Record findings without holding releases (default)
-o, --org string
Org that owns the policy
--set stringArray
Checker setting as key=value or key=@file, repeatable

Example

$ valet policies add secrets --checker catalog:secrets --block-at high
Added policy secrets in acme org (block at high)

$ valet policies add dependencies --checker catalog:osv --monitor
Added policy dependencies in acme org (monitor)

$ valet policies add app-secrets --checker catalog:secrets --set exclude=testdata/*,*.pem
Added policy app-secrets in acme org (monitor)

valet policies checkers

List the checkers you can configure

valet policies checkers [flags]

List the checkers an org can configure as policies, and add, remove, or verify an org's own.

A checker is a kind of policy; "valet policies add --checker" configures one. Each checker shows its id, then its display name, then what it does. Each checker lists the settings it takes in a table with the columns FIELD, REQUIRED, SECRET, and DESCRIPTION. Pass a setting to "valet policies add" with --set key=value, or --set key=@file to read the value from a file. Secret settings are write-only: Valet never shows them again.

An org checker also lists its origin, why it is unavailable, its URL, its approved files, its headers as written (a credential is a {{NAME}} reference, never its value), when Valet last tried to describe it, whether or not that worked, and the last error from a describe or validate. Use "valet policies checkers add", "remove", and "verify" to manage org checkers.

-o, --org string
Org to list checkers for

Example

$ valet policies checkers
=== Checkers
catalog:osv  Dependencies (OSV)
  Finds known-vulnerable dependencies in a release through OSV.dev
  FIELD   REQUIRED  SECRET  DESCRIPTION
  ignore  no        no      Comma-separated advisory ids to skip
catalog:secrets  Secrets (gitleaks)
  Finds credentials in a release's source with gitleaks' default rules
  FIELD    REQUIRED  SECRET  DESCRIPTION
  exclude  no        no      Comma-separated path globs of source files to skip
org:snyk  Snyk Open Source
  Finds vulnerable dependencies with Snyk
  Origin: organization
  URL: https://snyk-checker.acme.valet.run
  Approved files: build
  Header: Authorization: Bearer {{SNYK_CHECKER_TOKEN}}
  Last describe attempt: 2026-10-20T14:03:11Z
  Last error: its endpoint answered HTTP 401 to describe

valet policies checkers add

Add or replace an org checker

valet policies checkers add <name> --url <url> [flags]

Add an org checker, or replace the one with the same name.

An org checker is an HTTPS endpoint that implements the Checker API. Valet calls it for every release a policy that names it evaluates, and sends it links to the release's source or build, as the endpoint asks. Adding a checker agrees to send those files to its URL.

Pass headers with --header, repeated. Write a credential as a reference to a secret org env var, such as --header 'Authorization: Bearer {{SNYK_TOKEN}}'; set it first with valet env set --org. Valet resolves it at each call, so rotating the variable needs no change here. A header named Authorization, Proxy-Authorization, Cookie, X-Api-Key, or Api-Key, or ending in -Token, -Secret, or -Key, must hold a reference. Every member sees any other header's value as written.

Any member can add a checker, and its headers can name any secret org env var, which sends that secret to the checker's URL.

Replacing a checker takes effect on the next call of every policy that names it. A new URL or new headers also restart its running evaluations at the new endpoint. Pass every header again.

Requires the Admin role.

--header stringArray
Header as "Name: value", repeatable
-o, --org string
Org that owns the checker
--url string
The endpoint's base URL (https)

Example

$ valet policies checkers add snyk --url https://snyk-checker.acme.valet.run --header 'Authorization: Bearer {{SNYK_CHECKER_TOKEN}}'
Added checker org:snyk in acme org (Snyk Open Source; approved files: build)
Valet sends build of every release a policy that names org:snyk evaluates to https://snyk-checker.acme.valet.run.

valet policies checkers remove

Remove an org checker

valet policies checkers remove <name> [flags]

Remove an org checker.

Valet refuses while a policy names the checker. Remove the policy first with "valet policies remove", or point it at another checker.

Requires the Admin role.

-o, --org string
Org that owns the checker

Example

$ valet policies checkers remove snyk
Removed checker org:snyk from acme org

valet policies checkers verify

Check that an org checker's endpoint works

valet policies checkers verify <name> [flags]

Check that an org checker's endpoint answers.

Valet calls the endpoint's describe, with the saved headers, and reports whether it answered and how long it took. Pass --set key=value, repeated, or key=@file, to also check settings a policy would give the checker. Verify sends no release files. Within 10 seconds of the last describe, Valet reuses that result and reports no latency; it still checks any settings. It exits 1 when the endpoint fails or refuses the settings.

Requires the Admin role.

-o, --org string
Org that owns the checker
--set stringArray
Checker setting as key=value or key=@file, repeatable

Example

$ valet policies checkers verify snyk --set snyk_org=acme-prod
Verified org:snyk in acme org: OK in 412 ms

$ valet policies checkers verify snyk
Error: org:snyk failed verification: its endpoint answered HTTP 401 to describe

valet policies remove

Remove a policy

valet policies remove <name> [flags]

Remove a policy from an org.

New releases no longer evaluate the policy. A change to a policy applies to releases not yet decided. Changing a policy's enforcement or settings never changes a decided evaluation, and a running policy evaluation keeps the checker and enforcement it started with. A running policy evaluation whose checker hasn't started yet uses the current settings. Removing a policy, or changing its checker, cancels its running policy evaluations, so releases that waited only on it go ahead.

Requires the Admin role.

-o, --org string
Org that owns the policy

Example

$ valet policies remove app-secrets
Removing policy app-secrets from acme org... done

valet policies show

Show a release's evaluation and its findings

valet policies show [<id>] [flags]

Show the release evaluation of one release: its status, each policy's evaluation, and each finding with its file or package and how to fix it.

Without an id, show reads the service's latest release evaluation. Pass an evaluation id to read an older one. A finding that blocks is marked [blocks]. The deploy line says whether the release is waiting, live, or why it was refused. Decided is when the evaluation reached its status. Each policy ends with how long its evaluation took.

Use --agent (or run from a linked directory) to pick the service.

-a, --agent string
Service to show the release evaluation for (uses linked service if omitted)
-o, --org string
Org that owns the service

Example

$ valet policies show -a support-bot
=== Release evaluation 0192f1c3
  Service:  support-bot
  Commit:   9f2c1ab
  Status:   blocked
  Deploy:   deploy.policy_blocked
  Message:  acme's policies blocked support-bot's changes: secrets found 1 finding at high or above. Nothing was deployed; the current release is still live. Fix it and deploy again.
  Started:  2026-10-18T10:30:00Z
  Decided:  2026-10-18T10:30:04Z
=== Policies
  secrets        catalog:secrets  blocked (block at high)  4s
    high  config.yaml:3  Possible AWS access key in the source (gitleaks/aws-access-token) [blocks]
      Fix: Remove it from the source, rotate it, and set it with valet env set
  secrets-audit  catalog:secrets  passed (monitor)         100ms

valet ps

List processes for an agent or app

valet ps [flags]

List all processes for a deployed agent or app.

Shows each process with its size, current state, uptime, release version, and container ID. economy-1x stops after 30 minutes without traffic and starts on the next request; standard-1x never stops. While a rollout is in progress, the release column reads "v6 → v7": the container runs v6 and the process targets v7. A crashed process adds a line with the first line of its crash reason. An app has one process per Procfile process type and count, named like web.1 and worker.1.

The service is determined by the --agent or --app flag or the linked service in the current directory. --app is the same as --agent.

-a, --agent string
Agent or app to list processes for (uses linked service if omitted)
--app string
App to list processes for (same as --agent)
-o, --org string
Org that owns the agent or app
$ valet ps --agent my-agent
Processes for my-agent agent in acme org: 2 processes
my-agent.0	economy-1x	up	2h3m	v5	6e82d4187b0958
my-agent.1	economy-1x	up	2h3m	v5	6e82d418b62d78

$ valet ps --app checkout
Processes for checkout app in acme org: 2 processes
web.1	standard-1x	up	41m	v7	3d8e5617c42908
worker.1	economy-1x	up	41m	v7	3d8e5617c51a78

$ valet ps --app checkout
Processes for checkout app in acme org: 2 processes
web.1	economy-1x	up	2m	v6 → v7	3d8e5617c42908
worker.1	economy-1x	crashed	8s	v7	3d8e5617c51a78
  reason: exit status 1: Error: Cannot find module 'express'

valet ps restart

Restart all processes for an agent or app

valet ps restart [flags]

Restart all processes for a deployed agent or app by replacing their containers using the current release. This is useful for picking up changed environment variables or recovering from a stuck state without deploying a new release.

A restart cuts any in-flight conversations immediately — unlike a deploy, which lets a busy container finish its work before replacing it. That forcefulness is the point: it is the escape hatch for a wedged agent.

The service is determined by the --agent or --app flag or the linked service in the current directory. --app is the same as --agent.

For an app, restart then waits for each process to come up on a new container, printing a line as each changes. It exits 0 when every process is up (or idle), and 1 if one crashes or --wait-timeout passes. --no-wait returns once the restart is requested.

-a, --agent string
Agent or app to restart (uses linked service if omitted)
--app string
App to restart (same as --agent)
--no-wait
Return once the restart is requested, without waiting for an app's processes
-o, --org string
Org that owns the agent or app
--wait-timeout duration
How long to wait for an app's processes to come up

Example

$ valet ps restart --agent my-agent
Restarting my-agent agent in acme org... done

$ valet ps restart --app checkout
Restarting checkout app in acme org... done
web.1     up       v3
Restarted: 1 process up

valet ps scale

Scale processes for an agent or app

valet ps scale <process>=<value>... [flags]

Scale an agent or an app.

For an agent, pass a single "agent=<value>" pair. The right side of "=" is a model ID, a process count, a size, "model:count", or "count:size". Each value you leave out keeps its current setting. Today an agent's count must be 0 or 1.

For an app, pass one or more "<type>=<value>" pairs naming process types from its Procfile. The value is a count ("web=2"), a size ("web=standard-1x", which keeps the count), or both ("web=2:standard-1x"). A type's first scale without a size runs on economy-1x. Counts run from 0 up to the platform's per-type maximum.

Sizes:
  economy-1x   stops after 30 minutes without traffic and starts again
               on the next request
  standard-1x  the same machine, and never stops

Changing size restarts the type's processes.

Sites have no processes and cannot be scaled.

Changing an agent's model or count restarts its process. App scale changes never redeploy surviving processes.

The service is determined by the --agent or --app flag or the linked service in the current directory. --app is the same as --agent.

Available agent models:
  claude-sonnet-5
  claude-sonnet-5-5
  gpt-5.6-sol
  gpt-5.6-terra
  gpt-5.6-luna
  gpt-6-luna
  gpt-6.1-sol
  glm-5.3
  glm-5.3-flash
-a, --agent string
Agent or app to scale (uses linked service if omitted)
--app string
App to scale (same as --agent)
-o, --org string
Org that owns the agent or app

Example

$ valet ps scale agent=gpt-5.6-terra
Scaling my-agent agent in acme org... done, model=gpt-5.6-terra

$ valet ps scale agent=0
Scaling my-agent agent in acme org... done, count=0

$ valet ps scale web=2 worker=1 --app checkout
Scaling checkout app in acme org... done, web=2 worker=1

$ valet ps scale web=standard-1x --app checkout
Scaling checkout app in acme org... done, web=standard-1x

$ valet ps scale web=3:standard-1x --app checkout
Scaling checkout app in acme org... done, web=3:standard-1x

valet releases

List releases for an agent, app, site, or skill

valet releases [<name>] [flags]

List the release history for an agent, app, site, or skill, newest first.

A release is a versioned bundle of the service's files. The "(current)" marker flags the release the service is serving now. Only deployed releases appear: a release that was built but never deployed is left out, so the list reconciles with what has shipped. The positional argument, the --agent flag, or the directory's link names the service.

-a, --agent string
Agent, app, site, or skill name (overrides project link)
--app string
App name (same as --agent)
-o, --org string
Org the service belongs to
$ valet releases my-agent
=== Releases on my-agent
  v3    active   abc1234  2026-06-01T12:00:00Z  (current)
  v2    active   def5678  2026-05-20T09:30:00Z
  v1    active   9abcdef  2026-05-01T08:00:00Z

valet releases files

List files in the deployed release

valet releases files [<name>] [flags]

List the files in the agent's currently-deployed release. Reads at the release's commit, not at main HEAD — files published to main but not yet deployed are excluded so the listing reflects what the agent is actually running. Prints "No files." when the agent has no active release. Read-only — to edit, open a draft with `valet drafts create`.

-a, --agent string
Agent, app, site, or skill name (overrides project link)
--app string
App name (same as --agent)
-o, --org string
Org the service belongs to

Example

$ valet releases files my-agent
=== Files on my-agent
valet.yaml
SOUL.md
skills/triage.md

valet releases read

Print a file from the deployed release

valet releases read [<name>] <path> [flags]

Read one file from the agent's currently-deployed release. Reads at the release's commit, not at main HEAD — the file you see is what the agent is actually running. Contents go to stdout verbatim with no header so the output is pipeable. Returns an error when the agent has no active release.

-a, --agent string
Agent, app, site, or skill name (overrides project link)
--app string
App name (same as --agent)
-o, --org string
Org the service belongs to

Example

$ valet releases read my-agent SOUL.md
# triage
...

$ valet releases read my-agent SOUL.md > soul.md

valet resources

List resources

valet resources [flags]

List, create, attach, and destroy resources.

A resource is a named set of env vars your org owns, such as a PostgreSQL database Valet provisions for you. Attaching a resource to an app puts its env vars in the app's environment, so the app reads DATABASE_URL it never set. An app that needs two of the same kind attaches the second with a prefix, so it reads SECONDARY_DATABASE_URL beside the first.

A resource can be attached to any number of apps. Detaching removes the env vars from an app and keeps the resource. Destroying a provisioned resource deletes its data.

Running "valet resources" with no subcommand lists resources attached to the linked app, or every resource in the org with --org.

--app string
App to list resources for
-o, --org string
Org to list resources for
$ valet resources --app checkout
NAME               PLAN                  PREFIX     STATE
checkout-db        valet-postgresql:dev             provisioned
shared-events-db   valet-postgresql:dev  EVENTS     provisioned

$ valet resources --org acme
NAME               PLAN                  STATE        ATTACHMENTS
checkout-db        valet-postgresql:dev  provisioned  1
shared-events-db   valet-postgresql:dev  provisioned  2
scratch-db         valet-postgresql:dev  pending      0

valet resources attach

Attach a resource to an app

valet resources attach <resource-name> [flags]

Attach a resource to an app.

Puts the resource's env vars in the app's environment under their own names, so valet-postgresql sets DATABASE_URL, DATABASE_HOST, and the rest. Use --prefix when the app already has those names: --prefix SECONDARY sets SECONDARY_DATABASE_URL beside the first. The app is redeployed so the new env vars take effect.

The resource must be provisioned. Attaching fails when an env var it would set already exists on the app or its org; unset the env var, or attach with a prefix.

--app string
App to attach the resource to
-o, --org string
Org that owns the resource
--prefix string
Prefix for the attachment's env var names

Example

$ valet resources attach shared-events-db --app checkout --prefix EVENTS
Attaching shared-events-db to checkout app with prefix EVENTS... done
Sets EVENTS_DATABASE_URL, EVENTS_DATABASE_POOLED_URL, EVENTS_DATABASE_HOST,
EVENTS_DATABASE_PORT, EVENTS_DATABASE_NAME, EVENTS_DATABASE_USER,
EVENTS_DATABASE_PASSWORD.

$ valet resources attach shared-events-db --app analytics
Attaching shared-events-db to analytics app... done
Sets DATABASE_URL, DATABASE_POOLED_URL, DATABASE_HOST, DATABASE_PORT,
DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD.

valet resources catalog

List the resources you can create and their plans

valet resources catalog [flags]

List the resources you can create and their plans.

Shows each provider with its plans and the env var names an attachment sets. Create one with "valet resources create <provider>:<plan> <name>". Attach with --prefix to put a word in front of every name.

-o, --org string
Org to list the catalog for

Example

$ valet resources catalog
PROVIDER          NAME              PLANS       ENV VARS
valet-postgresql  Valet PostgreSQL  small, dev  DATABASE_URL, DATABASE_POOLED_URL, DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD

valet resources create

Create a resource

valet resources create <provider>:<plan> <name> [flags]

Create a resource.

Provisions a new resource from a provider and plan, written "<provider>:<plan>" as in "valet-postgresql:dev", under a name that is unique in your org. Run "valet resources catalog" to see the providers and plans.

Provisioning takes a few seconds. With --app (or from a linked app directory) the command waits for the resource to be provisioned and then attaches it, so the app's environment gains the resource's env vars and the app is redeployed; --prefix puts a word in front of every name. Without an app the command returns as soon as the resource is recorded; run "valet resources info" to watch it, and "valet resources attach" to use it.

--app string
App to attach the resource to once it is provisioned
-o, --org string
Org to create the resource in
--prefix string
Prefix for the attachment's env var names

Example

$ valet resources create valet-postgresql:dev checkout-db --app checkout
Creating valet-postgresql:dev checkout-db... done
Provisioning... provisioned
Attaching checkout-db to checkout app in acme org... done
Sets DATABASE_URL, DATABASE_POOLED_URL, DATABASE_HOST, DATABASE_PORT,
DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD.

$ valet resources create valet-postgresql:dev events-db --app checkout --prefix EVENTS
Creating valet-postgresql:dev events-db... done
Provisioning... provisioned
Attaching events-db to checkout app with prefix EVENTS in acme org... done
Sets EVENTS_DATABASE_URL, EVENTS_DATABASE_POOLED_URL, EVENTS_DATABASE_HOST,
EVENTS_DATABASE_PORT, EVENTS_DATABASE_NAME, EVENTS_DATABASE_USER,
EVENTS_DATABASE_PASSWORD.

$ valet resources create valet-postgresql:dev shared-events-db --org acme
Creating valet-postgresql:dev shared-events-db in acme org... done
Attach it once provisioned with
"valet resources attach shared-events-db --app <app>".

valet resources destroy

Destroy a resource and its data

valet resources destroy <name> [flags]

Destroy a resource and its data.

Deletes the resource. For a provisioned database this deletes every table and row, and it cannot be undone. The command asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

A resource attached to any app is refused unless --force is given, which detaches every app first. "valet resources detach" keeps the resource; only destroy deletes it.

--force
Detach from every app and destroy anyway
-o, --org string
Org that owns the resource
--yes
Skip the confirmation prompt

Example

$ valet resources destroy scratch-db
This deletes scratch-db and all of its data. Continue? (y/N) y
Destroying scratch-db in acme org... done

valet resources detach

Detach a resource from an app

valet resources detach <resource-name> [flags]

Detach a resource from an app.

Removes the attachment's env vars from the app's environment and redeploys the app. The resource is untouched; attach it again to restore the env vars.

--app string
App to detach the resource from
-o, --org string
Org that owns the resource

Example

$ valet resources detach shared-events-db --app checkout
Detaching shared-events-db from checkout app... done

valet resources info

Show resource details

valet resources info <name> [flags]

Show detailed information about a resource.

Displays the resource's provider and plan, state, and every attachment with its app, prefix, and the env var names it sets.

State is one of pending, provisioning, provisioned, deprovisioning, deprovisioned, or failed. Only a provisioned resource can be attached. Reason carries the provider's diagnostic when the state is not the one you expected.

-o, --org string
Org that owns the resource

Example

$ valet resources info shared-events-db
=== Resource: shared-events-db in acme org
Name:       shared-events-db
Plan:       valet-postgresql:dev (Valet PostgreSQL)
State:      provisioned
Created:    2026-09-25 14:02 UTC

Attachments:
  app: analytics          DATABASE_URL, DATABASE_POOLED_URL, DATABASE_HOST, ...
  app: checkout   EVENTS  EVENTS_DATABASE_URL, EVENTS_DATABASE_POOLED_URL, ...

$ valet resources info scratch-db
=== Resource: scratch-db in acme org
Name:       scratch-db
Plan:       valet-postgresql:dev (Valet PostgreSQL)
State:      failed
Reason:     neon: create project: 429 too many requests
Created:    2026-09-25 14:02 UTC

Attachments: none

valet run

Send a prompt to an agent and stream the response

valet run <prompt> [flags]

Send a single prompt to a deployed agent and stream back the execution trace.

Creates an ephemeral session, runs the agent loop, and displays text output, tool calls, and timing. The agent is determined by the --agent flag or the linked agent in the current directory. Useful for testing agents, scripting, and programmatic access.

Use --json for machine-readable NDJSON output. Use --timeout to set the maximum execution time (default 10m).

-a, --agent string
Agent to run (uses linked agent if omitted)
--json
Output newline-delimited JSON events
-o, --org string
Org that owns the agent
--timeout duration
Maximum execution time (default: 10m)
$ valet run --agent my-agent "what is 2+2"
> what is 2+2

[tool] Calculator({"expression":"2+2"})
[tool] → 4

The answer is 4.

elapsed: 5s

$ valet run --agent my-agent "hello" --json

valet sessions

List or show sessions

valet sessions [id] [flags]

List, show, and follow inference sessions for an agent.

Running "valet sessions" with no argument lists the sessions belonging to an agent. Passing a session ID shows that session's transcript. The -f/--follow flag streams events as they arrive. The agent is determined by the --agent flag or the linked agent in the current directory.

-a, --agent string
Agent to list sessions for (uses linked agent if omitted)
-f, --follow
Stream events as they arrive (default: dump and exit)
-o, --org string
Org that owns the agent
$ valet sessions --agent my-agent
=== Sessions
01HXYZ000000000000000001	2026-04-16 10:00 UTC	How do I deploy?
01HXYZ000000000000000002	2026-04-15 16:30 UTC	(untitled)

$ valet sessions 01HXYZ000000000000000001 --agent my-agent
[10:00:00] user: How do I deploy?
[10:00:02] assistant: Run "valet deploy".
[10:00:02] tokens: in=1234 out=567

$ valet sessions 01HXYZ000000000000000001 -a my-agent -f
# streams events until Ctrl-C

valet sessions delete

Delete a session

valet sessions delete <id> [flags]

Delete a session by ID.

The session and its transcript are removed from the server and no longer appear in "valet sessions". This action cannot be undone.

Requires the Admin role.

-a, --agent string
Agent that owns this session
-o, --org string
Org that owns the agent

Example

$ valet sessions delete 01HXYZ000000000000000001 --agent my-agent
Deleting session 01HXYZ000000000000000001 on my-agent agent in acme org... done

valet sessions info

Show session details

valet sessions info <id> [flags]

Show detailed information about a session.

Displays the session's status, channel, timestamps, and conversation key. The agent is determined by the --agent flag or the linked agent in the current directory.

-a, --agent string
Agent that owns this session
-o, --org string
Org that owns the agent

Example

$ valet sessions info 01HXYZ000000000000000001 --agent my-agent
=== Session: 01HXYZ000000000000000001 on my-agent agent in acme org
  title:    How do I deploy?
  status:   active
  channel:  ch-webhook
  created:  Thu Apr 16, 2026 10:00 AM UTC
  updated:  Thu Apr 16, 2026 10:05 AM UTC
  conv-key: 019d3c9f-2a10-7c80-9b8a-1e2f3d4a5b6c

valet setup

Set up Valet with guided onboarding

valet setup [flags]

Walk through a guided setup to get started with Valet.

Runs a five-step onboarding flow: authenticate, create an organization, install the Valet plugin for Claude Code, scaffold an agent project, and deploy it. Each step can be skipped if already completed. Press Ctrl+C at any prompt to cancel.

The deploy step works the way valet deploy does: it pushes the project with Git and publishes it. Creating an agent needs Git 2.32 or later on your PATH; setup checks before it scaffolds anything.

$ valet setup
Welcome to Valet!
Let's get you set up.

Step 1 of 5: Log in
✓ Already logged in as alice@example.com

Step 2 of 5: Create an organization
Creating org... done, my-org

Step 3 of 5: Install the Valet plugin for Claude Code
✓ Installed the Valet plugin

Step 4 of 5: Create your first agent
...

Step 5 of 5: Deploy
Creating agent... done, my-agent
Linking directory... done
Reading files... done, 5 files
Creating push for my-agent agent in my-org org... done
Fetching source... done
Pushing source... done
Deploying my-agent agent in my-org org... done, v1
Waiting for agent to start... done

✓ Setup complete!

valet sites

List sites

valet sites [flags]

List, create, rename, and destroy static sites.

A site is a directory of static files served over HTTPS at a name-derived address. Create a site, then run "valet deploy" from the linked directory to publish its content. The URL is live (serving 404s) as soon as the site is created.

Running "valet sites" with no subcommand lists sites in the default organization. Use --org to list sites in a different organization.

-o, --org string
Org to list sites for
$ valet sites
NAME     URL                             VERSION
my-site  https://acme.valet.run/my-site  3

valet sites access

Show or set a site's visibility

valet sites access <name> [public|private|password] [flags]

Show or set who can view a site.

With no mode, prints the site's current access mode. With a mode, moves the site to it:

  private   Members of the owning org, after a Valet login. New sites
            are private by default.
  password  Org members sign in with Valet, or any visitor enters the
            site password. The password is for external users.
  public    Anyone on the internet.

Password mode prompts for a hidden password; pass --password in scripts or agent runs where stdin is not a terminal. Switching away from password mode clears the stored password. Any change signs every current visitor out.

-o, --org string
Org that owns the site
--password string
Password to set (password mode; prompts with hidden input when omitted)

Example

$ valet sites access my-site
my-site access: private

$ valet sites access my-site public
Setting my-site access to public in acme org... done
Anyone can now view this site.

$ valet sites access my-site password
Password:
Setting my-site access to password in acme org... done
Org members sign in with Valet; others enter the password. Sessions last 24 hours.

valet sites claim

Claim an anonymous site into an org

valet sites claim [name] [flags]

Claim an anonymous site published without an account, moving it into an organization permanently.

An anonymous site lives in the shared incubator org, serves at a `try.valet.run` address, and expires. Claiming transfers it into an org you belong to, gives it a permanent URL, and leaves the anonymous site URL redirecting there. The claim consumes the anonymous site's claim token: afterwards the site is managed through org membership like any other.

A claimed site stays public, which a site made with "valet sites create" is not — those are private by default. The anonymous URL redirects to the permanent one, so making the site private at claim time would lock out everyone holding the link the publisher shared. Run "valet sites access <name> private" to change it.

Name the anonymous site on the command line, defaulting to the site this directory is linked to. Its claim token is read from that directory's .valet/config.json, so an anonymous site can only be claimed from the directory it was published from — from anywhere else, use the claim URL printed when the site was created.

--org is required and must name an org you already belong to: this command never guesses where a site should live, and it never creates an org, because an org's name is reserved permanently. For a brand-new org, run "valet orgs create <org>" first, or claim from the browser claim URL printed when the site was created, which does both at once.

Use --name to rename the site on the way in; a name that is already taken is reported rather than silently suffixed. On success the directory's .valet/config.json is rewritten to the new org and name, so "valet deploy" keeps working.

--name string
Rename the site on the way in (default: keep the anonymous site's name)
-o, --org string
Org to claim the site into (required; must already exist)

Example

$ valet sites claim --org acme
Claiming bubbling-brook-1934... done, bubbling-brook-1934 in acme
Updating link... done
URL: https://acme.valet.run/bubbling-brook-1934
The anonymous site URL now redirects here permanently.
This site stays public — anyone with the link can view it.
Make it private with "valet sites access bubbling-brook-1934 private".
Run "valet deploy" to publish changes.

$ valet sites claim bubbling-brook-1934 --org side-projects --name docs
Claiming bubbling-brook-1934... done, docs in side-projects
URL: https://side-projects.valet.run/docs
The anonymous site URL now redirects here permanently.
This site stays public — anyone with the link can view it.
Make it private with "valet sites access docs private".
Run "valet deploy" to publish changes.

valet sites create

Create a site

valet sites create [name] [flags]

Create a new static site.

The site's name becomes the last segment of its address. If the name is omitted, the server generates one. The URL is live immediately and serves 404s until the first deploy. The current directory is linked to the new site so "valet deploy" publishes it.

The site name is optional — if omitted, the server generates one. App, site, and agent names share one namespace within an org: a site cannot take the name of an existing app or agent.

When --org is not specified, the default org is used. The default org is set automatically when you create or join an org.

Use --anonymous to create a site with no Valet account at all. It lands in a shared incubator org, it is public to anyone with the link, it takes a generated name, and it may be removed 36 hours after it is created, unless it is claimed. Its claim token — the only credential that can update, delete, or claim it — is written into .valet/config.json in the current directory, which should not be committed. --anonymous takes no site name and cannot be combined with --org, and it is refused when you are signed in: "valet sites create <name>" followed by "valet sites access <name> public" makes a permanent public site in your own org instead. It also refuses to replace an existing link; pass --relink to mean it.

--anonymous
Create a public site with no account; it may be removed 36 hours after it is created, unless it is claimed (default: false)
-o, --org string
Org that owns the site
--relink
With --anonymous, replace this directory's existing .valet/config.json (default: false)

Example

$ valet sites create my-site
Creating site... done, my-site
Linking directory... done
URL: https://acme.valet.run/my-site
Run "valet deploy" to publish this directory.

$ valet sites create --anonymous
Creating anonymous site... done, bubbling-brook-1934
URL: https://try.valet.run/bubbling-brook-1934
Expires in 3h 54m (2026-07-31 03:14 UTC)
Claim URL: https://valet.dev/claim/RZ2m7q...
Linking directory... done
The claim token is now in .valet/config.json. It is the only credential for this site — do not commit it.
Run "valet deploy" to publish this directory.

valet sites destroy

Destroy a site

valet sites destroy [name] [flags]

Permanently destroy a site and all its releases.

The site's hostname stops serving within seconds. A later app or site in the same organization may reuse its name and hostname. This action cannot be undone. Generated anonymous hostnames remain retired.

Run with no name in a directory linked to an anonymous site to take that site down with the claim token in its .valet/config.json — no account needed. The server is asked first; the link file is removed only after the site is confirmed gone, because the token in it is the only credential the site has. An anonymous site that has already been claimed is refused: it belongs to an org now, and org membership is what governs it.

The command asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

-o, --org string
Org that owns the site
--yes
Skip the confirmation prompt

Example

$ valet sites destroy my-site
This destroys my-site and all its releases. It cannot be undone. Continue? (y/N) y
Destroying my-site site in acme org... done

$ valet sites destroy my-site --yes
Destroying my-site site in acme org... done

$ valet sites destroy --yes
Destroying anonymous site bubbling-brook-1934... done
Removed /home/me/site/.valet/config.json.

valet sites download

Download a deployed site's files

valet sites download <name> [dir] [flags]

Download a site's currently-deployed files into a local directory and link that directory to the site.

This is how one agent or person updates a site another created. A static site has no build step, so its deployed release is the source of truth: the downloaded copy is exactly what the site serves and is ready to edit and redeploy. Any org member with access to the site can download it — the original source is not needed.

Files are written into [dir], defaulting to a new directory named after the site. The directory must be empty unless --force is given; the .git and .valet directories are never written. A .valet/config.json link is written so "valet deploy" from the directory republishes to the same site. Returns an error when the site has no active release.

--force
Write into a non-empty directory
-o, --org string
Org that owns the site

Example

$ valet sites download docs-site
Downloading docs-site... done, 12 files to docs-site/
Linking directory... done
Run "valet deploy" from docs-site to publish changes.

valet sites info

Show site details

valet sites info [name] [flags]

Show detailed information about a site.

Displays the site's org, URL, current release with its deploy age, any attached drains, and any attached connectors under "integrations:" — each one's transport and whether a page served from the site can call it. A conforming connector also lists its live tool names on a nested "tools:" line. Use "valet releases" for the full release history. The site is determined by the positional argument or the linked site in the current directory.

Pass --schemas to print each tool's description and its input schema (the JSON Schema a page's call has to satisfy) instead of just its name — this is the CLI's route to the schemas that back "valet connectors call".

In a directory linked to an anonymous site, this reports that site's standing under the claim token in its .valet/config.json — no account needed. It answers in every state: while the site is live it prints the earliest moment the site may be removed, and once the site has been claimed it prints where it went, which is how a directory left behind by a browser claim finds its site again.

-o, --org string
Org that owns the site
--schemas
Print each attached connector's tool descriptions and input schemas

Example

$ valet sites info docs-site
=== Site: docs-site (acme org)
  org:        acme-corp
  url:        https://apt-lens-2877.valet.run
  release:    v3 (deployed 2h12m ago)
  access:     private (org members only, via Valet login)
  drains:     https://in.logs.example.com/v1/logs (logs; active), https://ingest.example.net/v1/logs (org; logs,traces; active)
  integrations:
    github-mcp       streamable-http  ok
      tools:      search_issues, create_issue
    betterstack-mcp  streamable-http  ok (session)
    stripe-mcp       sse              not usable: requires an interactive OAuth flow

$ valet sites info docs-site --schemas
...
  integrations:
    github-mcp       streamable-http  ok
      tools:
        search_issues — Search issues by query
          {"type":"object","properties":{"query":{"type":"string"}}}
        create_issue
          {"type":"object","properties":{"title":{"type":"string"}}}

$ valet sites info
=== Anonymous site: bubbling-brook-1934
  url:        https://bubbling-brook-1934.try.valet.run
  state:      unclaimed
  Expires in 13h 25m (2026-07-29 04:00 UTC)
  Claim it to keep it.

valet sites rename

Rename a site and its address

valet sites rename <name> <new-name> [flags]

Rename a site and move it to the address the new name derives.

In host mode, the old hostname stops serving and does not redirect. In path mode, the old path stops serving. The same organization may reuse ordinary handles. Compatibility paths and anonymous claim URLs keep redirecting to the site. Handles with redirect or anonymous history remain retired.

Renaming an existing path site in host mode preserves its old path as a redirect. Wait for its org's DNS and HTTPS readiness before renaming. A refused rename keeps the old name and address available.

-o, --org string
Org that owns the site

Example

$ valet sites rename launch-notes release-notes --org acme
Renaming launch-notes site in acme org to release-notes... done, https://release-notes.acme.valet.run

valet sites share

Share a private site by email

valet sites share <name> <email>... [flags]

Share a site with one or more email addresses.

Each address gets an email with a link that opens the site without a Valet account of its own — possession of the mailbox is the credential. The link is a bearer credential: anyone holding the email can open the site, so forwarding it forwards access. Remove a person's access with "valet sites unshare".

Sharing an address that already has a live share re-sends its existing link rather than minting a new one, so a re-send never breaks a copy already sitting in someone's inbox. --message attaches a short note the recipient reads before they click through.

Deadlines are optional and never default. --expires-in stops the link working a fixed time after it is sent; --expires-after-open stops it a fixed time after the recipient first opens it. Durations take forms like 7d, 48h, or 90m ("d" means 24 hours) or a Go duration like 1h30m0s.

--expires-after-open string
Stop the link working this long after it is first opened (e.g. 48h); default: never
--expires-in string
Stop the link working this long after it is sent (e.g. 7d, 48h); default: never
--message string
A short note the recipient reads before they click through (<= 500 characters)
-o, --org string
Org that owns the site

Example

$ valet sites share my-site alice@example.com bob@example.com --message "Take a look before Friday"
Sharing my-site site with 2 people in acme org... done

$ valet sites share my-site alice@example.com --expires-in 7d
Sharing my-site site with 1 people in acme org... done
Anyone with a share email can open the site — forwarding it forwards access.
Remove a person with "valet sites unshare my-site <email>".

valet sites shares

List who a site is shared with by email

valet sites shares <name> [flags]

List a site's live and expired email shares.

STATE is "invited" for a share nobody has opened yet, "opened" once the recipient has, and "not delivered" when the most recent send attempt failed. OPENED is how long ago the recipient last opened the link. EXPIRES shows the remaining deadline and any window after first open. Once opened, only the resolved deadline applies. "-" means unset. Revoked shares never appear here.

Use "valet sites share" to add a share or re-send an existing one, and "valet sites unshare" to remove one.

-o, --org string
Org that owns the site

Example

$ valet sites shares my-site
EMAIL               STATE    OPENED  EXPIRES
alice@example.com   opened   3d ago  -
bob@example.com     invited  -       in 6d

valet sites unshare

Remove one address's access to a shared site

valet sites unshare <name> <email> [flags]

Revoke a site share, so the address's link stops working.

The revocation is permanent: a revoked share is never resurrected by sharing the address again, which starts a new share instead. The address stops seeing the site once the change replicates to the gateway, within seconds.

-o, --org string
Org that owns the site

Example

$ valet sites unshare my-site alice@example.com
Removing alice@example.com from my-site site in acme org... done

valet skills

List configured agent and org skills, and manage org skills

valet skills [flags]

List configured agent and org skills, and manage org skills.

A skill is a versioned folder of instructions — a SKILL.md plus any supporting files — kept in its own Git repository. Each version is a commit. Agents get org skills by attachment, and Valet copies them into each release at deploy time. Attach refs take two forms:

  org:<name>[@vN|@latest]        an org skill
  catalog:<name>                 installs the catalog skill into the
                                 org, or reuses the org's copy, and
                                 attaches it

An unpinned or @latest ref resolves to the newest version at deploy time; @vN pins a specific version.

Running "valet skills --agent <agent>" lists the agent's attached skills. Running "valet skills --org <org>" lists the org's skills, each with its version, access mode, address, origin, and description. "valet skills access" shows or sets who can open a skill's address. Use "valet skills catalog" to browse curated skills and "valet skills attach" to attach a catalog or org skill source to an agent.

Create, publish, clone, rename, and destroy org skills with "valet skills create", "publish", "clone", "rename", and "destroy". Share a skill by email with "valet skills share", and list or remove shares with "valet skills shares" and "valet skills unshare".

-a, --agent string
Agent to list effective skills for
-o, --org string
Org to list skills for

valet skills access

Show or set who can open a skill's address

valet skills access <name> [public|private|password] [flags]

Show or set who can open a skill at its address.

With no mode, prints the skill's access mode and address. A skill has no address until Valet gives it one. With a mode, moves the skill to it:

  private   Members of the owning org, after a Valet login. Every
            skill is private when it is created.
  password  Org members sign in with Valet, or any visitor enters the
            skill password.
  public    Anyone with the link can open and download it.

Password mode prompts for a hidden password; pass --password in scripts or agent runs where stdin is not a terminal. Switching away from password mode clears the stored password. Any change signs every current visitor out.

-o, --org string
Org that owns the skill
--password string
Password to set (password mode; prompts with hidden input when omitted)

Example

$ valet skills access research
research access: private
URL: https://research.acme.valet.run

$ valet skills access research private
Setting research access to private in acme org... done
Only members of the owning org can open this skill, after a Valet login.

valet skills attach

Attach a skill to an agent

valet skills attach <source> [flags]

Attach a skill source to an agent.

Sources must be curated catalog refs or org skill refs:

  catalog:<name>
  org:<name>[@vN|@latest]

A catalog:<name> source installs the catalog skill into the org, or reuses the org's copy if it is already installed, then attaches it. A catalog source takes no version: an install copies the current template. Pin the org's copy with org:<name>@vN.

An org:<name> source that names a built-in, such as org:governance, attaches Valet's default when the org has published no skill of that name. The agent follows Valet's default until the org publishes its own, then follows that.

Use "valet skills catalog" to browse curated skills and "valet skills --org <org>" to list org skill snapshots.

-a, --agent string
Agent to attach the skill to
-o, --org string
Org that owns the agent

Example

$ valet skills attach catalog:research --agent assistant --org acme
Attaching catalog:research to assistant agent in acme org... done, catalog:research

$ valet skills attach org:brand-voice@v2 --agent assistant
Attaching org:brand-voice@v2 to assistant agent... done, org:brand-voice@v2

valet skills catalog

List curated skill catalog entries

valet skills catalog [flags]

List curated skill catalog entries.

Each entry is a Valet-curated template. Install one as the org's own skill with "valet skills create --from catalog:<name>". The command is org-scoped because catalog visibility is controlled by the skills feature gate.

-o, --org string
Org to list catalog skills for

Example

$ valet skills catalog --org acme
research  Research  Research a person or company
posthog   Analytics Summarize PostHog user activity

valet skills clone

Clone an org skill with Git

valet skills clone <name> [dir] [flags]

Clone an org skill with Git.

Clones the skill's latest version into a directory named after the skill, or into dir, and links that directory to the skill. The clone's main branch holds that version's commit. Edit the files there, then publish them with "valet deploy" in the directory, or with "valet skills publish". The clone keeps no Git remote, so it holds no credential.

-o, --org string
Org that owns the skill

Example

$ valet skills clone research
Cloned research v4 from acme org into ./research
Run valet deploy in ./research to publish your changes.

valet skills create

Create an org skill

valet skills create [dir] [flags]

Create an org skill.

Creates the skill a directory's SKILL.md names, links the directory to it, and publishes the directory as its first version. The directory defaults to the current one. Every file in it is published, except the .git and .valet directories. Run "valet deploy" in the directory to publish its next version.

With --from catalog:<name>, installs a copy of that catalog skill instead and reads no directory. The copy is the org's own skill: edit it and publish new versions like any other. It does not change when Valet updates the catalog.

--from string
Install a catalog skill, written catalog:<name>
-o, --org string
Org to create the skill in

Example

$ valet skills create ./research
Created research in acme org: v1

$ valet skills create --from catalog:premortem
Installed premortem from the catalog in acme org: v1

valet skills destroy

Destroy an org skill

valet skills destroy <name> [flags]

Destroy an org skill.

Destroys the skill, its releases, and its repository, and frees its name. A skill attached to an agent can't be destroyed: detach it first. For a built-in skill, Valet's default answers again.

The command asks for confirmation; pass --yes to skip it, which a script must, since the prompt needs a terminal.

-o, --org string
Org that owns the skill
--yes
Skip the confirmation prompt

Example

$ valet skills destroy research
This destroys research and all its releases. It cannot be undone. Continue? (y/N) y
Destroying research in acme org... done

$ valet skills destroy research --yes
Destroying research in acme org... done

valet skills detach

Detach a skill from an agent

valet skills detach <source-or-name> [flags]

Detach a skill from an agent.

Pass the original source ref, such as catalog:research, or the materialized skill name, such as research. The org skill snapshot or catalog entry is not deleted.

-a, --agent string
Agent to detach the skill from
-o, --org string
Org that owns the agent

Example

$ valet skills detach catalog:research --agent assistant --org acme
Detaching catalog:research from assistant agent in acme org... done

$ valet skills detach research --agent assistant
Detaching research from assistant agent... done

valet skills info

Show org skill details

valet skills info <name> [flags]

Show detailed information about an org skill.

Displays the skill's description, its author, its address and access mode, its origin (catalog:<name> for a copy installed from the catalog, custom:manual for one the org created), its active release, whether it is starred, the release history, and the agents that hold it. The Ref line is the form to declare in a manifest's skills: list. An agent that holds the skill follows its active release.

-o, --org string
Org that owns the skill

Example

$ valet skills info premortem
=== Skill: premortem in acme org
  Name:            premortem
  Description:     Run a premortem on any plan
  Author:          Alice Example
  URL:             https://premortem.acme.valet.run
  Access:          private
  Origin:          catalog:premortem
  Active release:  v2
  Content SHA-256: 4bf5c2…
  Starred:         since 2026-07-03T00:00:00Z
  Created:         2026-07-01T00:00:00Z
  Updated:         2026-07-02T00:00:00Z
  Ref:             org:premortem
=== Versions (2)
  v2  4bf5c2…  2048 bytes  2026-07-02T00:00:00Z
  v1  9d01ae…  1024 bytes  2026-07-01T00:00:00Z
=== Held by (1)
  support-bot

valet skills publish

Publish a new version of an org skill

valet skills publish [dir] [flags]

Publish a new version of an org skill.

Publishes the directory as the next version of the skill its SKILL.md names. The directory defaults to the current one. Every file in it is published, except a .git directory, and a file the latest version has that the directory lacks is removed. Files identical to the latest version publish nothing.

The CLI sends the files with Git. A skill can hold up to 500 files and 50 MB, with at most 25 MB per file, and binary files.

-o, --org string
Org that owns the skill

Example

$ valet skills publish ./research
Published research in acme org: v4

$ valet skills publish
research in acme org: no changes since v4

valet skills rename

Rename an org skill

valet skills rename <name> <new-name> [flags]

Rename an org skill.

The skill keeps its history and its attachments. Valet publishes a release whose SKILL.md carries the new name, and every agent that attaches the skill uses the new name from its next start.

If the current directory is linked to the skill, rename updates the link. Edit the name in your own copy of SKILL.md before the next publish.

-o, --org string
Org that owns the skill

Example

$ valet skills rename research deep-research
Renamed research to deep-research (v7).
Attached to support-bot and triage-bot. Update any instructions that name the old skill.

valet skills share

Share a skill by email

valet skills share <name> <email>... [flags]

Share an org skill with one or more email addresses.

Each address gets an email with a link that opens the skill without a Valet account of its own — possession of the mailbox is the credential. The link is a bearer credential: anyone holding the email can open the skill, so forwarding it forwards access. Remove a person's access with "valet skills unshare".

Sharing an address that already has a live share re-sends its existing link rather than minting a new one. --message attaches a short note the recipient reads before they click through.

Deadlines are optional and never default. --expires-in stops the link working a fixed time after it is sent; --expires-after-open stops it a fixed time after the recipient first opens it. Durations take forms like 7d, 48h, or 90m ("d" means 24 hours) or a Go duration like 1h30m0s.

Skill sharing is off until the Valet server enables it. While it is off, the server's refusal is printed and the command exits 1.

--expires-after-open string
Stop the link working this long after it is first opened (e.g. 48h); default: never
--expires-in string
Stop the link working this long after it is sent (e.g. 7d, 48h); default: never
--message string
A short note the recipient reads before they click through (<= 500 characters)
-o, --org string
Org that owns the skill

Example

$ valet skills share brand-voice alice@example.com bob@example.com --message "Our house style"
Sharing brand-voice skill with 2 people in acme org... done
Anyone with a share email can open the skill — forwarding it forwards access.
Remove a person with "valet skills unshare brand-voice <email>".

$ valet skills share brand-voice alice@example.com --expires-in 7d

valet skills shares

List who a skill is shared with by email

valet skills shares <name> [flags]

List a skill's live and expired email shares.

STATE is "invited" for a share nobody has opened yet, "opened" once the recipient has, and "not delivered" when the most recent send attempt failed. OPENED is how long ago the recipient last opened the link. EXPIRES shows the remaining deadline and any window after first open. "-" means unset. Revoked shares never appear here. When the server has sharing by email off, the list still prints, followed by a line saying so.

Use "valet skills share" to add a share or re-send an existing one, and "valet skills unshare" to remove one. While the Valet server has skill sharing off, "share" prints its refusal and exits 1.

-o, --org string
Org that owns the skill

Example

$ valet skills shares brand-voice
EMAIL               STATE    OPENED  EXPIRES
alice@example.com   opened   3d ago  -
bob@example.com     invited  -       in 6d

valet skills show

Print an org skill's SKILL.md

valet skills show <name> [flags]

Print an org skill's SKILL.md.

Prints the org's own skill, or, for a built-in skill the org has not changed, Valet's current default. The SKILL.md goes to stdout and the source line to stderr, so the output can be redirected to a file.

With --path, prints that supporting file, such as reference/guide.md, instead of SKILL.md. With --release, prints that release instead of the active one. "valet releases <skill>" lists the releases.

-o, --org string
Org that owns the skill
--path string
Print this supporting file instead of SKILL.md
--release int32
Print this release instead of the active one

Example

$ valet skills show governance --org acme > SKILL.md
governance in acme org: Valet's default

$ valet skills show premortem
premortem in acme org: v2

$ valet skills show premortem --release 1
premortem in acme org: v1

$ valet skills show premortem --path reference/guide.md

valet skills unshare

Remove one address's access to a shared skill

valet skills unshare <name> <email> [flags]

Revoke a skill share, so the address's link stops working.

The revocation is permanent: a revoked share is never resurrected by sharing the address again, which starts a new share instead. The address stops seeing the skill once the change replicates to the gateway, within seconds.

-o, --org string
Org that owns the skill

Example

$ valet skills unshare brand-voice alice@example.com
Removing alice@example.com from brand-voice skill in acme org... done

valet topics

Read help guides

Read help guides on common Valet workflows and concepts.

Available topics cover getting started, the agent lifecycle, channels and sessions, and MCP connectors. Run "valet topics <name>" to read a specific guide.

valet topics agent-lifecycle

Agent creation, linking, and deployment

valet topics agent-lifecycle [flags]

Agent lifecycle: creation, linking, and deployment.

An agent project is a directory containing a SOUL.md file that defines the agent's personality, skills, and behavior.

Creating an agent:

  $ valet agents create my-agent

This creates the agent on the server, links the current directory to it, and deploys the first release. The directory must contain SOUL.md. When --org is not specified, the default org is used.

Creating from a source:

  $ valet agents create my-agent --from catalog:code-reviewer --org acme
  $ valet agents create my-agent --from github.com/user/repo
  $ valet agents create my-agent --from ./path/to/agent

The --from flag accepts a catalog reference, a Git URL, or a local path. Catalog references scaffold a Valet-curated agent template.

Attaching resources at creation:

  $ valet agents create my-bot --org acme \
      --attach-connector github \
      --attach-channel gh-webhook

Use --attach-connector and --attach-channel to wire org-scoped resources to the agent at creation time.

Linking a directory:

  $ valet agents link my-agent

Links the current directory to an existing agent. Creates a .valet/config.json file so subsequent commands use this agent automatically.

Deploying:

  $ valet deploy

Packages the current directory into a release tarball, uploads it, and activates it. Uses the linked agent name unless one is provided explicitly. Waits for the agent to become ready. Use --no-wait to skip the readiness check.

Agent info:

  $ valet agents info my-agent

Shows detailed information about an agent including its current release, state, attached connectors, channels, and effective environment (env vars with secret values masked and plain values shown inline; manage them with "valet env").

Destroying:

  $ valet agents destroy my-agent

Permanently removes the agent and all its releases. The command asks for confirmation. Pass --yes to skip it; a script must.

valet topics channels

Channels and sessions

valet topics channels [flags]

Channels and sessions.

Channels are message entry points for agents. Each channel has a type and belongs to an org or to one agent. An org channel (webhook or slack) reaches an agent through an attachment, so one org channel can serve several agents.

Channel types:
  - webhook:    Receives HTTP webhooks from third-party services
  - telegram:   Connects a Telegram bot to an agent
  - heartbeat:  Fires a prompt on a fixed interval
  - cron:       Fires a prompt on a cron schedule

Browsing the catalog:

  $ valet channels catalog
  $ valet channels catalog get github-webhook

The catalog contains Valet-curated channel definitions for well-known services. Catalog entries encode signing schemes, event taxonomies, and service-specific behaviors.

Adding from the catalog:

  $ valet channels create github-webhook --org acme
  $ valet channels create github-webhook --org acme --as github-docs

Use --as to give the channel a custom name when adding multiple instances of the same catalog entry.

Creating a channel directly:

  $ valet channels create webhook slack --agent my-agent
  $ valet channels create heartbeat health --agent my-agent --every 5m
  $ valet channels create cron daily --agent my-agent --schedule "every day at 9:00am"
  $ valet channels create telegram bot --agent my-agent

Each channel has a prompt path (defaults to channels/<name>.md).

Attaching an org channel to an agent:

  $ valet channels attach github-webhook --agent my-bot
  $ valet channels attach github-webhook --agent my-bot --events push,pull_request

Use --events to filter which event types are delivered to the agent. Use --as to give the attachment a custom alias.

Detaching:

  $ valet channels detach github-webhook --agent my-bot

Webhook signature verification:

Each webhook channel has a verification scheme that validates incoming requests. Signing secrets are stored as env vars (kind secret, so the agent never sees them) and referenced by the channel via {{NAME}}; channels added from the catalog create them automatically. Manage them with "valet env". Use --verify to select a scheme:

  hmac-sha256    HMAC-SHA256 of the raw body. Default header:
                 X-Webhook-Signature. Auto-detects sha256=<hex>,
                 v1=<hex>, raw hex, and raw base64 formats. Use
                 --signature-header to change the header name.
  stripe         HMAC-SHA256 of "{timestamp}.{body}". Default
                 header: Stripe-Signature. Parses t=<ts>,v1=<hex>
                 from the header value. Works with any provider
                 that uses this format (Stripe, WorkOS, etc). Use
                 --signature-header for providers with a different
                 header name (e.g. WorkOS-Signature).
  svix           HMAC-SHA256 of "{msg_id}.{timestamp}.{body}".
                 Reads svix-id, svix-timestamp, svix-signature
                 headers, falling back to webhook-id,
                 webhook-timestamp, webhook-signature (Loops.so
                 and other standard-webhooks senders). Secret
                 must be base64-encoded, optionally prefixed
                 with whsec_.
  static-token   Constant-time comparison of a bearer token.
                 Default header: X-Webhook-Signature. Use
                 --signature-header to change the header name.
  none           No verification. Use for testing or trusted
                 networks.

valet topics connectors-overview

Connectors (MCP and command)

valet topics connectors-overview [flags]

Connectors: tool and CLI access for agents.

Connectors give agents access to external tools and CLI commands. Two types are supported: MCP server connectors (structured tool access via the Model Context Protocol) and command connectors (CLI tools with automatic secret injection).

MCP Server Connectors:

MCP server connectors expose structured tools to agents. Each defines a transport and can be scoped to an agent or an org.

Transports:
  - stdio: runs a local command (e.g., npx -y @modelcontextprotocol/server-slack)
  - sse: connects to a remote server via Server-Sent Events
  - streamable-http: connects via HTTP streaming

Creating MCP server connectors:

  $ valet connectors create slack --transport stdio \
      --command npx --args=-y,server-slack \
      --env SLACK_BOT_TOKEN={{SLACK_BOT_TOKEN}} \
      --env SLACK_TEAM_ID={{SLACK_TEAM_ID}}
  $ valet connectors create linear --transport streamable-http \
      --url https://mcp.linear.app/mcp

Environment variables and headers can reference env vars using the {{NAME}} template syntax. The connector stores the reference and the control plane resolves it at deploy time. Templates can appear anywhere in a value (e.g. https://{{HOST}}/api). Use "valet env set NAME=VALUE" to create env vars before referencing them. Env vars are secret by default -- hidden from the agent -- which is right for credentials; pass --plain for values the agent should also read directly from its environment. Both kinds resolve in templates.

Command Connectors:

Command connectors wrap CLI tools and make them available on the agent's PATH. They inject secrets automatically — the agent calls the connector name as a regular command and secrets are resolved transparently.

Naming convention:

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 the agent is expected to run. For example, if the CLI command is "gh", name the connector "gh". If the CLI is installed via npx (e.g., npx -y agentmail-cli installs the "agentmail" command), name the connector "agentmail" — not the npm package name.

  $ valet connectors create gh --type command \
      --command gh --secrets GITHUB_TOKEN
  $ valet connectors create agentmail --type command \
      --command npx --args=-y,agentmail-cli \
      --secrets AGENTMAIL_API_KEY

The second example names the connector "agentmail" (the CLI command) even though the npm package is "agentmail-cli". The agent runs "agentmail inboxes list" and the wrapper transparently handles npx, args, and secret injection.

How command connectors work at runtime:

The supervisor generates a wrapper script in ~/bin/ named after the connector. When the agent calls this command, the wrapper injects the configured secrets and runs the underlying command.

The agent runs "gh pr list" and the runtime connector helper injects the connector's secrets. The agent never sees the secret values directly.

Important: the agent runs the connector name, not the underlying command or npx invocation. Only the connector name is on PATH:

  agentmail inboxes list        # correct — connector name
  npx agentmail-cli inboxes list  # wrong — bypasses the wrapper
  agentmail-cli inboxes list      # wrong — not on PATH

SOUL.md workflow steps should reference the connector name as the command the agent should run.

Browsing the catalog:

  $ valet connectors catalog
  $ valet connectors catalog get github

The catalog contains Valet-curated connector definitions for well-known services. Each entry defines transport, command, and required secret slots.

Adding from the catalog:

  $ valet connectors add github --org acme
  $ valet connectors add github --org acme --as github-readonly

Use --as to give the connector a custom name when adding multiple instances of the same catalog entry with different credentials.

Attaching an org connector to an agent:

  $ valet connectors attach github --agent my-bot
  $ valet connectors attach github --agent my-bot --as gh-tools

Use --as to give the attachment a custom alias on the agent.

Detaching:

  $ valet connectors detach github --agent my-bot

Scoping:

Connectors can be scoped to an org (--org) or directly to an agent (--agent). Org-scoped connectors are configured once and shared across agents in the organization. Agent-scoped connectors belong to a single agent.

  $ valet connectors --org acme          # list org connectors
  $ valet connectors --agent my-bot      # list agent connectors

valet topics getting-started

Getting started with Valet

valet topics getting-started [flags]

Getting started with Valet.

1. Log in:

  $ valet auth login

2. Create an agent from a directory containing a SOUL.md:

  $ cd my-agent-project
  $ valet agents create my-agent
  Creating agent... done, my-agent
  Linking directory... done
  Deploying... done, my-agent v1
  Waiting for agent to start... done

3. Deploy new releases after making changes:

  $ valet deploy
  Deploying... done, my-agent v2
  Waiting for agent to start... done

4. Start an interactive console session:

  $ valet console my-agent

5. Add a connector from the catalog:

  $ valet connectors catalog
  $ valet connectors add github --org acme
  $ valet env set GITHUB_TOKEN=ghp_abc123 --org acme

Env vars are secret by default: the agent can use them through connectors but never sees the values. Pass --plain for values the agent should read directly from its environment (a region, a base URL).

6. Attach the connector to your agent:

  $ valet connectors attach github --agent my-agent

7. Add a webhook channel:

  $ valet channels create webhook slack --agent my-agent

8. Check your agents:

  $ valet agents

valet topics resolution

How Valet resolves agents and orgs

valet topics resolution [flags]

How Valet resolves agents and orgs.

Most valet commands target an agent, an org, or both. The CLI resolves your target from three sources, in precedence order:

  1. Flags — --agent and --org on the command line
  2. Project link — .valet/config.json in your project
  3. Default org — set at login or with "valet orgs set-default"

# The Rules

Flags override everything. If you pass any flag, the CLI uses only your flags — project link and default org are ignored. One exception: a command that needs an agent, app, or site, given only --org, uses the linked one when the link names that same org.

In a linked project, the project's agent and org are used together as a pair. "valet agents create", "valet apps create", and "valet sites create" link the directory they run in; "valet agents link", "valet apps link", and "valet sites link" pin an existing directory.

Otherwise, the default org is used. Agent is unspecified, so commands that require an agent will error.

Sources are never mixed. If you pass --agent without --org and you belong to multiple orgs where that agent name exists, the server returns an error listing the orgs — pass --org to disambiguate.

# Command Kinds

  AgentRequired  --agent, or a linked project
                 (org is optional — the server resolves it)
  OrgRequired    --org, or the default org
  DualScoped     --agent or --org (or a linked project)
                 Scope follows whichever is populated.

# Examples

Single-org user, unlinked directory:

  $ valet agents                    # uses your one org
  $ valet deploy --agent foo # --agent wins

Multi-org user, unlinked directory:

  $ valet orgs set-default acme     # pick your default
  $ valet agents                    # lists agents in acme
  $ valet agents --org widgets      # lists agents in widgets

Linked project:

  $ cd ~/src/my-reviewer
  $ valet deploy             # uses the project's link

Override a link:

  $ cd ~/src/my-reviewer
  $ valet deploy --agent other --org acme
                                    # flags win; link ignored

# Errors

"--agent is required (or run from a linked directory)."
    Command needs an agent. Pass --agent or cd into a linked
    project. Commands that take --app say "--app is required".
"--org is required (or set a default with 'valet orgs set-default')."
    Command needs an org. Pass --org or set a default.
"specify --agent, --org, or run from a linked directory."
    A dual-scoped command saw nothing. Pick a scope.
"agent 'foo' exists in multiple orgs (acme, widgets)..."
    Multi-org user passed --agent alone where that name is
    ambiguous. Pass --org to pick one.

# Commands That Help

  valet auth whoami        shows your default org and any
                           linked project
  valet agents link <name> link the current directory to an
                           agent
  valet orgs set-default   change your default org
  valet orgs               list your memberships

valet update

Update the Valet CLI to the latest version

valet update [flags]

Update the Valet CLI using the method that installed it.

Official direct installations download and verify the latest stable release. Homebrew installations continue to update through Homebrew. Unknown or manually-copied binaries are never modified.

$ valet update
Valet 1.2.3 is already up to date.

valet version

Print the CLI version

valet version [flags]

Print the Valet CLI version, platform, and Go runtime version.

$ valet version
valet/1.0.0 darwin-arm64 go1.24.0

Next steps