migration-project-move · v1.0.0 · 2026-09-15 · sha256 1819057598e9f4dc

migration-project-move v1.0.0A

Immutable. This exact content is served forever at /api/v1/blob/1819057598e9f4dc.

---
name: migration-project-move
description: >
  Narrow POSIX contract for the bundled initiating-Agent whole-Project
  same-volume self-move helper.
version: 1.0.0
last_changed_at: "2026-09-15T03:15:00Z"
tags: [lingtai, migration, project, relocation, posix, no-replace, lease, recovery]
related_files:
- src/lingtai/intrinsic_skills/system-manual/reference/migration-guide/SKILL.md
- src/lingtai/intrinsic_skills/system-manual/reference/migration-guide/scripts/move_project.py
- src/lingtai/tools/system/ANATOMY.md
- src/lingtai/tools/system/CONTRACT.md
- tests/test_move_project.py
maintenance: |
  Keep this helper contract aligned with move_project.py and its focused tests.
  Common authority, phase, acceptance, and receipt rules stay in the parent router.
---

# Project Move Helper

**Conclusion:** first complete the parent [migration router](../../SKILL.md).
Use this helper only for its narrow initiating-Agent, local same-volume POSIX
lane; otherwise `HOLD`.

## Invoke

```sh
python <exact-move_project.py> --agent-dir /absolute/project/.lingtai/agent --to /absolute/new-project-root [--timeout 30]
```

The bundled source is `../../scripts/move_project.py`. It moves only the Project
directly above the initiating Agent's `.lingtai`. The authorized operation must
include shutdown, root rename, any project-local venv rebase, and relaunch.

## Filesystem and observation contract

The helper requires a trusted local operator, separately established
local-filesystem semantics, and no same-privilege source, target, or helper
mutation. It rechecks canonical non-symlink paths, an absent target outside the
source, equal `st_dev`, and Linux `RENAME_NOREPLACE` or macOS `RENAME_EXCL`.
Network or unknown filesystems are `HOLD`.

Supported process observation is a flat `ps command=` string. Source, target,
initiating workdir, and every Agent-present direct child must therefore be
printable with no surrounding whitespace; interior spaces and printable Unicode
remain valid. Before any runtime probe or process scan, the helper lazily
verifies a process-local copied environment with bounded `locale charmap`:
Darwin uses the proven `en_US.UTF-8` candidate; Linux prefers
`C.UTF-8`/`C.utf8`, then `en_US.UTF-8`; only a normalized exact `UTF-8` result is
accepted. That cached environment goes only to helper-owned command and ancestry
`ps` calls with strict UTF-8 decoding. It neither changes the ambient
environment nor enters the relaunched Agent. Probe, execution, decode, or
no-locale failure refuses before suspension.

## Self-handoff and sibling fence

“Self” means invocation by that Agent's synchronous Shell. The outer helper
requires the exact PID/token in its current ancestor chain, starts the detached
supervisor with one inherited private gate, and releases it only to preflight and
flock every valid stopped sibling. While the Shell still pins normal Agent
execution/lease teardown, the outer helper revalidates ancestor/token, process,
heartbeat, lease, and workdir set; exclusively creates `.suspend`; finalizes and
verifies its descriptor at exact mode 0600; closes it; sends one explicit commit
byte; then closes the gate. EOF before that byte and wrong or trailing protocol
data abort source-authoritative. Direct terminal/wrapper callers refuse.

After the exact byte and normal close, one `lstat` accepts either one regular
non-symlink marker or its lifecycle-consumed absence. Every pre-marker
PID/token/ancestry observation remains strict. Only after that commit, an
unavailable initiating identity may mean normal exit when a fresh strict
Project-process rescan proves its PID absent and finds no replacement. The wait
still needs a later empty scan, stale heartbeat, acquired initiating lease, and
final cutover revalidation. A crash plus external auto-restart is outside this
causal guarantee and requires inspection.

Any direct child with `.agent.json` or `init.json` is Agent-present, except the
exact canonical direct record-only `human` pseudo-agent (`agent_name`/`address`
both `human`, `admin` missing/null), which is validated then excluded as
non-launchable. Every malformed, partial, symlinked, aliased, noncanonical, or
identity-disagreeing shape refuses before the marker. Safe ordinary siblings
remain fenced through target liveness. Post-rename proof rejects any Agent-run
process still naming the old source. Siblings and `human` are never launched.

## Runtime and prompt boundaries

A present `venv_path` must be a string before selection. A nonempty string
remains explicit and must be existing, canonical, absolute, and non-symlink;
only a missing key or empty string selects the existing canonical managed
default. Only a project-local explicit venv rebases. Every path the canonical
owner classifies as the managed default—including an explicit equal path—must
have marker status exactly `match` before suspension and at target-origin probe;
`missing`, `error`, and `mismatch` refuse read-only. That managed default receives
current Python-selection policy with the owner's `RuntimeError` fallback.
Ordinary nondefault operator venvs retain owner-compatible marker handling and
remain policy-exempt.

Durable init stays unchanged. The helper creates, stamps, heals, removes, or
rewrites no venv or managed-environment marker. The exact target
runtime/cwd/environment prove
executable/import origin and relaunch only the initiator. Semantic JSON/mode and
file-plus-parent fsync are promised, not bytes, timestamps, owner, xattrs, or
ACLs.

A known source `.prompt` refuses before suspend. A raced source/target prompt is
preserved and fails loud at the observed authority boundary. After rename and
before relaunch, the helper exclusively creates and durably syncs one mode-0600
target `.prompt` naming the exact old/new roots and telling the same Agent to
continue only remaining stale-reference migration, verify/report, and not move
again or broaden side effects. Success waits for that prompt to be consumed;
the lifecycle supplies durable `prompt_received` and `wake` evidence.

## Scope and recovery boundary

The private log moves at `logs/move-project.log`. The helper offers no Windows,
cross-filesystem, copy, merge, overwrite, address change, registry rewrite,
sibling relaunch, framework/Project CLI/TUI, version, integration, or
communication claim. Follow the parent router's observed-phase recovery table
and complete its target-origin acceptance checklist; helper success alone is not
full acceptance.