Describe the problem
Bug Report: TUI prompts appear during copier update despite --defaults --skip-answered flags
Description
When running copier update with --defaults --skip-answered flags in automation contexts (Make targets, shell scripts), the interactive TUI still appears and prompts for questions that have already been answered. This breaks non-interactive workflows and causes commands to hang waiting for user input.
Expected Behavior
When using --defaults --skip-answered flags, copier should:
- Use default values for all questions
- Skip questions that already have answers in
.copier-answers.yml
- Run completely non-interactively without showing the TUI
- Complete successfully without requiring terminal input
Actual Behavior
Despite using --defaults --skip-answered flags, copier:
- Shows the interactive TUI with emoji prompts (🎤)
- Displays questions that already have answers
- Waits for user input, causing the command to hang
- Prevents automation/CI/CD workflows from completing
Reproduction Steps
- Create a template and generate a project with copier
- Ensure project has
.copier-answers.yml with previous answers
- Run update from a Makefile or script using
$() command substitution:
update:
OUTPUT=$$(copier update --trust --defaults --skip-answered --vcs-ref=HEAD 2>&1); \
echo "$$OUTPUT"
- The command hangs showing interactive prompts despite flags
Environment
- Copier version: 9.11.0
- Python version: 3.12
- OS: Linux
- Context: Make target with
$$() command substitution
Root Cause
Copier detects if stdin is connected to a terminal and launches the TUI even when --defaults --skip-answered flags are present. In Make's $$() subprocess, stdin remains open/connected, causing copier to attempt interactive mode.
Workaround
Close stdin explicitly when running copier in a subshell:
( copier update --trust --defaults --skip-answered --vcs-ref=HEAD 0<&- < /dev/null ) > output.txt 2>&1
Or in a Makefile:
OUTPUT=$$($$COPIER_CMD update $$OPTS 0<&- < /dev/null 2>&1);
This forces copier into non-interactive mode by closing file descriptor 0.
Impact
This issue affects:
- ✗ Makefile-based automation
- ✗ CI/CD pipelines using shell script wrappers
- ✗ Any subprocess that captures output via
$()
- ✗ Automated template updates in frameworks
Suggested Fix
The --defaults and --skip-answered flags should take precedence over stdin detection. If these flags are present, copier should:
- Never attempt to show the TUI
- Raise an error if a required question has no default/answer (as documented)
- Run in truly non-interactive mode regardless of stdin state
Alternatively, document that stdin must be explicitly closed when running copier in subprocess contexts for automation.
References
Additional Context
The extensive test suite for --skip-answered uses spawn() which creates a pseudo-terminal (PTY). This is different from Make's $$() subprocess behavior where stdin is inherited from the parent process. The tests pass because PTY behaves differently than real subprocess stdin redirection.
The workaround is reliable but non-obvious. Many users expect --defaults --skip-answered to mean "never prompt, use existing answers" without needing to understand stdin file descriptor manipulation.
Template
Digitalized Architecture Framework - Template Configuration
=============================================================
_metadata:
version: "1.1.0"
description: "Digitalized Architecture Framework with Four Architecting Pillars"
Default answers (for --defaults mode)
project_name: "my-project"
project_description: "A software development project using the Digitalized Architecture Framework"
organization_name: "Development Team"
methodology_folder: "daf-methodology"
workspace_folder: "daf-workspace"
tests_folder: "tests"
use_capability_areas: true
use_user_journeys: true
use_issue_templates: true
use_test_methodology: true
use_reports: false
Questions for interactive mode
_questions:
project_name:
type: str
help: "What is the name of your project?"
placeholder: "my-awesome-project"
default: "my-project"
project_description:
type: str
help: "Brief description of your project"
placeholder: "An innovative solution for..."
default: "A software development project"
organization_name:
type: str
help: "Your organization name"
placeholder: "Acme Corp"
default: "Development Team"
workspace_folder:
type: str
help: "Name for the workspace folder (your project work)"
placeholder: "daf-workspace, ai-project, my-workspace"
default: "daf-workspace"
tests_folder:
type: str
help: "Name for the tests folder (test suite location)"
placeholder: "tests, test, tst"
default: "tests"
use_capability_areas:
type: bool
help: "Include Capability Area methodology?"
default: true
use_user_journeys:
type: bool
help: "Include User Journey methodology?"
default: true
use_issue_templates:
type: bool
help: "Include issue tracking templates?"
default: true
use_test_methodology:
type: bool
help: "Include testing methodology?"
default: true
use_reports:
type: bool
help: "Include reporting tools and templates?"
default: false
Template processing
_templates_suffix: ".jinja2"
_envops:
keep_trailing_newline: true
Skip existing files by default (non-destructive installation)
_skip_if_exists:
- "README.md"
- "*/README.md"
Files to exclude
_exclude:
- "copier.yml"
- "copier.yml.bak"
- ".copier-answers.yml" # Framework's answers (adopters generate their own)
- ".git"
- ".gitignore"
- "*.pyc"
- "pycache"
- ".DS_Store"
Framework development (not shipped to users)
- "daf-workspace"
- "daf-workspace/**"
- "pytest.ini" # Dev version includes daf-workspace/tests
- "install.sh"
- "pdf"
- "pdf/**"
- "tests"
- "tests/**"
Install scripts and templates (used by install.sh, not copied)
- "daf-methodology/bin/install"
- "daf-methodology/bin/install/**"
Symlinked directories (do not copy symlinks, copy actual source files instead)
- "daf-methodology/docs/_root"
- "daf-methodology/docs/_root/**"
Generated files
- "**/00-OVERVIEW.md" # Generated by navigation script
- "daf-methodology/docs/index.md" # Symlink (generated)
Framework-specific files (not for adopters)
- "mkdocs-ai-dev.yml" # Framework dev only (not copied to adopters)
- "CONTRIBUTING.md" # Copied as DAF-CONTRIBUTING.md by install.sh
Tasks to run after generation
_tasks:
Note: Copier automatically creates .copier-answers.yml for update support
- "echo '✅ Digitalized Architecture Framework installed successfully!'"
- "echo ''"
- "echo '📊 Framework: 8 Methodologies across 4 Pillars'"
- "echo ' Pillar 1: Value Stream Architecting (User Journey, Domain Modeling)'"
- "echo ' Pillar 2: Complexity Management Architecting (Capability Area, Arc42++)'"
- "echo ' Pillar 3: Product Memory Architecting (Knowledge Map, Conversation Backlog)'"
- "echo ' Pillar 4: Quality Assurance Architecting (Testing Pyramid, Delivery Modeling)'"
- "echo ''"
- "echo '📖 What was created:'"
- "echo ' • docs/knowledge-map.html - Interactive methodology visualization'"
- "echo ' • README.md - Framework overview with Four Pillars'"
- "echo ' • daf-methodology/make/backlog.mk - Makefile extension for backlog management'"
- "echo ' • daf-methodology/bin/backlog/ - Backlog management scripts (CLI, TUI)'"
- "echo ' • .github/instructions/ - AI agent instruction files (context-optimized)'"
- "echo ' • .github/prompts/ - README enhancement prompts for AI agents'"
- "echo ' • docs/capability-areas/ - Feature development templates'"
- "echo ' • docs/user-journeys/ - User experience templates'"
- "echo ' • issues/templates/ - Issue tracking templates (Conversation Backlog)'"
- "echo ' • tests/ - Testing Pyramid methodology'"
- "{% if use_reports %}echo ' • reports/ - Reporting tools'{% endif %}"
- "echo ''"
- "echo '📚 Quick Start:'"
- "echo ' 1. Explore: Run make meth-serve (Ctrl+Click URL to open docs)'"
- "echo ' 2. Document: Start in daf-workspace/docs/capability-areas/'"
- "echo ' 3. Issues: Run make issues-ui (interactive TUI)'"
- "echo ''"
- "echo '⚙️ Optional (custom folder names): Edit daf-config.yml, then run make config-update'"
- "echo '📦 Updates: Run make daf-update to get latest framework'"
To Reproduce
No response
Logs
Expected behavior
it should work without TUI
Screenshots/screencasts/logs
No response
Operating system
Linux
Operating system distribution and version
Ubuntu 24
Copier version
Copier 9.11.0
Python version
Python 3.12.3
Installation method
uvx+pypi
Additional context
No response
Describe the problem
Bug Report: TUI prompts appear during
copier updatedespite--defaults --skip-answeredflagsDescription
When running
copier updatewith--defaults --skip-answeredflags in automation contexts (Make targets, shell scripts), the interactive TUI still appears and prompts for questions that have already been answered. This breaks non-interactive workflows and causes commands to hang waiting for user input.Expected Behavior
When using
--defaults --skip-answeredflags, copier should:.copier-answers.ymlActual Behavior
Despite using
--defaults --skip-answeredflags, copier:Reproduction Steps
.copier-answers.ymlwith previous answers$()command substitution:Environment
$$()command substitutionRoot Cause
Copier detects if stdin is connected to a terminal and launches the TUI even when
--defaults --skip-answeredflags are present. In Make's$$()subprocess, stdin remains open/connected, causing copier to attempt interactive mode.Workaround
Close stdin explicitly when running copier in a subshell:
Or in a Makefile:
This forces copier into non-interactive mode by closing file descriptor 0.
Impact
This issue affects:
$()Suggested Fix
The
--defaultsand--skip-answeredflags should take precedence over stdin detection. If these flags are present, copier should:Alternatively, document that stdin must be explicitly closed when running copier in subprocess contexts for automation.
References
--skip-answered: Don't require users to review all questions when running copier update #1178pexpect.spawn()with PTY, not subprocess$()Additional Context
The extensive test suite for
--skip-answeredusesspawn()which creates a pseudo-terminal (PTY). This is different from Make's$$()subprocess behavior where stdin is inherited from the parent process. The tests pass because PTY behaves differently than real subprocess stdin redirection.The workaround is reliable but non-obvious. Many users expect
--defaults --skip-answeredto mean "never prompt, use existing answers" without needing to understand stdin file descriptor manipulation.Template
Digitalized Architecture Framework - Template Configuration
=============================================================
_metadata:
version: "1.1.0"
description: "Digitalized Architecture Framework with Four Architecting Pillars"
Default answers (for --defaults mode)
project_name: "my-project"
project_description: "A software development project using the Digitalized Architecture Framework"
organization_name: "Development Team"
methodology_folder: "daf-methodology"
workspace_folder: "daf-workspace"
tests_folder: "tests"
use_capability_areas: true
use_user_journeys: true
use_issue_templates: true
use_test_methodology: true
use_reports: false
Questions for interactive mode
_questions:
project_name:
type: str
help: "What is the name of your project?"
placeholder: "my-awesome-project"
default: "my-project"
project_description:
type: str
help: "Brief description of your project"
placeholder: "An innovative solution for..."
default: "A software development project"
organization_name:
type: str
help: "Your organization name"
placeholder: "Acme Corp"
default: "Development Team"
workspace_folder:
type: str
help: "Name for the workspace folder (your project work)"
placeholder: "daf-workspace, ai-project, my-workspace"
default: "daf-workspace"
tests_folder:
type: str
help: "Name for the tests folder (test suite location)"
placeholder: "tests, test, tst"
default: "tests"
use_capability_areas:
type: bool
help: "Include Capability Area methodology?"
default: true
use_user_journeys:
type: bool
help: "Include User Journey methodology?"
default: true
use_issue_templates:
type: bool
help: "Include issue tracking templates?"
default: true
use_test_methodology:
type: bool
help: "Include testing methodology?"
default: true
use_reports:
type: bool
help: "Include reporting tools and templates?"
default: false
Template processing
_templates_suffix: ".jinja2"
_envops:
keep_trailing_newline: true
Skip existing files by default (non-destructive installation)
_skip_if_exists:
Files to exclude
_exclude:
Framework development (not shipped to users)
Install scripts and templates (used by install.sh, not copied)
Symlinked directories (do not copy symlinks, copy actual source files instead)
Generated files
Framework-specific files (not for adopters)
Tasks to run after generation
_tasks:
Note: Copier automatically creates .copier-answers.yml for update support
To Reproduce
No response
Logs
Expected behavior
it should work without TUI
Screenshots/screencasts/logs
No response
Operating system
Linux
Operating system distribution and version
Ubuntu 24
Copier version
Copier 9.11.0
Python version
Python 3.12.3
Installation method
uvx+pypi
Additional context
No response