Prepared 2026-07-18 so the owner's deploy-verified window is an execution, not a
discovery project. Why this is deploy-gated and not auto-executed:
deploy-hetzner.yml auto-fires on push to main with path filters that
include services/psyche/**, libs/**, and its own workflow file — a move
commit both matches the old filters (deleted paths) and rewrites the pipeline it
triggers, unwatched. The Hetzner pipeline is also under active development in a
parallel session (oshun-lt-2-hetzner). Execute this in a window where a failed
deploy is observable and reversible.
Scope#
Move services/concordia (1 orchestrator project), services/metis (Python
FastAPI service: alembic, openapi export, own Dockerfiles), and
services/psyche (~14 sub-services with project.json + Dockerfiles) into
apps/. Note apps/metis/* already exists (admin/api-gateway/mobile/web/
worker are the TS surfaces); services/metis is the Python backend — land it
as apps/metis/service (recommended) to avoid a name collision, and land
psyche/concordia as apps/psyche, apps/concordia.
Complete live-reference inventory (79 tracked files; regenerate with the#
command below before executing — parallel sessions add references)
git grep -l -E "services/(concordia|metis|psyche)" \
| grep -v -E "^(docs/|evidence/|TODOS/|V[0-9]|WALKTHROUGH)"
By category:
- Workflows (6):
deploy-ecs.yml(dispatch-only; psyche path map lines ~177/253),deploy-hetzner.yml(auto-fire; filter line ~49 + path maps ~190/285),metis-e2e.yml,prompt-injection-portfolio.yml(pip install-e services/metis[dev]),psyche-ci.yml(~10 glob sites),psyche-container-build.yml. - Build/deploy config:
infrastructure/terraform/variables.tf(comment ~line 172),deploy/v1/hetzner/docker-compose.yml(2 comment references), per-service Dockerfiles under the moved trees (checkCOPY/WORKDIRrelative-depth assumptions — psyche Dockerfiles build with own contexts). - Workspace config:
tsconfig.base.json— 118 alias path entries;pnpm-workspace.yaml—services/concordia/*glob (metis/psyche are Python, not pnpm members);nx.jsonworkspaceLayout.servicesDir(drop it);package.json(1 script reference);pnpm-lock.yamlimporter keys forservices/concordia/*(regenerated bypnpm install --lockfile-only). - Nx projects: every
project.jsoninside the moved trees carriessourceRoot/target cwds withservices/...paths (~16 files). - Cross-references (~25 lib/app files): hardcoded service paths in
libs/openapi/scripts/generate.ts+ generatedmetis.ts,libs/metis/*transports/tests,libs/calliope/bridge,libs/nous/advanced-speech(2),libs/neith/cloud,libs/v9/*(2),libs/oshun/*(2),apps/metis/admin/e2efixtures,apps/oshun/webConcordia adapter,scripts/verify-phase-25-completion.mjs,services/metisself-references (openapi export, admin service, tests), psyche READMEs/self-refs. - Guards to update:
tools/docs/verify-domains-source-of-truth.mjsCODE_ROOT_ALLOWLIST(keysservices/metis,services/psyche; theREQUIRED_PLANNED_ROOTSneedles reference TODO text and stay);tools/env/split-env-examples.mjsderives per-app env files — moved trees become apps and must emit their.env.example(run--check). - Leave alone:
docs/,evidence/,TODOS/,V*/,DEPENDENCIES.md,content-coverage/seed-registry.v1.json(historical/regenerable records — regenerate the seed registry rather than editing).
Execution order (one change, one push)#
- Freeze window: confirm no parallel session is mid-flight on
deploy-hetzner.yml/oshun-lt-2-*branches; announce the window. git mv services/concordia apps/concordia && git mv services/psyche apps/psyche && git mv services/metis apps/metis/service.- Mechanical rewrite over the categories above:
services/psyche→apps/psyche,services/concordia→apps/concordia,services/metis→apps/metis/service(careful: do NOT blind-sed the deploy workflows'apps/metis/*lines that already exist). - Drop
workspaceLayout.servicesDirfrom nx.json; update pnpm-workspace glob;pnpm install --lockfile-only. - Static verification, all green before push:
npx nx show projectfor each moved project (graph resolves);pnpm nx affected -t lint --files=<moved>dry pass;- spot-
tsctwo consumers of the 118 aliases; - psyche pytest per
reference_devbox_toolchains(208 baseline) + metis pytest; concordia orchestrator suite; - glob-test every changed workflow path filter against
git ls-files(the audit G-2 method); node tools/env/split-env-examples.mjs --check;node tools/docs/verify-domains-source-of-truth.mjs;act-style dry parse of deploy-hetzner detection script with a synthetic changed-file list covering each service class.
- Push during the window; watch the auto-fired
deploy-hetznerrun to completion (or confirm it no-ops on filter mismatch); dispatch adeploy-ecsstaging run for one psyche service to validate the ECS map. - Rollback: single revert commit restores every path; images/deploys are immutable-tagged so reverting the repo reverts the pipeline inputs.