Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/pipecat/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"""Pipecat CLI - command-line tools for building Pipecat AI voice agents.

This package provides command-line tools for:
- Scaffolding new Pipecat projects with `pipecat create`
- Making a project agent-ready (AGENTS.md + CLAUDE.md) with `pipecat init`
- Initializing a new Pipecat project with `pipecat init` (the entry point: writes the
coding-agent guide, then helps you build with a coding agent or scaffold a bot)
- Scaffolding a project with `pipecat create`
- Running behavioral evals against a bot with `pipecat eval`

And allows installing extensions like Pipecat Cloud:
- Deploying to Pipecat Cloud with `pipecat cloud`
Expand Down
6 changes: 2 additions & 4 deletions src/pipecat/cli/agent_templates/GETTING_STARTED.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Getting Started — Building Pipecat Bots with a Coding Agent

**This file is for you**: how to drive your coding agent well. The other
files here are for the **agent**: AGENTS.md teaches it how to build Pipecat
apps — scaffold with `pipecat create`, check APIs against live sources
instead of stale training data, verify its own work with headless evals —
and CLAUDE.md loads it into Claude Code.
files here (`AGENTS.md`, `CLAUDE.md`) are the agent's guide; it picks them
up automatically, so you don't need to read them.

## First: set up the Pipecat Context Hub

Expand Down
4 changes: 2 additions & 2 deletions src/pipecat/cli/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def create_command(
# command and routing the `quickstart` token preserves `pc create quickstart [-o ...]`.
#
# NOTE: this is the `pipecat create` scaffolder (formerly `pipecat init`). `pipecat init`
# is now a separate command that makes a project agent-ready (see commands/init.py).
# is now a separate command that initializes a new Pipecat project (see commands/init.py).
if target == "quickstart":
return quickstart_command(output_dir=output_dir)

Expand Down Expand Up @@ -321,7 +321,7 @@ def scaffold_quickstart(
Sets up a project with SmallWebRTC, Daily, Deepgram STT, OpenAI LLM, and Cartesia
TTS — the fastest way to get a voice agent running. Shared by ``pipecat create
quickstart`` (creates a ``pipecat-quickstart`` subfolder) and ``pipecat init
quickstart`` (scaffolds in-place into an already agent-ready directory, via
quickstart`` (scaffolds in-place into an already-initialized directory, via
``dest`` / ``in_place``).
"""
project_name = "pipecat-quickstart"
Expand Down
31 changes: 15 additions & 16 deletions src/pipecat/cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

"""``pipecat init`` — the single starting point for building a Pipecat app.

``pipecat init`` makes a project agent-ready, then routes you to a build method:
``pipecat init`` initializes a new Pipecat project, then routes you to a build method:

- ``AGENTS.md`` — the coding-agent guide (read natively by most coding agents).
- ``CLAUDE.md`` — a one-line ``@AGENTS.md`` import so Claude Code loads it too.
Expand All @@ -21,7 +21,7 @@
hand off to a coding agent (which later scaffolds with ``pipecat create``), or scaffold
a runnable bot right now (it runs the ``pipecat create`` wizard in-place in the same
directory). ``pipecat init quickstart`` skips the question and scaffolds the canned
quickstart bot in-place — agent-ready *and* runnable in one step.
quickstart bot in-place — the coding-agent guide *and* a runnable bot in one step.

``pipecat create`` remains the scaffolder itself: coding agents and automation call
it directly (non-interactively); ``init`` is the human entry point that wraps it.
Expand Down Expand Up @@ -71,7 +71,7 @@ def _guide_footer() -> str:
def _write_agent_guide(target_dir: Path, force: bool) -> None:
"""Write the core agent guide — AGENTS.md and CLAUDE.md — into a directory.

These make the project agent-ready and are wanted on *every* path (coding agent,
These set up the project for coding agents and are wanted on *every* path (coding agent,
scaffold-now, quickstart), so they're written upfront. ``AGENTS.md`` is pipecat-owned
and always (re)written, so re-running refreshes it after a Pipecat upgrade; ``CLAUDE.md``
is the developer's own entry point and is only overwritten with ``force``.
Expand Down Expand Up @@ -142,7 +142,7 @@ def _is_interactive() -> bool:
return sys.stdin.isatty() and sys.stdout.isatty()


def _print_agent_ready(target_dir: Path) -> None:
def _print_ready(target_dir: Path) -> None:
"""Print the guidance shown when the developer keeps the coding-agent path.

Names the project directory so the developer knows where to open their session,
Expand All @@ -152,7 +152,7 @@ def _print_agent_ready(target_dir: Path) -> None:
"""
where = "here" if target_dir.resolve() == Path.cwd() else f"in [bold]{target_dir}[/bold]"
console.print(
f"\n[bold]Project is agent-ready.[/bold]\n\n"
f"\n[bold]Your project is ready.[/bold]\n\n"
f"Read [bold]{_GETTING_STARTED_FILE}[/bold] for how to prompt your agent, then open a "
f"coding session {where} to start building."
)
Expand All @@ -170,7 +170,7 @@ def _route_build_method(target_dir: Path) -> None:
already_scaffolded = (target_dir / "server").exists()
if already_scaffolded or not _is_interactive():
_write_developer_guide(target_dir)
_print_agent_ready(target_dir)
_print_ready(target_dir)
return

import questionary
Expand All @@ -189,7 +189,7 @@ def _route_build_method(target_dir: Path) -> None:
# `ask()` returns None on Ctrl-C / EOF — fall through to the safe agent path.
if choice != "scaffold":
_write_developer_guide(target_dir)
_print_agent_ready(target_dir)
_print_ready(target_dir)
return

# Scaffold now: run the `create` wizard in-place. The scaffold lands in the same
Expand All @@ -213,11 +213,11 @@ def _route_build_method(target_dir: Path) -> None:


def _init_quickstart(force: bool) -> None:
"""``pipecat init quickstart``: the canned quickstart, made agent-ready.
"""``pipecat init quickstart``: the canned quickstart, with the coding-agent guide.

Writes the agent guide into ``pipecat-quickstart/`` and scaffolds the quickstart
bot in-place there, so the learner's first project is both runnable and
agent-ready. The human counterpart to ``pipecat create quickstart`` (which omits
bot in-place there, so the learner's first project is both runnable and set up for
coding agents. The human counterpart to ``pipecat create quickstart`` (which omits
the guide). Non-interactive — it's a fixed preset, so there's no build-method
question.

Expand Down Expand Up @@ -245,16 +245,15 @@ def init_command(
ctx: typer.Context,
target: str | None = typer.Argument(
None,
help="Directory to make agent-ready (or 'quickstart' for the canned bot). "
"Created if missing.",
help="Directory to initialize (or 'quickstart' for the canned bot). Created if missing.",
),
force: bool = typer.Option(
False,
"--force",
help=f"Also overwrite an existing {_CLAUDE_FILE} ({_AGENTS_FILE} is always refreshed).",
),
):
"""Make a project agent-ready, then choose how to build.
"""Initialize a new Pipecat project, then choose how to build.

Writes AGENTS.md + CLAUDE.md + GETTING_STARTED.md, then (interactively) hands you
off to a coding agent or scaffolds a runnable bot in-place with ``pipecat create``.
Expand All @@ -263,11 +262,11 @@ def init_command(

pipecat init # prompt for a directory, then choose how to build
pipecat init my-bot # set up ./my-bot
pipecat init quickstart # agent-ready canned quickstart bot in ./pipecat-quickstart
pipecat init quickstart # canned quickstart bot in ./pipecat-quickstart
pipecat init my-bot --force # overwrite existing files in ./my-bot
pipecat init . # set up the current directory
"""
# `pipecat init quickstart`: scaffold the canned bot in-place, made agent-ready.
# `pipecat init quickstart`: scaffold the canned bot in-place, with the coding-agent guide.
if target == "quickstart":
return _init_quickstart(force)

Expand All @@ -278,7 +277,7 @@ def init_command(
unexpected = " ".join(ctx.args)
console.print(
f"[red]Unexpected arguments:[/red] {unexpected}\n\n"
"`pipecat init` makes a project agent-ready (writes AGENTS.md, CLAUDE.md, "
"`pipecat init` initializes a new Pipecat project (writes AGENTS.md, CLAUDE.md, "
"and GETTING_STARTED.md); it takes only an optional target directory and `--force`.\n"
"To scaffold non-interactively, use [bold]`pipecat create`[/bold] — run "
"`pipecat create --help`."
Expand Down
4 changes: 2 additions & 2 deletions src/pipecat/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ def _build_app():
# positional target path followed by options (e.g. `pc create . --bot-type web`).
app.command("create", help="Create a new Pipecat project")(create_command)

# `init` makes a project agent-ready (writes AGENTS.md + CLAUDE.md). ignore_unknown_options
# `init` initializes a new Pipecat project (writes AGENTS.md + CLAUDE.md). ignore_unknown_options
# lets it catch legacy scaffolder flags (now `pipecat create`) and redirect with a clear
# message instead of an opaque "no such option" error.
app.command(
"init",
help="Make a project agent-ready (writes AGENTS.md + CLAUDE.md)",
help="Initialize a new Pipecat project (writes AGENTS.md + CLAUDE.md)",
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
)(init_command)

Expand Down
10 changes: 5 additions & 5 deletions tests/cli/test_init_agent_ready.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# SPDX-License-Identifier: BSD 2-Clause License
#

"""Tests for `pipecat init` — making a project agent-ready (AGENTS.md + CLAUDE.md)."""
"""Tests for `pipecat init` — initializing a project (AGENTS.md + CLAUDE.md)."""

from pathlib import Path

Expand Down Expand Up @@ -109,14 +109,14 @@ def test_legacy_scaffolder_flags_redirect(self, tmp_path):
# Redirect must not write a half-initialized project.
assert not (tmp_path / "AGENTS.md").exists()

def test_quickstart_scaffolds_and_makes_agent_ready(self, tmp_path, monkeypatch):
def test_quickstart_scaffolds_and_writes_guide(self, tmp_path, monkeypatch):
# `init quickstart` is the human front door for the canned bot: it scaffolds the
# quickstart in-place AND drops the agent guide, all in ./pipecat-quickstart.
monkeypatch.chdir(tmp_path)
result = runner.invoke(app, ["init", "quickstart"])
assert result.exit_code == 0, result.output
project = tmp_path / "pipecat-quickstart"
# Agent-ready files...
# Coding-agent guide files...
assert (project / "AGENTS.md").exists()
assert (project / "CLAUDE.md").read_text(encoding="utf-8").strip() == "@AGENTS.md"
# ...plus a runnable bot in the same directory.
Expand Down Expand Up @@ -173,7 +173,7 @@ def test_scaffold_branch_runs_create_in_place(self, tmp_path, monkeypatch, _sele
# Scaffolding now ends in a built bot, so the from-scratch developer guide is
# skipped — its place is taken by the scaffold's README (see test_quickstart_*).
assert not (tmp_path / "GETTING_STARTED.md").exists()
# ...but the core agent-ready files are still written.
# ...but the core coding-agent guide files are still written.
assert (tmp_path / "AGENTS.md").exists()
assert (tmp_path / "CLAUDE.md").exists()

Expand All @@ -186,7 +186,7 @@ def test_agent_branch_does_not_scaffold(self, tmp_path, monkeypatch, _select):
)
result = runner.invoke(app, ["init", str(tmp_path)])
assert result.exit_code == 0, result.output
assert "agent-ready" in result.output.lower()
assert "your project is ready" in result.output.lower()
assert not (tmp_path / "server").exists()
# The coding-agent path gets the developer guide.
assert (tmp_path / "GETTING_STARTED.md").exists()
Expand Down
Loading