Use a stable lane for real work and a separate worktree lane for development.
This keeps local source edits, dependencies, builds, and private state from
changing underneath another chat or the installed ghostget command.
Keep the control checkout on main and use it to create and retire worktrees.
Keep the normally installed ghostget command and its normal state for trusted
day-to-day work, especially provider mutations. Do not globally link a changing
development checkout over that command.
Give every development chat a unique task name. Its worktree gets a
codex/<task> branch, its own frozen Bun install, and private state and media
roots. Chats that may edit source must not share a task worktree. They may run
in parallel when each uses its own task.
The helpers require Bun 1.3.14. Git worktrees cannot inherit uncommitted files,
so first commit the local-development setup and any source every new task needs.
The helper uses the control checkout's current HEAD by default; fetch and
advance that checkout only when you explicitly want a newer base:
git fetch --prune origin # optional: refresh the local base first
./scripts/local-dev/new-worktree codex-20260814-exampleThe helper does not fetch or merge implicitly. GHOSTGET_WORKTREE_BASE may select
another locally known commit or ref. By default it creates the worktree in a
sibling directory named <control-checkout>-worktrees. Set an absolute
GHOSTGET_WORKTREE_ROOT to put worktrees elsewhere:
GHOSTGET_WORKTREE_ROOT=/absolute/path/ghostget-worktrees \
./scripts/local-dev/new-worktree codex-20260814-exampleTask names contain only lowercase letters, digits, and internal hyphens and are
at most 48 characters. The helper refuses an existing target or branch and
runs bun install --frozen-lockfile only after Git creates the worktree. If the
install fails, it leaves the worktree in place for inspection or an explicit
cleanup.
Invoke the task's source CLI through the control checkout's runner:
./scripts/local-dev/run-ghostget codex-20260814-example doctor --jsonThe runner starts a new Bun process against that worktree's source on every
call and disables Bun's automatic package installation. A tiny tracked launcher
binds Bun to the worktree's configuration before restoring the caller's working
directory and loading src/cli.ts. No build or global relink is needed: a
completed edit is visible to the next invocation. An already-running invocation
keeps the code it loaded, so source edits do not hot-swap its process. Let
long-running commands finish before changing behavior they depend on. The
runner also disables caller .env loading and verifies the exact registered
codex/<task> worktree before executing it. Ambient BUN_CONFIG_FILE,
BUN_OPTIONS, and NODE_OPTIONS runtime hooks are discarded as part of that
boundary.
The runner briefly enters the Ghostget worktree to bind Bun configuration; the tracked launcher restores the caller directory before the CLI loads. Relative CLI inputs and outputs therefore continue to resolve from the caller's directory:
cd /absolute/path/to/a/caller-project
/absolute/path/to/ghostget/scripts/local-dev/run-ghostget \
codex-20260814-example doctor --jsonEach task uses these private roots by default:
$HOME/.local/share/ghostget-dev/<task>/state
$HOME/.local/share/ghostget-dev/<task>/media
Move that development root with an absolute GHOSTGET_DEV_HOME. Use the same
overrides for every invocation of a task:
GHOSTGET_WORKTREE_ROOT=/absolute/path/ghostget-worktrees \
GHOSTGET_DEV_HOME=/absolute/private/path/ghostget-dev \
/absolute/path/to/ghostget/scripts/local-dev/run-ghostget \
codex-20260814-example doctor --jsonNever point a development task at the stable Ghostget state or media roots, and
never symlink state, media, auth, browser profiles, node_modules, or dist
between tasks.
State isolation also isolates confirmation, dispatch, and at-most-once evidence. Separate task ledgers cannot coordinate with each other or with the stable installation. Do not submit the same real R2 or R3 provider mutation from multiple lanes. Route real mutations through one stable Ghostget installation and its normal state. Use development roots for reads, local fixtures, and deliberately isolated test accounts or targets.
The repository's skills/ghostget/ directory is the skill source; an agent does
not automatically read edits from that directory. Keep the normally installed
skill pinned to the same stable release as plain ghostget; CLI worktree
iteration does not require replacing it.
Skill replacement is a serialized maintenance boundary, not hot reload. When
no active task may still discover or use the installed Ghostget skill, validate
the revision, stage a complete copy on the same filesystem but outside Codex's
skill-discovery directory, and publish that complete tree with rollback. Then
refresh Codex and start a new task. Do not run rsync --delete directly into
the live installed directory, and do not switch one user-level skill between
parallel worktrees.
For example, after quiescing Ghostget tasks:
(
set -eu
CODEX_ROOT="${CODEX_HOME:-$HOME/.codex}"
CODEX_SKILLS_HOME="$CODEX_ROOT/skills"
SKILL_SWAP_ROOT="$CODEX_ROOT/local-skill-snapshots/ghostget"
mkdir -p "$SKILL_SWAP_ROOT"
SKILL_SWAP="$(mktemp -d "$SKILL_SWAP_ROOT/swap.XXXXXX")"
SKILL_STAGE="$SKILL_SWAP/stage"
SKILL_BACKUP="$SKILL_SWAP/previous"
cp -R ./skills/ghostget "$SKILL_STAGE"
mv "$CODEX_SKILLS_HOME/ghostget" "$SKILL_BACKUP"
if ! mv "$SKILL_STAGE" "$CODEX_SKILLS_HOME/ghostget"; then
mv "$SKILL_BACKUP" "$CODEX_SKILLS_HOME/ghostget"
exit 1
fi
)The preserved local-skill-snapshots/ghostget/swap.*/previous directory is an
explicit rollback candidate outside live skill discovery; inspect and retire it
manually only after the new skill is accepted. The quiesced replacement has a
brief gap between moving the prior directory aside and publishing the complete
staged tree, and the snippet restores the prior directory if publication fails.
Adjust the destination if the agent host uses a different skills directory.
Existing tasks may have already loaded instructions, so the safe guarantee is
only that new tasks started after the refresh see the new complete snapshot.
When testing local code, tell the new task the absolute run-ghostget command and
task name so it does not fall back to the stable ghostget executable.
Before source delivery, run relevant focused local checks inside the task
worktree and obtain independent impact and diff review. Complete Required
PR CI is the normal final source integration gate for executable and
documentation changes. It runs the complete Linux aggregate plus a selected
macOS suite; preserve its executable phase-composition and disjoint source
coverage contracts:
cd /absolute/path/ghostget-worktrees/codex-20260814-example
bun test scripts/ci-pr-gate.test.tsRecord the repository, reviewed workflow, successful run and attempt, complete required job union, actual checked commit and tree, PR head, and current base. Revalidate immediately before conditional merge; head or base movement requires matching current-candidate CI. An older candidate's receipt never qualifies the new integration.
The selected macOS inventory in scripts/ci-macos-check.ts does not cover every
native behavior or establish complete macOS package or installation equivalence.
For impacted native behavior outside that suite, run relevant focused macOS
checks or add and pass an independently reviewed CI extension. Keep every
explicit local, native, coupled-sequence, live, installation, package-release,
provider-control, and production acceptance requirement, including opt-in
qualifications when required. Hosted runners do not qualify the user's
Keychain, signed-in browser, profiles, devices, installation, or production state.
Keep bun run check available as the complete local aggregate and use it when
coverage or equivalence is uncertain, a coupled sequence must run together, or a
known failure needs the complete local reproduction. Diagnose observed failures
and retain their relevant reproduction
and repair checks. Independently review workflow, discovery, command, deadline,
and platform changes against the prior required coverage; edited coverage
assertions alone cannot certify a weakened workflow.
CI bounds each Apalache check to 25 minutes, each Quint shard step to 40 minutes,
and its job to 45 minutes. This preserves time for the remaining model checks,
mutants, replay, setup, and diagnostic upload. The September 27, 2026
passing source run
took 18 minutes 23 seconds for fenceSafety and 29 minutes 38 seconds for its
whole shard; three subsequent merged-source runs exhausted the former
20-minute checker ceiling, the latest during final-state checks. The larger
ceilings retain every model, depth, seed, invariant, and mutant. A timeout remains a failed gate;
release admission still requires success for the current source candidate.
Before cleanup, make sure no chat or shell is using the worktree and commit or otherwise preserve wanted changes. Then remove the exact worktree through Git, delete its branch only after Git accepts the removal, and prune stale metadata:
git -C /absolute/path/to/ghostget worktree remove \
/absolute/path/ghostget-worktrees/codex-20260814-example
git -C /absolute/path/to/ghostget branch -d codex/codex-20260814-example
git -C /absolute/path/to/ghostget worktree pruneReview the exact <GHOSTGET_DEV_HOME>/<task> directory separately before
deleting it. It can contain private auth, provider, plugin, and media state. Do
not use a broad glob or remove the worktree directory directly.
The read runtime ownership guide describes the R1 Effect
programs, native cleanup proof and the bun run check:effect architecture gate.
The confirmed-write guide explains synchronous
durable callbacks, reconciliation and native cleanup for R2/R3 confirmation.