Skip to content

Fix #179: Migrate legacy .autocoder projects and scaffold allowed_commands.yaml - #292

Open
zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-179-ada
Open

zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-179-ada

Conversation

@zwanski-start

Copy link
Copy Markdown

Closes #179

Problem

Opening an existing AutoCoder-era project left .autoforge/ and .autocoder/ effectively empty, and .autoforge/allowed_commands.yaml was never created:

  • migrate_project_layout only renamed .autocoder/ → .autoforge/ when .autoforge/ did not exist. If anything had already created .autoforge/ (e.g. registering the folder in the UI, which scaffolds before migrating), the legacy dir was never migrated.
  • allowed_commands.yaml is only copied in scaffold_project_prompts (new projects). No migration created it for existing projects.
  • scaffold_project_prompts always stamped the current migration version, so registering an existing folder skipped its pending migrations.

Changes

  • autoforge_paths.py: when both dirs exist, merge .autocoder/ entries into .autoforge/ (existing .autoforge/ entries win), then remove .autocoder/ if it's empty.
  • prompts.py: new _ensure_allowed_commands_file helper (shared with scaffolding) and migration v2 that creates .autoforge/allowed_commands.yaml for existing projects. It runs on agent start via migrate_project_to_current. CURRENT_MIGRATION_VERSION goes from 1 to 2.
  • prompts.py: only stamp the migration version when the prompts were freshly created from templates.
  • server/routers/projects.py and start.py: run migrate_project_layout before scaffolding when registering a project folder.

Verification

  • New test_project_migration.py (7 tests): rename, merge into an existing .autoforge/, conflict handling, v2 creates or keeps the allowlist, new-project scaffold, and an existing-project scaffold that doesn't skip migrations.
  • ruff check . passes. mypy . reports no new errors (the 26 existing errors are all in files this PR doesn't touch). test_security.py, test_security_integration.py and test_client.py pass.
  • No UI changes, so I didn't do a browser check.

Assumptions

  • Migration still happens on agent start and when a folder is registered. It does not run on a plain GET /api/projects/{name}. A GET shouldn't move databases around, and the assistant DB may be open at that point.
  • If the same entry exists in both dirs, the .autoforge/ copy wins and the legacy copy stays in .autocoder/.
  • A project that already has .autocoder/allowed_commands.yaml doesn't get a new template, because security.py still reads that path.

🤖 Generated with Claude Code

…allowed_commands.yaml

- migrate_project_layout now merges .autocoder/ into an existing
  .autoforge/ instead of silently skipping the migration when the new
  directory already exists (leaving both effectively empty/unused).
- Add migration v2 that creates .autoforge/allowed_commands.yaml for
  existing projects that never received the template.
- Run the layout migration before scaffolding when registering an existing
  folder (UI + CLI), so legacy files aren't shadowed by fresh scaffolding.
- Only stamp the migration version on genuinely new projects, so registering
  an existing project doesn't skip pending prompt migrations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zwanski-start

Copy link
Copy Markdown
Author

🔍 QA report: ✅ Passed

Tester: Barbara (cubefarm agent, in a fresh session) · Round: 1 · Author: Ada

Registering a legacy AutoCoder project (via POST /api/projects or start.py) now moves .autocoder/ prompts and features.db into .autoforge/, also merges into an existing .autoforge/, and creates .autoforge/allowed_commands.yaml through a new v2 migration. I confirmed this end to end on the real server, and also on a project registered with master's code (the state the issue describes), where the agent-start migration completed the move. ruff, the new tests and the security tests pass. The 21 pytest failures and 25 mypy errors are the same as on master.

Check Details
✅ Issue repro: register legacy .autocoder project via UI API Made a project with .autocoder/prompts (app_spec, coding/initializer prompts) and .autocoder/features.db with 1 feature, then POSTed /api/projects (200). Result: .autoforge/{prompts,features.db,allowed_commands.yaml,.gitignore} exist, .autocoder/ is removed and the legacy prompts are kept. GET /api/projects/legacy1 returns has_spec=true and 1/1 passing. The migration version is left unset, so the v0->v1 prompt migration still runs on agent start.
✅ Project already registered with master's code Ran master's scaffold_project_prompts on a legacy project: real prompts and DB stayed in .autocoder/ and the version was stamped 1, which reproduces the bug. The PR's agent-start sequence (migrate_project_layout + migrate_project_to_current) merged features.db and prompts into .autoforge/, removed .autocoder/ and set the version to 2.
✅ Agent-start migration is idempotent Running migrate_project_layout and migrate_project_to_current again on the migrated project returned [] and kept .migration_version=2.
✅ Allowlist creation doesn't overwrite or shadow existing config _ensure_allowed_commands_file skips when .autoforge/ or legacy .autocoder/allowed_commands.yaml exists. security.py's allowlist and config lookup are unchanged. Covered by unit tests.
✅ New unit tests (test_project_migration.py) All 7 pass: rename, merge, conflict keeps .autoforge/ entry, v2 creates or keeps the allowlist, new-project stamping, existing-project scaffold doesn't stamp.
✅ No regressions vs master (pytest, mypy) Ran both on a throwaway origin/master worktree. The sorted pytest FAILED lists match exactly (21, all in test_devserver_security.py) and the mypy error lists match exactly (25).
✅ Browser: migrated project renders in dashboard/Kanban/Graph Selected legacy1. The dashboard shows 1/1 at 100%, the Kanban board shows 'Legacy feat' in Done, the Graph view renders and phone width (390px) loads. No console errors or warnings.
⏭️ UI e2e (Playwright test suite) The PR changes no UI files. The UI build and lint pass.
✅ Server cleanup Stopped uvicorn on 5443 (health check refused afterwards) and found no tracebacks in the server log. The worktree is clean.
🧪 Commands run
Command Result
ruff check . All checks passed
mypy . 25 errors in 10 files, the same list as origin/master (none in changed files)
python -m pytest -q 151 passed, 21 failed; the failures are the same as on origin/master (test_devserver_security.py)
python -m pytest -v test_project_migration.py 7 passed
python test_security.py ALL TESTS PASSED
python test_security_integration.py ALL INTEGRATION TESTS PASSED
npm --prefix ui run build built successfully
npm --prefix ui run lint 0 errors, 6 warnings
HOME=<scratch> python -m uvicorn server.main:app --host 127.0.0.1 --port 5443 + curl POST /api/projects, GET /api/projects/legacy1, GET /api/projects/legacy1/features 200s; legacy files migrated, allowlist created, feature data served
python -c migrate_project_layout + migrate_project_to_current (agent-start sequence) on PR code and on a master-scaffolded project Merged leftover .autocoder entries, version moved to 2, idempotent on re-run

No browser screenshots were taken in this round.

Posted by cubefarm · merges automatically once GitHub's checks pass

cabana8471-arch pushed a commit to cabana8471-arch/autoforge that referenced this pull request Nov 8, 2026
…allowed_commands.yaml

Adaptations: autocoder_config._get_config_path now uses project_config._get_config_path's order (.autoforge/config.json, then legacy .autocoder/config.json, new files in .autoforge/), so both modules read one file; docs (FORK_README, git_workflow docstring) updated. start.py conflict resolved (my-features import layout). New test_autocoder_config_path.py. Migration (prompt version 1 -> 2) verified on a copy of a real legacy project: .autocoder/allowed_commands.yaml merged into the existing .autoforge/ byte-identical, root prompts/ and DBs moved, idempotent on re-run, pre-migration code still runs and serves the features.

Integrates AutoForgeAI#292

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeH26pcsqoxPb3CDs8g1VN
cabana8471-arch added a commit to cabana8471-arch/autoforge that referenced this pull request Nov 8, 2026
migrate_project_layout runs in the AutoForge process, outside the agent's sandbox. A .autocoder/ that the agent turned into a symlink (node -e, or a committed symlink restored by git) made the new merge step (AutoForgeAI#292) move the link target's files into .autoforge/; reproduced with a symlink to a directory holding a key file. A symlinked prompts/ was copied the same way (copytree follows links), and root DBs/settings files were followed too. Every step now skips symlinks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeH26pcsqoxPb3CDs8g1VN
cabana8471-arch pushed a commit to cabana8471-arch/autoforge that referenced this pull request Nov 8, 2026
Adaptations: the prompt migration lands as v3 (_migrate_v2_to_v3, CURRENT_MIGRATION_VERSION = 3) after AutoForgeAI#292's v2. Fixed a non-idempotent replacement (the testing-prompt note was appended again on every run, since its new text starts with the old one) and skip symlinked prompt files. New test_prompt_migrations.py: v3 converges pre-v3 template wording on the current templates, second run changes nothing, custom prompts untouched, validation/ + .gitignore entry created, v1 chain and new-project stamp; v2 idempotency and untouched prompts.

Integrates AutoForgeAI#289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeH26pcsqoxPb3CDs8g1VN
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.

.autoforge/allowed_commands.yaml NOT generated for existing autocoder project

1 participant