Skip to content

Bug Report: TUI prompts appear during copier update despite --defaults --skip-answered flagsΒ #2436

@SteelOtter1242

Description

@SteelOtter1242

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:

  1. Use default values for all questions
  2. Skip questions that already have answers in .copier-answers.yml
  3. Run completely non-interactively without showing the TUI
  4. Complete successfully without requiring terminal input

Actual Behavior

Despite using --defaults --skip-answered flags, copier:

  1. Shows the interactive TUI with emoji prompts (🎀)
  2. Displays questions that already have answers
  3. Waits for user input, causing the command to hang
  4. Prevents automation/CI/CD workflows from completing

Reproduction Steps

  1. Create a template and generate a project with copier
  2. Ensure project has .copier-answers.yml with previous answers
  3. 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"
  4. 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:

  1. Never attempt to show the TUI
  2. Raise an error if a required question has no default/answer (as documented)
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugtriageTrying to make sure if this is valid or not

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions