# TeleQuick agent setup

> A paste-ready prompt that points your coding agent at a real, verified TeleQuick voice agent — connected, called, and transcribed.

> **NOTE:**
> **Using this page.** Everything below is written for a coding agent. Paste this
> into Claude Code, Cursor or Codex CLI and it will fetch the rest itself:
> 
> ```text
> Get my voice agent onto TeleQuick and prove it takes a real call.
> First read https://docs.telequick.dev/agent-setup/prompt.md and follow it.
> Never put my app secret in chat or commit it. Don't buy numbers, change
> billing, or add policy without asking me first.
> ```
> 
> The raw Markdown for this page is at
> [`/agent-setup/prompt.md`](https://docs.telequick.dev/agent-setup/prompt.md).

You're helping a developer connect their voice agent to TeleQuick and
confirm it actually answers a call. Your job isn't to explain TeleQuick;
it's to produce a working, verified agent.

This needs terminal access on the machine running the agent. If you're running
remotely and can't reach the developer's machine, don't guess — hand them the
commands to run themselves.

Before you start anything, understand the model, because it decides which of
the two paths below you take:

> **TeleQuick does not run your agent. It carries the media.** The platform
> owns the phone number, the carrier trunk and the call; your process owns the
> speech-to-text, the model and the voice. Your agent opens **one outbound QUIC
> connection** to the platform and waits. When a call arrives, audio flows both
> ways over that connection.

Because the connection is outbound, the developer's machine needs no public
URL, no inbound port and no tunnel. If you were about to reach for one, don't.

Confirm with the developer which path applies before you write any code:

- **They already have a LiveKit Agents worker** — keep it. Swap only the media
  transport. Path B.
- **They have no agent yet, or a custom one** — use the framework-free agents
  SDK, which is a register-and-wait worker where they bring their own
  STT/LLM/TTS. Path A.

## Setup

### 1. Get credentials — the developer does this, not you

An external agent needs an **app key** and **secret**, minted per agent in the
console:

**Agents → New → External**, or the **External agents** screen at
`https://portal.telequick.dev/admin/external-agents`.

The reveal panel shows four things: the connect URL, the agent handle, the app
key (`ck_…`) and the secret. **The secret is shown once.** Ask the developer to
copy it into their shell or `.env` themselves — never ask them to paste it into
the chat, and never write it into a tracked file.

The **agent handle** matters: it is the name the platform routes calls to. Keep
it stable and use the same value everywhere below.

### 2. Install and wire the agent

**Path A — framework-free agents SDK**

These packages are not on the public npm or PyPI registries. Point the scope at
the artifact registry first, or the install will 404:

```bash
npm config set @telequick:registry https://artifacts.clutchcall.dev/npm/
npm i @telequick/agents @fails-components/webtransport
```

```bash
pip install 'telequick-agents[quic]' --extra-index-url https://artifacts.clutchcall.dev/pip/simple/
```

Go and Rust are published too — Go resolves from git tags at
`github.com/telequick/agents`, Rust from the sparse registry at
`sparse+https://artifacts.clutchcall.dev/cargo/`. The exact per-language
commands live in the recipe; use them rather than improvising a version.

The worker shape is `serve(handler)`: it registers, waits, and reconnects with
backoff. Handle `onReady` and `onDisconnected`. Full walkthrough:
[TypeScript agent recipe](/modalities/voice/recipes/typescript-agent).

**Path B — existing LiveKit Agents worker**

```bash
pip install "livekit-plugins-telequick[quic]"
```

```bash
npm i @telequick/livekit-transport @fails-components/webtransport
```

Change one thing: replace `cli.run_app(...)` / the worker bootstrap with
`run_agent_worker(...)` / `runAgentWorker(...)`, passing `engine_url`,
`app_key`, `app_secret`, `agent_name` and `sample_rate=8000`. Your prompts,
tools, STT, LLM and TTS are untouched. Full walkthrough:
[LiveKit transport recipe](/modalities/voice/recipes/livekit-transport).

Telephony is narrowband. If the developer's agent hardcodes 16 kHz or 24 kHz
anywhere, fix it to 8 kHz now rather than debugging robotic audio later.

### 3. Run it — in the background

Environment, with the secret coming from the developer's own shell. Take the
host from the connect URL the console showed in step 1 — it is authoritative
for their tenant; `engine.telequick.dev` is only the default:

```bash
export TELEQUICK_HOST=engine.telequick.dev
export TELEQUICK_MEDIA_KEY=ck_...
export TELEQUICK_MEDIA_SECRET=...        # never echo this
export TELEQUICK_AGENT=salesbot         # the agent handle from step 1
```

Start the worker as a background process and keep it running. Don't background
it silently — tell the developer how to stop it when you're done.

Confirm it registered before going near a phone. A healthy worker logs a
successful connect and then sits idle; it does not exit. If it exits
immediately, the credentials or the handle are wrong — re-check those before
changing anything about the transport.

The agent's presence is also visible in the console on the External agents
screen. That is the authoritative check: if the console doesn't show it
connected, the platform can't route a call to it, no matter what the local logs
say.

### 4. Prove it takes a call

Two ways, in order of preference:

- **[Test Drive](/modalities/voice/test-drive)** — talk to the agent from the
  browser with your microphone, no phone number and no carrier involved. It's on
  the agent's row in the console. Use this first: it isolates the agent from
  telephony entirely, so a failure here is unambiguously the agent. Note it runs
  at 8 kHz like a real call, so a pipeline pinned to 16 or 24 kHz sounds wrong
  here too — that is the point.
- **A real phone call** — assign a number to the agent under **Numbers**, then
  dial it.

Then verify the loop actually closed, not just that audio happened:

- The call appears in call records with the expected duration.
- The transcript is populated. If the developer's agent does its own
  speech-to-text, it must call `sendTranscript(role, text)` per turn — otherwise
  the call is real but the platform-side transcript, the analytics timeline and
  the `voice.transcript.ready` webhook all stay empty. This is the single most
  common "it works but nothing shows up" report.

If audio is one-way, check the sample rate before anything else.

## Offer to harden it — only with the developer's OK

A connected agent is a production path to a phone number. Offer these; apply
nothing without agreement:

- Rotate the app secret on a schedule; revoke keys for agents you retire.
- Scope any MCP or admin key to `read` unless a write is genuinely needed.
- Put the agent behind a dispatch rule so only intended numbers reach it.

## Give yourself the docs

Two machine-readable surfaces exist. Wire one up if the developer wants you to
keep working on this codebase:

- **Docs MCP server** (read-only, no auth) at
  `https://docs.telequick.dev/api/mcp` — tools `search_docs`, `get_page`,
  `list_pages`.
- **Control-plane MCP server** at `https://portal.telequick.dev/mcp` — reads and
  writes the developer's own tenant with an `mpk_…` key minted under
  **Admin → API keys → MCP access keys**. Scoped `mcp:<domain>:<action>`.

```json
{
  "mcpServers": {
    "telequick-docs": { "url": "https://docs.telequick.dev/api/mcp" }
  }
}
```

Every docs page is also plain Markdown at `<url>.md`, with an index at
[`/llms.txt`](https://docs.telequick.dev/llms.txt).

## Notes for agents

- Never print, echo or commit the app secret or an `mpk_` key. Never ask for
  one in chat.
- Don't buy a phone number, change billing, or add a dispatch rule without
  explicit agreement — these cost money or divert live traffic.
- Keep the worker process running while the agent is in use, and tell the
  developer how to stop it.
- Prefer Test Drive over a real call while iterating. It costs nothing and
  removes the carrier from the picture.
