Fix: Exclude .factory/ directory from git commits

Resolved 💬 4 comments Opened Nov 5, 2025 by sl-factory[bot] Closed Jan 9, 2026

Summary

Prevent Factory internal state files (logs, conversation history, state files) from being committed to project repositories by ensuring .factory/ is always excluded from git operations.

Problem (Bug #4 from #167)

During Stage 2 execution, PR #19 accidentally included 86 Factory internal files:

  • .factory/logs/2025-11-04_21-49-13_sprint/prompts/msg_*.txt (65+ prompt/response files)
  • .factory/current-sprint.json
  • Full conversation history from all tickets

This caused Code Reviewer to review the wrong ticket - it read Ticket #1's conversation logs and echoed that instead of reviewing Ticket #3's actual code changes.

Impact:

  • Code Reviewer sees incorrect context (other tickets' conversations)
  • PRs become massive (1.5MB for simple config changes)
  • Exposes internal Factory operations in public repos
  • Token waste (Code Reviewer reads logs instead of code)

Root Cause

  1. .factory/ directory NOT in project's .gitignore
  2. git_add tool stages everything matching patterns without filtering
  3. Developer agent doesn't validate staged files before committing

Solution

Primary Fix: git_add tool should auto-exclude .factory/

Update src/factory/agents/tools.py:

def git_add(files: list[str], project_path: str) -> dict:
    # ... existing validation ...

    # IMPORTANT: Never commit Factory internal state
    # Filter out .factory/ paths before staging
    filtered_files = []
    for file in files:
        if not file.startswith('.factory/') and '/.factory/' not in file:
            filtered_files.append(file)
        else:
            logger.warning(f"Skipping Factory internal file: {file}")

    if not filtered_files:
        return {"success": False, "error": "No files to add after filtering"}

    # Stage filtered files
    subprocess.run(["git", "add"] + filtered_files, cwd=project_path, ...)

Secondary Fix: CLI ensures .factory/ in .gitignore

At sprint start (Stage 2), verify .factory/ is in project's .gitignore:

# In cli.py, before execute_stage_2():
gitignore_path = project_dir / ".gitignore"
if gitignore_path.exists():
    content = gitignore_path.read_text()
    if '.factory/' not in content:
        # Append .factory/ to gitignore
        with open(gitignore_path, 'a') as f:
            f.write('\n# Factory internal state (do not commit)\n.factory/\n')

Test Plan

  1. Unit test for git_add filtering:
  • Create test files including .factory/logs/test.txt
  • Call git_add(['.factory/logs/test.txt', 'src/index.ts'])
  • Verify only src/index.ts staged
  • Verify warning logged for .factory/ file
  1. E2E test:
  • Start fresh sprint with test project
  • Let Developer complete one ticket
  • Check staged files for PR: should NOT include .factory/*
  • Check .gitignore: should contain .factory/
  1. Verify existing repos:
  • Run CLI on existing project without .factory/ in .gitignore
  • Verify CLI adds it automatically
  • Verify no Factory files in subsequent commits

Acceptance Criteria

  • [ ] git_add tool filters out all .factory/ paths
  • [ ] Warning logged when Factory files are skipped
  • [ ] CLI verifies/adds .factory/ to .gitignore at sprint start
  • [ ] Unit tests for git_add filtering
  • [ ] E2E test verifies no Factory files in PRs
  • [ ] Documentation: .factory/ should never be committed
  • [ ] Test on existing repo without .factory/ in .gitignore

Related Issues

  • Fixes Bug #4 in #167
  • Prevents Code Reviewer from seeing wrong context
  • Reduces PR size and token usage

Priority

High - This causes Code Reviewer to malfunction and review wrong tickets.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗