Skip to content

Support pc init . to scaffold a project in place#95

Merged
markbackman merged 3 commits into
mainfrom
mb/create-proj-in-place
Jun 4, 2026
Merged

Support pc init . to scaffold a project in place#95
markbackman merged 3 commits into
mainfrom
mb/create-proj-in-place

Conversation

@markbackman
Copy link
Copy Markdown
Contributor

Summary

Adds an optional positional TARGET path to pc init. Passing a path — e.g. pc init . — scaffolds the project contents directly into that directory instead of nesting them under a <project_name>/ subfolder (the vite/django convention: npm create vite@latest ., django-admin startproject name .).

This is motivated by the upcoming Pipecat agentic coding loop: a user creates a directory containing CLAUDE.md guidance, the agent runs pc init, and the project should land in that directory rather than nested one level down (which would otherwise force the agent to mv/rmdir files around — fragile with hidden files and stray artifacts).

Non-breaking: omitting the positional argument keeps the exact current behavior (<-o or cwd>/<name>/).

Behavior

Invocation Result
pc init Unchanged — <-o or cwd>/<name>/ subfolder
pc init . Scaffold into the current dir; name defaults to the dir basename
pc init ./foo Scaffold directly into ./foo (created if missing)
pc init quickstart [-o DIR] Unchanged — runs quickstart defaults
  • The positional TARGET is the exact destination; -o/--output keeps its legacy "parent dir + name subfolder" meaning. Passing both is an error.
  • Project name when TARGET is given: --name if provided, else derived from the target directory's basename. So --name is optional in this mode.

Implementation notes

  • init converted from a Typer group to a plain command. A positional argument on a Click group can't be followed by options (parsing stops at the first positional), which would break pc init . --bot-type web .... As a plain command, interspersed options work. The quickstart token is dispatched from within init_command to preserve pc init quickstart [-o DIR].
  • ProjectGenerator.generate(..., in_place=True) writes straight into the target, guards against clobbering an existing project (aborts if a server/ dir is already present), and print_next_steps omits the now-irrelevant cd <name> step. Shared file-writing logic extracted into _write_project_files.

Testing

  • uv run pytest tests/ → 445 passing.
  • New tests/test_init_in_place.py: in-place writes, name derivation, CLAUDE.md preservation, conflict abort, target/-o mutual exclusion, and non-breaking regressions (nested layout + quickstart). Plus generator-level in_place unit tests.
  • Manual: pc init . into a dir holding CLAUDE.md → flat layout (server/, README.md, .gitignore), CLAUDE.md untouched, name derived from the folder.

🤖 Generated with Claude Code

Add an optional positional TARGET path to 'pc init'. Passing a path
(e.g. '.') scaffolds the project contents directly into that directory
instead of nesting them under a <project_name> subfolder. The project
name defaults to the target directory's basename (--name still overrides).

Convert 'init' from a Typer group to a plain command so the positional
argument can be followed by options (Click groups stop parsing options
at the first positional). The 'quickstart' token is dispatched from the
init callback to preserve 'pc init quickstart [-o DIR]'.

Omitting the positional argument keeps the existing nesting behavior, so
this change is non-breaking.
Cover CLI behavior (in-place writes, name derivation from the directory,
CLAUDE.md preservation, conflict abort, target/-o mutual exclusion) and
non-breaking regressions (nested layout, quickstart), plus generator-level
in_place unit tests.
@markbackman markbackman merged commit 753898e into main Jun 4, 2026
1 check passed
@markbackman markbackman deleted the mb/create-proj-in-place branch June 4, 2026 22:20
markbackman added a commit to pipecat-ai/pipecat that referenced this pull request Jun 4, 2026
Add an optional positional TARGET to `pipecat init`. Passing a path — e.g.
`pipecat init .` — scaffolds the project directly into that directory instead
of nesting it under a <project-name>/ subfolder (the vite/django convention).
The project name defaults to the target directory's basename; --name still
overrides it. Omitting the argument keeps the existing behavior, so this is
non-breaking.

init is converted from a Typer group to a plain command so the positional can
be followed by options; the quickstart token is dispatched from within
init_command to preserve `pc init quickstart [-o DIR]`. ProjectGenerator gains
an in_place mode that writes straight into the target, guards against
clobbering an existing project (server/ present), and omits the `cd <name>`
next step.

Ported from pipecat-ai/pipecat-cli#95.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant