rapid-honey-43838
02/19/2026, 9:21 AMtall-airline-16756
02/19/2026, 9:21 AMtall-airline-16756
02/19/2026, 9:21 AM<wss://my-project.livekit.cloud>). Note the exact subdomain (in this example: my-project).
1. Check livekit.toml
◦ Open your agent’s livekit.toml and confirm the subdomain field exactly matches the project subdomain:
[project]
subdomain = "your-project-subdomain"
• Subdomain must match character-for-character (case, hyphens, etc.).
1. Confirm LIVEKIT_URL environment variable
◦ Ensure LIVEKIT_URL uses the same subdomain as the project URL (for example: <wss://my-project.livekit.cloud>).
1. Common mismatches to watch for
◦ Extra prefixes/suffixes (e.g., www, trailing slashes)
◦ Different casing
◦ Typo or hyphen vs underscore
◦ Using the full hostname in subdomain instead of only the subdomain (subdomain should be my-project, not my-project.livekit.cloud)
If you’d like, reply with:
• The value of subdomain from your livekit.toml (redact any secrets), and
• The LIVEKIT_URL you’re using (or the project URL from the dashboard).
With those I’ll tell you exactly which value to change and the next steps to redeploy.
Sources: server-sdk-go | livekit/livekit_composite | DeepWikirapid-honey-43838
02/19/2026, 9:23 AMlk cloud auth needs browser ?tall-airline-16756
02/19/2026, 9:23 AMlk cloud auth requires a browser.
You can avoid the interactive browser login in CI by providing credentials as environment variables. The LiveKit CLI will use these instead of running lk cloud auth.
What to set in your CI environment:
• LIVEKIT_API_KEY — your project API key
• LIVEKIT_API_SECRET — your project API secret
• LIVEKIT_URL — your project URL (for example: <wss://my-project.livekit.cloud>)
Example (GitHub Actions):
env:
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
steps:
- name: Deploy LiveKit agent
run: lk agent create
Notes and tips:
• Store API key/secret as CI secrets (never commit them into repo).
• Ensure LIVEKIT_URL uses the correct subdomain (see earlier error you had — subdomain in livekit.toml must match the subdomain in LIVEKIT_URL).
• With these env vars set, you can run any CLI command (e.g., lk agent create, lk deploy) non-interactively.
If you’d like, tell me:
• Which CI provider you’re using (GitHub Actions, GitLab CI, CircleCI, etc.), and
• Which lk command you need to run in CI.
I’ll provide a ready-to-use CI snippet tailored to your provider and deployment step.
Sources: server-sdk-js | livekit/livekit_composite | DeepWiki | Deploy LiveKit Agents with GitHub Actions | LiveKitrapid-honey-43838
02/19/2026, 9:24 AMtall-airline-16756
02/19/2026, 9:24 AM<wss://my-project.livekit.cloud>)
• (optional) DOCKERHUB_USERNAME, DOCKERHUB_TOKEN (or registry credentials) if you build/push images
Important: Confirm the subdomain in your agent’s livekit.toml exactly matches the subdomain of LIVEKIT_URL. For example, if LIVEKIT_URL is <wss://my-project.livekit.cloud>, livekit.toml must contain:
[project]
subdomain = "my-project"
Example GitHub Actions workflow (place in .github/workflows/deploy-livekit-agent.yml):
name: Deploy LiveKit Agent
on:
push:
branches:
- main
env:
# These will be provided from repository secrets
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go (if your agent tooling needs Go)
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Install LiveKit CLI
run: |
curl -sSL <https://github.com/livekit/cli/releases/latest/download/lk-linux-amd64> -o /usr/local/bin/lk
chmod +x /usr/local/bin/lk
lk version
- name: Validate LIVEKIT_URL / subdomain quick check
run: |
echo "LIVEKIT_URL=$LIVEKIT_URL"
# Extract subdomain from LIVEKIT_URL (strip scheme and domain)
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Detected subdomain: $SUBDOMAIN"
# Optional: compare with livekit.toml if present
if [ -f livekit.toml ]; then
TOML_SUBDOMAIN=$(grep -E '^subdomain' livekit.toml | sed -E 's/.*= *"([^"]+)".*/\1/')
echo "livekit.toml subdomain: $TOML_SUBDOMAIN"
if [ "$SUBDOMAIN" != "$TOML_SUBDOMAIN" ]; then
echo "ERROR: subdomain in livekit.toml ($TOML_SUBDOMAIN) does not match LIVEKIT_URL subdomain ($SUBDOMAIN)"
exit 1
fi
fi
# Optional: Build and push Docker image
- name: Log in to DockerHub
if: needs.build_image.outputs.build_image == 'true' || always()
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
if: always()
run: |
# Example: adjust image name/tag as needed
IMAGE_NAME="your-org/livekit-agent:latest"
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME
- name: Deploy LiveKit agent (non-interactive)
env:
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
run: |
# Example: create or update an agent using the CLI
# Replace flags/values with what your deployment requires
lk agent create --name my-agent --image your-org/livekit-agent:latest --project-subdomain $(echo $LIVEKIT_URL | sed -E 's#^wss?://([^./]+).*#\1#') || true
# If you already created and want to deploy/update:
lk agent deploy my-agent --image your-org/livekit-agent:latest
Notes and recommendations
• Use secrets for all credentials and never store API key/secret in code.
• The small validation step prevents the “project does not match agent subdomain” error by confirming livekit.toml (if present) and LIVEKIT_URL subdomain match.
• lk honors LIVEKIT_API_KEY, LIVEKIT_API_SECRET, and LIVEKIT_URL environment variables, so lk cloud auth is unnecessary in CI.
• Adjust Docker build/push steps to match your registry and image naming conventions.
• Replace `lk agent create`/`lk agent deploy` flags with options your agent requires.
If you want, tell me:
• Whether you build a Docker image in CI or use a public image,
• The exact lk command you run locally (create/deploy/update), and
• Whether you keep livekit.toml in the repo,
and I’ll tailor the workflow to your specific commands and image registry.rapid-honey-43838
02/19/2026, 9:27 AMtall-airline-16756
02/19/2026, 9:27 AMlk) itself is a single binary and does not require Go to run in CI. Remove the Go setup step if your workflow doesn't build Go code. Keep it only if your agent build process or other steps actually need Go in the runner.
2) Do you need to build/push a Docker image in CI, or does lk agent build it from the repo/Dockerfile?
• The CLI does not automatically build your image from your repo in your CI runner. If you want LiveKit to run a specific container image, you must provide an image the platform can pull (for example, an image pushed to Docker Hub or another registry).
• Building and pushing the image in CI ensures the image is available to LiveKit when you run lk agent create or lk agent deploy.
• If you already host your image publicly (or use a registry image tag you control), you can skip the build/push steps and point lk at that image.
• If your workflow expects LiveKit to build from your repo, that is not the behavior shown in the example; instead, produce and publish the image from CI, then deploy it.
If you like, tell me:
• Do you want the runner to build and push the image in CI, or do you already have a registry image to reference?
• Which exact lk command you run locally (create/deploy/update) and whether livekit.toml is in the repo.
I’ll give a trimmed GitHub Actions workflow that removes the unnecessary Go step and either omits Docker steps (if you already have an image) or includes a focused build/push sequence.rapid-honey-43838
02/19/2026, 9:31 AMtall-airline-16756
02/19/2026, 9:31 AMlk CLI and CI secrets,
• Validates the LiveKit subdomain to avoid the “project does not match agent subdomain” error.
Before using this workflow, add these repository secrets in GitHub:
• LIVEKIT_API_KEY
• LIVEKIT_API_SECRET
• LIVEKIT_URL (example: wss://my-project.livekit.cloud)
• DOCKERHUB_USERNAME
• DOCKERHUB_TOKEN
Place this file at .github/workflows/deploy-livekit-agent.yml:
name: Build & Deploy LiveKit Agent
on:
push:
branches:
- main
env:
# populated from repository secrets
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install LiveKit CLI
run: |
curl -sSL <https://github.com/livekit/cli/releases/latest/download/lk-linux-amd64> -o /usr/local/bin/lk
chmod +x /usr/local/bin/lk
lk version
- name: Validate LIVEKIT_URL subdomain and livekit.toml (if present)
run: |
if [ -z "$LIVEKIT_URL" ]; then
echo "LIVEKIT_URL is not set"; exit 1
fi
echo "LIVEKIT_URL=$LIVEKIT_URL"
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Detected subdomain: $SUBDOMAIN"
if [ -f livekit.toml ]; then
TOML_SUBDOMAIN=$(grep -E '^subdomain' livekit.toml | sed -E 's/.*= *"([^"]+)".*/\1/' || true)
if [ -n "$TOML_SUBDOMAIN" ]; then
echo "livekit.toml subdomain: $TOML_SUBDOMAIN"
if [ "$SUBDOMAIN" != "$TOML_SUBDOMAIN" ]; then
echo "ERROR: subdomain in livekit.toml ($TOML_SUBDOMAIN) does not match LIVEKIT_URL subdomain ($SUBDOMAIN)"
exit 1
fi
else
echo "livekit.toml present but no subdomain key found; continuing"
fi
fi
- name: Set image name and tag
id: vars
run: |
IMAGE_NAME="${{ github.repository_owner }}/livekit-agent"
IMAGE_TAG="${GITHUB_SHA::7}"
echo "IMAGE_NAME=$IMAGE_NAME" >> $GITHUB_OUTPUT
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Docker image
run: |
IMAGE="${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.IMAGE_TAG }}"
echo "Building $IMAGE"
docker build -t "$IMAGE" .
echo "::set-output name=image::$IMAGE"
id: build
- name: Push Docker image
run: |
IMAGE="${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.IMAGE_TAG }}"
echo "Pushing $IMAGE"
docker push "$IMAGE"
- name: Deploy LiveKit agent (create or update)
env:
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
run: |
IMAGE="${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.IMAGE_TAG }}"
AGENT_NAME="my-agent" # change as needed
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
# Try to create the agent; if it already exists, update/deploy the image
set -o pipefail
if lk agent list | grep -q "^$AGENT_NAME$"; then
echo "Agent $AGENT_NAME exists — deploying image"
lk agent deploy "$AGENT_NAME" --image "$IMAGE"
else
echo "Creating agent $AGENT_NAME"
lk agent create --name "$AGENT_NAME" --image "$IMAGE" --project-subdomain "$SUBDOMAIN"
fi
Quick notes and how to customize:
• Change AGENT_NAME to your desired agent name.
• IMAGE naming: This workflow pushes to Docker Hub under ${{ github.repository_owner }}/livekit-agent:sha. Change IMAGE_NAME if you prefer a different registry or path.
• If using a different registry (ECR, GCR, GitHub Container Registry), replace the Docker login step with the appropriate login action and adjust image naming.
• The workflow ensures LIVEKIT_API_KEY, LIVEKIT_API_SECRET, and LIVEKIT_URL are used by the lk CLI so no browser lk cloud auth is required.
• The subdomain check compares LIVEKIT_URL with livekit.toml (if present) to prevent the “project does not match agent subdomain” error.
If you want, I can:
• Convert this to use GitHub Container Registry or AWS ECR instead of Docker Hub,
• Adjust the image tag strategy (semantic tags, branch-based tagging),
• Or tailor the lk agent create flags to match any custom agent configuration you need.
Which would you like next?rapid-honey-43838
02/19/2026, 9:34 AMname: Deploy Staging
# Agent runtime secrets (OPENAI_API_KEY, DEEPGRAM_API_KEY, etc.) are managed
# separately via the Update Staging Secrets workflow.
# They persist across deployments and only need updating when keys change.
on:
workflow_dispatch:
inputs:
agent:
description: "Agent to deploy"
required: true
type: choice
options:
- inbound
- persistence_demo
jobs:
deploy:
name: Deploy ${{ inputs.agent }} to staging
runs-on: ubuntu-latest
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
steps:
- uses: actions/checkout@v4
- name: Install lk CLI
run: |
curl -sSL <https://get.livekit.io/cli> | bash
echo "$HOME/.livekit/bin" >> "$GITHUB_PATH"
- name: Deploy ${{ inputs.agent }} agent
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
echo "Deploying ${{ inputs.agent }} agent to staging"
lk agent deploy \
--config src/agents/${{ inputs.agent }}/livekit.toml \
--secrets AGENT_TYPE=${{ inputs.agent }} \
--silent
- name: Verify deployment
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
lk agent status \
--config src/agents/${{ inputs.agent }}/livekit.tomltall-airline-16756
02/19/2026, 9:34 AMlk agent deploy / lk agent status steps.
First, I need the failing error text. Could you paste the exact error output from the failing job (the logs for the step that failed)? That will let me pinpoint the cause.
Meanwhile, here are the most common reasons this workflow fails and quick checks you can run right now:
• Missing/incorrect subdomain in livekit.toml
◦ Symptom: Error like “project does not match agent subdomain”.
◦ Check: Open src/agents/<agent>/livekit.toml and confirm:
[project]
subdomain = "your-subdomain" # must match the subdomain in LIVEKIT_URL
• Confirm LIVEKIT_URL secret (example: <wss://my-project.livekit.cloud>) and ensure the subdomain (my-project) exactly matches the subdomain value.
• Authentication problems (API key/secret or LIVEKIT_URL)
◦ Symptom: Authorization or connection errors from lk (403/401, connection refused).
◦ Check: Ensure the three secrets are set correctly in repository/organization secrets and are available to the workflow. You already set them in both job env and step env — that’s fine; just confirm values are correct and not expired/rotated.
• lk CLI install failure or PATH not set
◦ Symptom: “command not found: lk” or version/install errors.
◦ Check: The workflow uses the install script and then appends $HOME/.livekit/bin to PATH. Confirm install succeeded earlier in the logs and that lk version shows a version. If install script changed, switch to downloading the binary directly:
▪︎ Example: curl the binary to /usr/local/bin and chmod +x, then run lk version.
• Agent image not provided / CLI expecting an image
◦ Symptom: lk agent deploy errors complaining about missing image or invalid image reference.
◦ Check: If your agent expects an image, lk agent deploy must reference an image previously pushed to a registry (or your livekit.toml must specify how to build). If you aren’t building images in this workflow, add build/push steps (I can provide a snippet). If your agents are configured to use a remote image, ensure the image URL is reachable and credentials are provided if private.
• --config path or file not found
◦ Symptom: Errors indicating livekit.toml or config path missing.
◦ Check: Confirm repo checkout path contains src/agents/<agent>/livekit.toml in that branch/run. If the file is generated earlier or in another job, ensure job dependencies and artifact passing are correct.
• Silent/quiet mode hiding helpful errors
◦ Symptom: Fails with no visible output.
◦ Check: Temporarily remove --silent from lk agent deploy to see full logs from the command.
What I need from you to help further (pick any that apply):
• The exact failing step logs (copy/paste the error output from GitHub Actions).
• The contents (or at least the subdomain field) of src/agents/<agent>/livekit.toml for the agent you tried to deploy (redact secrets).
• Whether your agent uses a Docker image built in CI or references a public/private registry image.
• Confirmation that lk install step completed successfully (you can paste the lk version log line).
If you paste the failing log and the subdomain value, I’ll tell you the precise fix and an updated workflow snippet (if needed).rapid-honey-43838
02/19/2026, 9:47 AMDeploying persistence_demo agent to staging
2026-02-19T09:47:05.130Z DEBUG lk config/livekit.go:89 loading src/agents/persistence_demo/livekit.toml file
Using url, api-key, api-secret from environment
agent ID or [src/agents/persistence_demo/livekit.toml] required
URL: ***, api-key: ***, api-secret: ************
2026-02-19T09:47:05.155Z DEBUG lk config/livekit.go:89 loading src/agents/persistence_demo/livekit.toml file
Using url, api-key, api-secret from environment
URL: ***, api-key: ***, api-secret: ************
huh: could not open a new TTY: open /dev/tty: no such device or addresstall-airline-16756
02/19/2026, 9:47 AMlk agent deploy command in your job is trying to open a TTY (interactive prompt) because it expects either an agent ID or some interactive input when it can’t determine the target to deploy from the config alone.
• In CI there’s no /dev/tty, so the CLI errors: “could not open a new TTY: open /dev/tty: no such device or address.”
• The logs also show “agent ID or [src/agents/persistence_demo/livekit.toml] required” — the CLI wasn’t given an explicit agent name/ID and the config didn’t supply everything the CLI needed non-interactively.
How to fix it (two recommended approaches) Pick one of these depending on how you want to manage deployments.
Option A — Deploy by specifying the agent name and image (non-interactive, recommended)
• Provide an explicit agent name (or ID) to lk agent deploy and ensure the agent has an image configured (either in livekit.toml or passed by flag). This avoids any interactive prompt.
Example step change (replace IMAGE with your registry/image):
- name: Deploy ${{ inputs.agent }} agent
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
IMAGE="your-org/${{ inputs.agent }}:latest" # or image built and pushed earlier
AGENT_NAME="${{ inputs.agent }}-staging" # pick the agent name you created
echo "Deploying $AGENT_NAME with image $IMAGE"
lk agent deploy "$AGENT_NAME" --image "$IMAGE" --config src/agents/${{ inputs.agent }}/livekit.toml --silent
Why this works
• --image + explicit agent name gives the CLI everything it needs; it won’t prompt for interactive choices.
Option B — Create-or-update flow (if agent may not exist yet)
• Try creating the agent non-interactively first (with lk agent create --name ... --image ... --project-subdomain ...) and if it already exists, call lk agent deploy. That is what I suggested earlier and prevents interactive selection on first run.
Example:
run: |
IMAGE="your-org/${{ inputs.agent }}:${GITHUB_SHA::7}"
AGENT_NAME="${{ inputs.agent }}-staging"
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
if lk agent list | grep -q "^$AGENT_NAME$"; then
lk agent deploy "$AGENT_NAME" --image "$IMAGE" --config src/agents/${{ inputs.agent }}/livekit.toml --silent
else
lk agent create --name "$AGENT_NAME" --image "$IMAGE" --project-subdomain "$SUBDOMAIN" --config src/agents/${{ inputs.agent }}/livekit.toml --silent
fi
Other immediate checks and tips
• Ensure your livekit.toml contains a valid project.subdomain that matches LIVEKIT_URL (we saw this earlier).
• If you’re not pushing images in this workflow, add build+push steps (or point --image to a public image).
• Remove --silent temporarily while debugging so you see full CLI output in logs.
• Do not try to force a TTY in CI (e.g., --tty) — this won’t work because GitHub Actions has no /dev/tty.
If you want, I can:
• Produce a full patched workflow that builds the image, pushes it, then runs the create-or-update flow for your repo,
• Or edit your existing workflow to add the image build/push and the explicit agent name so it runs non-interactively.
Which would you prefer? If you want the updated workflow, tell me the image name format you prefer (Docker Hub, GHCR, etc.) and the AGENT_NAME you want to use.rapid-honey-43838
02/19/2026, 9:58 AMtall-airline-16756
02/19/2026, 9:58 AMlk CLI is trying to open an interactive prompt (TTY) — typically because it needs confirmation, authentication, or missing required fields (agent id/image/project subdomain) and falls back to an interactive flow.
• CI runners (GitHub Actions) do not provide /dev/tty, so any interactive attempt fails with that error.
• To run in CI you must provide all required inputs up front (agent id/name, image or build steps, project subdomain) and avoid interactive flags.
Quick checklist to make deploy non-interactive
• Ensure LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET are set as secrets and exported in the step (you already do this).
• Ensure src/agents/persistence_demo/livekit.toml exists and contains the correct project subdomain:
[project]
subdomain = "your-staging-subdomain"
• Provide an explicit agent name/ID and an image (or pre-build the image in CI). Do not rely on the CLI to prompt you for these.
• Avoid interactive mode. Use explicit flags (or the deploy-action) so the CLI never tries to open a TTY.
Two simple, reliable fixes (pick one)
Option 1 — Pre-build image, then deploy with explicit agent name (recommended)
• Build & push the Docker image in the workflow.
• Call lk agent create (first-run) or lk agent deploy with explicit agent name and --image. This prevents any interactive prompt.
Example step to use inside your job (replace image name and AGENT_NAME):
- name: Build and push image
run: |
IMAGE="your-registry/persistence_demo:${GITHUB_SHA::7}"
docker build -t "$IMAGE" src/agents/persistence_demo
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push "$IMAGE"
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
- name: Create or deploy agent (non-interactive)
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
IMAGE="your-registry/persistence_demo:${GITHUB_SHA::7}"
AGENT_NAME="persistence_demo-staging"
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
if lk agent list | grep -q "^$AGENT_NAME$"; then
lk agent deploy "$AGENT_NAME" --image "$IMAGE" --config src/agents/persistence_demo/livekit.toml
else
lk agent create --name "$AGENT_NAME" --image "$IMAGE" --project-subdomain "$SUBDOMAIN" --config src/agents/persistence_demo/livekit.toml
fi
Option 2 — Use LiveKit GitHub Action (no TTY, higher-level convenience)
• Use the official deploy-action which is CI-friendly and avoids TTY prompts when configured with env secrets and working directory.
Example step:
- name: Deploy LiveKit Cloud Agent
uses: livekit/deploy-action@v2
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
with:
OPERATION: deploy
WORKING_DIRECTORY: src/agents/persistence_demo
IMAGE: your-registry/persistence_demo:latest # optional if you want to use pre-built image
Additional debugging tips
• Remove --silent temporarily so logs show full CLI output while you iterate.
• If you still see the TTY error, check the command that runs immediately before it — it’s trying to prompt somewhere (missing --image, missing --name, or falling back to login flow).
• Confirm livekit.toml subdomain matches the subdomain parsed from LIVEKIT_URL exactly (no case, hyphen, or suffix mismatches).
If you’d like, I can:
• Provide a full GitHub Actions workflow file (build → push → deploy) tailored to Docker Hub, GHCR, or ECR.
• Edit your existing workflow in-place to add image build/push and the create-or-deploy steps so the TTY prompt disappears.
Tell me:
• Which container registry you prefer (Docker Hub, GHCR, ECR), and
• The agent name you want to use (or I can keep using persistence_demo-staging).
I’ll return a complete, ready-to-use workflow you can drop into .github/workflows/.
Sources: Voice AI quickstart | LiveKit Documentation | Examples | livekit/livekit_composite | DeepWiki | Deploy LiveKit Agents with GitHub Actions | LiveKit | server-sdk-go | livekit/livekit_composite | DeepWiki | Server-side | livekit/livekit_composite | DeepWikirapid-honey-43838
02/19/2026, 10:00 AMtall-airline-16756
02/19/2026, 10:00 AMname: Deploy Staging
on:
workflow_dispatch:
inputs:
agent:
description: "Agent to deploy"
required: true
type: choice
options:
- inbound
- persistence_demo
jobs:
deploy:
name: Deploy ${{ inputs.agent }} to staging
runs-on: ubuntu-latest
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
# Docker Hub credentials (set these as repo secrets)
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
steps:
- uses: actions/checkout@v4
- name: Install lk CLI
run: |
curl -sSL <https://get.livekit.io/cli> | bash
echo "$HOME/.livekit/bin" >> "$GITHUB_PATH"
- name: Set image name & tag
id: image-vars
run: |
AGENT="${{ inputs.agent }}"
IMAGE_NAME="${{ github.repository_owner }}/livekit-${AGENT}"
IMAGE_TAG="${GITHUB_SHA::7}"
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
echo "AGENT=${AGENT}" >> $GITHUB_OUTPUT
echo "IMAGE=${IMAGE}" >> $GITHUB_OUTPUT
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_OUTPUT
echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_OUTPUT
- name: Log in to Docker registry
if: always()
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
run: |
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
AGENT="${{ steps.image-vars.outputs.AGENT }}"
CONTEXT="./src/agents/${AGENT}"
echo "Building $IMAGE from $CONTEXT"
docker build -t "$IMAGE" "$CONTEXT"
- name: Push Docker image
run: |
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
echo "Pushing $IMAGE"
docker push "$IMAGE"
- name: Validate LIVEKIT_URL subdomain and livekit.toml (optional)
run: |
if [ -z "$LIVEKIT_URL" ]; then
echo "LIVEKIT_URL is not set"; exit 1
fi
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Detected LIVEKIT_URL subdomain: $SUBDOMAIN"
CONF="./src/agents/${{ inputs.agent }}/livekit.toml"
if [ -f "$CONF" ]; then
TOML_SUBDOMAIN=$(grep -E '^subdomain' "$CONF" | sed -E 's/.*= *"([^"]+)".*/\1/' || true)
if [ -n "$TOML_SUBDOMAIN" ]; then
echo "livekit.toml subdomain: $TOML_SUBDOMAIN"
if [ "$SUBDOMAIN" != "$TOML_SUBDOMAIN" ]; then
echo "ERROR: livekit.toml subdomain ($TOML_SUBDOMAIN) does not match LIVEKIT_URL subdomain ($SUBDOMAIN)"
exit 1
fi
else
echo "livekit.toml present but no subdomain key found; continuing"
fi
else
echo "No livekit.toml at $CONF; ensure it exists or pass flags to lk"
fi
- name: Create or deploy agent (non-interactive)
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
set -euo pipefail
AGENT="${{ steps.image-vars.outputs.AGENT }}"
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
AGENT_NAME="${AGENT}-staging" # change if you prefer a different agent name
CONF_PATH="src/agents/${AGENT}/livekit.toml"
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Agent: $AGENT"
echo "Agent name (used in LiveKit): $AGENT_NAME"
echo "Image: $IMAGE"
echo "Config: $CONF_PATH"
echo "Project subdomain: $SUBDOMAIN"
# Ensure lk uses env creds (no lk cloud auth)
# If the agent already exists, deploy updated image. Otherwise create it non-interactively.
if lk agent list --no-headers | awk '{print $1}' | grep -xq "$AGENT_NAME"; then
echo "Agent exists — deploying new image"
lk agent deploy "$AGENT_NAME" --image "$IMAGE" --config "$CONF_PATH"
else
echo "Agent not found — creating non-interactively"
lk agent create --name "$AGENT_NAME" --image "$IMAGE" --project-subdomain "$SUBDOMAIN" --config "$CONF_PATH"
fi
- name: Verify deployment
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
AGENT="${{ steps.image-vars.outputs.AGENT }}"
AGENT_NAME="${AGENT}-staging"
echo "Checking status for $AGENT_NAME"
lk agent status --config "src/agents/${AGENT}/livekit.toml" || lk agent status "$AGENT_NAME"
What I changed and why
• Added Docker build & push steps so the agent image is available to LiveKit — the CLI will not implicitly build an image in CI without configuration.
• Provide an explicit AGENT_NAME and IMAGE to lk agent create / lk agent deploy so the CLI never falls back to an interactive prompt.
• Kept your original env secrets and config path usage.
• Subdomain validation step to prevent the “project does not match agent subdomain” problem you saw earlier.
• No TTY usage and no browser login required — the CLI uses the API key/secret from environment variables.
Small notes / next steps
• If you use a registry other than Docker Hub (GHCR, ECR), replace Docker login/push steps accordingly.
• If you prefer a different agent naming convention, change AGENT_NAME.
• If your livekit.toml lacks required fields (like project.subdomain), the workflow either supplies --project-subdomain flag during create or you should add it to the file.
If you want, I can:
• Convert the Docker steps to GHCR or ECR for your org,
• Change the image tagging scheme (branch/tag instead of short SHA),
• Or remove the build/push if you later host images externally.
Tell me which registry you use (Docker Hub, GHCR, ECR) and whether you’d like a different image tag format; I’ll update the workflow accordingly.rapid-honey-43838
02/19/2026, 10:08 AMtall-airline-16756
02/19/2026, 10:09 AMname: Deploy Staging
on:
workflow_dispatch:
inputs:
agent:
description: "Agent to deploy"
required: true
type: choice
options:
- inbound
- persistence_demo
jobs:
deploy:
name: Deploy ${{ inputs.agent }} to staging
runs-on: ubuntu-latest
env:
# LiveKit secrets (set these in repo or org secrets)
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
# Docker Hub credentials (set these as repo secrets)
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install lk CLI
run: |
curl -sSL <https://get.livekit.io/cli> | bash
echo "$HOME/.livekit/bin" >> "$GITHUB_PATH"
lk version
- name: Set image name & tag
id: image-vars
run: |
AGENT="${{ inputs.agent }}"
IMAGE_NAME="${{ github.repository_owner }}/livekit-${AGENT}"
IMAGE_TAG="${GITHUB_SHA::7}"
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
echo "AGENT=${AGENT}" >> $GITHUB_OUTPUT
echo "IMAGE=${IMAGE}" >> $GITHUB_OUTPUT
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_OUTPUT
echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_OUTPUT
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
run: |
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
AGENT="${{ steps.image-vars.outputs.AGENT }}"
CONTEXT="./src/agents/${AGENT}"
if [ ! -f "$CONTEXT/Dockerfile" ]; then
echo "No Dockerfile found at $CONTEXT/Dockerfile"; exit 1
fi
echo "Building $IMAGE from $CONTEXT"
docker build -t "$IMAGE" "$CONTEXT"
- name: Push Docker image
run: |
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
echo "Pushing $IMAGE"
docker push "$IMAGE"
- name: Validate LIVEKIT_URL subdomain and livekit.toml
run: |
if [ -z "$LIVEKIT_URL" ]; then
echo "LIVEKIT_URL is not set"; exit 1
fi
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Detected LIVEKIT_URL subdomain: $SUBDOMAIN"
CONF="./src/agents/${{ inputs.agent }}/livekit.toml"
if [ -f "$CONF" ]; then
TOML_SUBDOMAIN=$(grep -E '^subdomain' "$CONF" | sed -E 's/.*= *"([^"]+)".*/\1/' || true)
if [ -n "$TOML_SUBDOMAIN" ]; then
echo "livekit.toml subdomain: $TOML_SUBDOMAIN"
if [ "$SUBDOMAIN" != "$TOML_SUBDOMAIN" ]; then
echo "ERROR: livekit.toml subdomain ($TOML_SUBDOMAIN) does not match LIVEKIT_URL subdomain ($SUBDOMAIN)"
exit 1
fi
else
echo "livekit.toml present but no subdomain key found; continuing"
fi
else
echo "No livekit.toml at $CONF; ensure this file exists or pass flags to lk"
fi
- name: Create or deploy agent (non-interactive)
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
set -euo pipefail
AGENT="${{ steps.image-vars.outputs.AGENT }}"
IMAGE="${{ steps.image-vars.outputs.IMAGE }}"
AGENT_NAME="${AGENT}-staging" # change if you prefer another name
CONF_PATH="src/agents/${AGENT}/livekit.toml"
SUBDOMAIN=$(echo "$LIVEKIT_URL" | sed -E 's#^wss?://([^./]+).*#\1#')
echo "Agent: $AGENT"
echo "Agent name (LiveKit): $AGENT_NAME"
echo "Image: $IMAGE"
echo "Config: $CONF_PATH"
echo "Project subdomain: $SUBDOMAIN"
# Confirm agent list accessible
lk agent list --no-headers || true
# Create or deploy without TTY. Provide --image and required flags so lk won't prompt.
if lk agent list --no-headers | awk '{print $1}' | grep -xq "$AGENT_NAME"; then
echo "Agent exists — deploying new image"
lk agent deploy "$AGENT_NAME" --image "$IMAGE" --config "$CONF_PATH"
else
echo "Agent not found — creating non-interactively"
lk agent create --name "$AGENT_NAME" --image "$IMAGE" --project-subdomain "$SUBDOMAIN" --config "$CONF_PATH"
fi
- name: Verify deployment
env:
LIVEKIT_URL: ${{ secrets.STAGING_LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.STAGING_LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.STAGING_LIVEKIT_API_SECRET }}
run: |
AGENT="${{ steps.image-vars.outputs.AGENT }}"
AGENT_NAME="${AGENT}-staging"
echo "Checking status for $AGENT_NAME"
lk agent status --config "src/agents/${AGENT}/livekit.toml" || lk agent status "$AGENT_NAME"
Notes and recommendations
• Docker Hub: ensure DOCKER_USERNAME and DOCKER_PASSWORD are set as repository secrets.
• livekit.toml: if present, ensure the [project].subdomain value exactly matches the subdomain parsed from LIVEKIT_URL (no extra suffixes, different casing, or typos).
• Agent name: workflow uses AGENT_NAME="${agent}-staging". Change if you want a different naming convention.
• Debugging: temporarily remove or omit silent flags (none used here) to see full lk output if you need more logs.
• If your agent requires additional runtime secrets (OPENAI_API_KEY, etc.), manage those separately as repository or environment secrets and inject them into the agent via `lk agent create`/`--secrets` or LiveKit dashboard.
If you want, I can:
• Swap Docker Hub steps to GitHub Container Registry or AWS ECR,
• Change the image tag strategy to include branch names or semantic tags,
• Add CI steps to inject runtime secrets into LiveKit agent creation if you want the agent to receive them automatically.
Which should I do next (if anything)?