Skip to content

feat: preserve workspace continuity - #36

Merged
beefiker merged 5 commits into
mainfrom
codex/workspace-safety-continuity
Jul 25, 2026
Merged

feat: preserve workspace continuity#36
beefiker merged 5 commits into
mainfrom
codex/workspace-safety-continuity

Conversation

@beefiker

Copy link
Copy Markdown
Owner

What changed

  • Bind new loop plans to one canonical checkout and reject copied or mismatched state across CLI and hook mutation paths.
  • Add explicit legacy binding with confined-path validation.
  • Meter injected additional context with character, UTF-8 byte, and estimated-token counts while keeping research targets advisory-only.
  • Make structured steering replay-safe with bounded idempotency receipts.
  • Add a bounded compaction recovery capsule and six semantic continuity regressions.
  • Bump package and plugin manifests to 0.13.0.

Why

Repo-local state could previously be resumed from the wrong checkout, repeated hook delivery could apply steering twice, and compacted sessions lacked a small durable semantic recovery contract. Research guidance also treated saturation as a goal instead of making cost visible without blocking the loop.

Impact

New plans use schema version 2 and include an anonymous checkout identity. Version 1 plans remain readable but require the explicit loop bind confirmation before mutation. Context targets remain guidance only: they never block, delay, rewrite, or request approval.

Checks

  • npm test: 697 tests passed, 0 failed
  • node src/cli.js doctor --json: ok
  • npm pack --dry-run: 0.13.0 package created; all five new runtime modules included
  • git diff --check: clean

@beefiker
beefiker marked this pull request as ready for review July 24, 2026 07:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e41a4da167

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/hooks.js
Comment on lines +159 to 161
payload = { ...payload, cwd: resolveWorkspaceRoot(payload.cwd) };
if (!envOn(process.env, "SUPERLOOPY_STOP_HOOK")) return "";
return await decideContinuation(payload, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate Stop continuation on repository binding

When SUPERLOOPY_STOP_HOOK=on and a copied or mismatched plan exists in the current workspace, statusLoop now returns {ok:false, binding} instead of throwing, but this path still passes that status into decideContinuation, which ignores ok/binding, writes loop-control.json/ledger entries, and emits commands to resume the copied state. This bypasses the new binding refusal specifically in the Stop hook path, so add a non-resumable binding check before continuation or teach decideContinuation to stop without mutation.

Useful? React with 👍 / 👎.

Comment thread src/workspace-identity.js Outdated
Comment on lines +9 to +10
const git = findNearestGitWorktree(origin);
if (git !== null) return git.root;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy subdirectory loop discovery

Because this returns the Git worktree root before looking for an existing .superloopy directory, any v1 plan created by the previous CLI from a package/subdirectory inside a Git repo becomes undiscoverable after upgrade: superloopy loop status or loop bind from that same directory is redirected to the repo root and fails with “No Superloopy plan found” instead of offering the legacy bind flow. Consider honoring an existing state directory at or above origin for legacy discovery before canonicalizing to the Git root.

Useful? React with 👍 / 👎.

Comment thread src/cli.js Outdated

async function dispatchLoop(cwd, subcommand, argv) {
if (!["begin", "create", "status", "bind"].includes(subcommand)) {
const scope = scopeFromSessionId(readFlag(argv, "--session-id"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore --session-id after the command delimiter

For loop prove/loop capture, a validation command can legitimately contain its own --session-id after --, but this new preflight scans the entire argv before the subcommand parser splits options from command args. In that case it tries to load a Superloopy scoped plan for the validation command's flag and fails or blocks the wrong plan, even though the actual prove/capture operation would use the unscoped plan.

Useful? React with 👍 / 👎.

Comment thread src/repository-binding.js Outdated
}

function bindCommand(sessionId) {
const session = typeof sessionId === "string" && sessionId.length > 0 ? ` --session-id ${sessionId}` : "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Quote legacy session IDs in suggested bind command

For an untrusted legacy plan, sessionId is read directly from goals.json and interpolated into the copy-pasteable binding.next command. If a repo ships a v1 plan with a value such as abc; touch /tmp/pwn, loop status suggests a command that will execute the injected shell fragment, so the session id should be normalized/rejected or shell-quoted before being placed in guidance.

Useful? React with 👍 / 👎.

Comment thread src/cli.js
return 0;
}
const result = await dispatchLoop(cwd, subcommand, argv);
const result = await dispatchLoop(resolveWorkspaceRoot(cwd), subcommand, argv);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize PreToolUse cwd before completion checks

With this canonicalization, superloopy loop begin from a package subdirectory now creates the plan at the Git root, but runPreToolUseHook still looks for goals.json under the host-provided cwd. In a Codex session whose cwd remains packages/app, update_goal status=complete sees no plan and is allowed while the root Superloopy plan is incomplete, so the native completion guard is bypassed; normalize that hook or pass the resolved root too.

Useful? React with 👍 / 👎.

Comment thread src/compaction-recovery.js Outdated
"Only the deterministic Superloopy gate authorizes completion."
].join("\n");
if (mandatory.length <= maxChars) return mandatory;
return `${mandatory.slice(0, Math.max(0, maxChars - 32)).trimEnd()}\n[recovery capsule truncated]`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve recovery tail fields when truncating

This prefix-only truncation lets any long active goal title or unresolved list cut off later recovery fields, including Next action and the deterministic-gate warning, exactly when compacted sessions need them to resume safely. For example, a long goal title under a 700-character cap leaves the capsule without the resume command, so reserve or append the mandatory tail fields instead of slicing the whole string from the front.

Useful? React with 👍 / 👎.

@beefiker
beefiker merged commit e4ba130 into main Jul 25, 2026
6 checks passed
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.

1 participant