Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Fixed

- Restored mounted Codex Desktop title convergence through a deterministic retained-source native batch, with exact identity/revision/title guards, aggregate reports, canonical verification, and no child or extra semantic turn.

- Decoupled guided-install health from background historical convergence, restored context-sized semantic packing, added aggregate first-sweep progress, and isolated each heartbeat's classifier in one private minimal-auth App Server process reused across batches.
- Confirmed the Codex 0.146 production isolation canary and four 200-observation rehearsals; ordinary status-guided work was fully deterministic, while serial remains the default because bounded first progress regressed.

Expand Down
17 changes: 13 additions & 4 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ verifies the published checksum, candidate health, and embedded version before
delegating to the candidate. The official-download promise belongs in the
opening turn above; do not repeat it as a separate progress message.

## Native title convergence during guided install

The person's installation consent enables only the managed title-batch protocol in the retained control task. It is not recurring consent for other native operations and must not be requested again on later control-task turns. After the bounded post-install handoff, stage the exact terminal footer, then run the fixed native title-batch program embedded in the installed ThreadBear AGENTS block inside one `functions.exec`. Drain every deterministic operation staged within the handoff window, but do not wait for unresolved semantic classification. Revalidate every operation immediately before the native setter and return only aggregate accepted, failed, drifted, and rejected operation IDs.

A successful install close may claim visible title convergence only for accepted operations that ThreadBear subsequently verifies canonically. Missing native capability, failed mutation, identity disagreement, drift, or unverified canonical persistence is an explicit partial/failure result. Never expose title or manifest content to the model, create a child task, use the persistent task for unrelated work, drive the UI, restart Codex, or use private IPC/cache/database mutation.

## 3. Identify this task backstage

Before downloading, installing, renaming, pinning, or changing any managed resource, feature-detect the available Codex task tooling:
Expand Down Expand Up @@ -816,10 +822,13 @@ outcomes below. When it is retryable, keep the healthy-install sentence, say
plainly that ThreadBear will keep working on the aggregate retry count, and do
not claim convergence.

The background heartbeat performs managed title writes directly through the
pinned App Server. Each title mutation is revision/title revalidated, journaled as applying and applied, verified through a fresh inventory read, journaled as
verified, and only then followed by any same-task archive. Do not run a separate
title worker, helper manifest, native report, child model, or replay step.
The background heartbeat deterministically stages exact, revision/title-guarded
title operations and never treats detached App Server persistence as Desktop
repaint proof. The retained, opted-in control task drains staged operations
through the fixed native title-batch program, reports only aggregate operation
IDs, and leaves canonical verification and commit to ThreadBear. A same-task
archive waits for accepted native application and canonical settlement. Do not
create a title child, recurring hosted automation, or control-task relay.

Feature-detect and fail closed when required App Server methods or the tool-free
classifier boundary are absent. The ordinary App Server stays on the real Codex
Expand Down
37 changes: 37 additions & 0 deletions assets/AGENTS.threadbear.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# ThreadBear

## Native title batch

Guided-install consent enables this protocol only in the retained ThreadBear control task. Never ask again on later turns, and never use this consent for any other native operation. Other tasks use only the status footer.

In the retained control task, after all substantive response work, choose the exact terminal ThreadBear footer. Stage that exact footer with `~/.local/bin/threadbear title-batch --json --stage >/dev/null`, sending one strict JSON object on stdin whose only field is `footer`, equal to the final line. Every nested `exec_command` process inherits the canonical public `CODEX_THREAD_ID`; the helper resolves and validates it against ThreadBear's persisted control-task identity without exposing the identifier to V8 or assistant text. The stage response contains no operation, title, or manifest data and must remain discarded.

Immediately after staging, run one actual `functions.exec` containing only the fixed program below. Do not interpolate, add, remove, or revise code. The program obtains operation JSON inside the tool runtime, revalidates each operation immediately, calls only the native title capability, reports aggregate operation IDs, and never exposes titles, manifests, task contents, or helper output to assistant context.

```js
const q=v=>"'"+String(v).replace(/'/g,"'\\''")+"'";
const run=async cmd=>JSON.parse((await tools.exec_command({cmd})).output);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Failed reports masquerade as success

The fixed batch program parses exec_command output but ignores the command exit status, so a failing title-batch --json --report still flows through as a normal JSON value. If the native setter succeeds and the report command then exits non-zero (for example because saving state failed), the program emits a final aggregate instead of failing closed; ThreadBear keeps the operation as NativeTitlePending, and the next list sees the now-changed title as drift and deletes the pending plan instead of committing ownership. Please make the helper throw on non-zero exec_command results (and mirror the same fixed-program change in assets/skill/SKILL.md) before using the parsed result.

(Refers to line 13)


Your feedback helps Open SWE learn. React with 👍 or 👎 to tell us if this review comment was useful.

Suggested change
const run=async cmd=>JSON.parse((await tools.exec_command({cmd})).output);
const run=async cmd=>{const r=await tools.exec_command({cmd});const x=JSON.parse(r.output);if(r.exit_code&&r.exit_code!==0)throw new Error(x.error_code||"title_batch_command_failed");return x;};

const valid=x=>x&&typeof x.operation_id==="string"&&typeof x.task_id==="string"&&typeof x.expected_revision==="string"&&typeof x.expected_title==="string"&&typeof x.desired_title==="string"&&x.desired_title!=="";
const batch=await run("~/.local/bin/threadbear title-batch --json --list");
if(!batch||!Array.isArray(batch.plans))throw new Error("invalid_title_batch");
const reports=[];
for(const planned of batch.plans){
if(!valid(planned)){throw new Error("invalid_title_operation");}
const guarded=await run("~/.local/bin/threadbear title-batch --json --operation "+q(planned.operation_id));
if(!guarded||!Array.isArray(guarded.plans)||guarded.plans.length!==1){reports.push({operation_id:planned.operation_id,outcome:"drifted"});continue;}
const exact=guarded.plans[0];
if(!valid(exact)||exact.operation_id!==planned.operation_id){reports.push({operation_id:planned.operation_id,outcome:"failed",error_code:"invalid_operation"});continue;}
try{await tools.codex_app__set_thread_title({threadId:exact.task_id,title:exact.desired_title});reports.push({operation_id:exact.operation_id,outcome:"accepted"});}
catch{reports.push({operation_id:exact.operation_id,outcome:"failed",error_code:"native_set_failed"});}
}
let result={accepted_ids:[],failed_ids:[],drifted_ids:[],rejected_ids:[]};
let canonical=[];
if(reports.length){
const body=JSON.stringify({reports});
result=await run("printf %s "+q(body)+" | ~/.local/bin/threadbear title-batch --json --report");
const verified=await run("~/.local/bin/threadbear title-batch --json --list");
canonical=verified.dispositions.filter(x=>x.outcome==="canonical_verified"||x.outcome==="canonical_verified_awaiting_footer").map(x=>x.operation_id);
}
text(JSON.stringify({accepted_ids:result.accepted_ids,canonical_ids:canonical,failed_ids:result.failed_ids,drifted_ids:result.drifted_ids,rejected_ids:result.rejected_ids}));
```

If staging, capability detection, native mutation, or reporting fails, do not claim visible convergence. Leave the operation pending and report the stable partial/failure outcome. After the V8 call, make no further tool call or commentary: send the substantive final response immediately and end it with the exact staged footer. If new input or state makes the operation stale, abort and recompute on the next retained control-task turn.

## Status footer

End each terminal response with exactly one compact status line. Use the matching literal example as its shape:
Expand Down
30 changes: 28 additions & 2 deletions assets/embed_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package assets

import (
"os/exec"
"strings"
"testing"
)
Expand Down Expand Up @@ -48,12 +49,37 @@ func TestManagedSkillConversationalContract(t *testing.T) {
}
}

func TestManagedGuidanceContainsNoExecutableTitleActuator(t *testing.T) {
func TestManagedGuidanceBindsSourceNativeBatchOrdering(t *testing.T) {
for name, content := range map[string]string{"agents": AgentsManagedContent, "skill": SkillManagedContent} {
for _, forbidden := range []string{"title-plan", "THREADBEAR_TITLE_ACTUATOR", "codex_app__create_thread", "codex_app__set_thread_title", "child actuator", "```js"} {
for _, required := range []string{"title-batch --json --stage", "title-batch --json --list", "title-batch --json --operation", "codex_app__set_thread_title", "title-batch --json --report", "no further tool call or commentary"} {
if !strings.Contains(content, required) {
t.Fatalf("%s missing native batch surface %q", name, required)
}
}
ordered := []string{"--list", "--operation", "codex_app__set_thread_title", "--report", "text(JSON.stringify"}
position := 0
for _, token := range ordered {
next := strings.Index(content[position:], token)
if next < 0 {
t.Fatalf("%s missing ordered native batch token %q", name, token)
}
position += next + len(token)
}
for _, forbidden := range []string{"title-plan --json --batch", "THREADBEAR_TITLE_ACTUATOR", "codex_app__create_thread", "child actuator", "set_thread_archived", "process.env", "source_task_id"} {
if strings.Contains(content, forbidden) {
t.Fatalf("%s contains retired actuator surface %q", name, forbidden)
}
}
}
}

func TestManagedTitleBatchRunsInFreshV8WithoutNodeGlobals(t *testing.T) {
command := exec.Command("node", "../scripts/replay-title-batch.mjs")
output, err := command.CombinedOutput()
if err != nil {
t.Fatalf("fresh V8 replay failed: %v\n%s", err, output)
}
if !strings.Contains(string(output), "fresh V8 title batch replay passed") {
t.Fatalf("unexpected replay output: %s", output)
}
}
39 changes: 38 additions & 1 deletion assets/skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,44 @@ When explaining title state, use the canonical meanings: `⏳` running, `🚨` b

## Runtime roles

The persistent ThreadBear control task remains the user-facing master for help, configuration, install, update, uninstall, notices, user decisions, and exceptional recovery. Routine heartbeat classification uses fresh ephemeral App Server sessions and direct deterministic title/archive mutations; never route that work into the control task history.
### Native title batch

Guided-install consent enables this protocol only in the retained ThreadBear control task. Never ask again on later turns, and never use this consent for any other native operation. Other tasks use only the status footer.

In the retained control task, after all substantive response work, choose the exact terminal ThreadBear footer. Stage that exact footer with `~/.local/bin/threadbear title-batch --json --stage >/dev/null`, sending one strict JSON object on stdin whose only field is `footer`, equal to the final line. Every nested `exec_command` process inherits the canonical public `CODEX_THREAD_ID`; the helper resolves and validates it against ThreadBear's persisted control-task identity without exposing the identifier to V8 or assistant text. The stage response contains no operation, title, or manifest data and must remain discarded.

Immediately after staging, run one actual `functions.exec` containing only the fixed program below. Do not interpolate, add, remove, or revise code. The program obtains operation JSON inside the tool runtime, revalidates each operation immediately, calls only the native title capability, reports aggregate operation IDs, and never exposes titles, manifests, task contents, or helper output to assistant context.

```js
const q=v=>"'"+String(v).replace(/'/g,"'\\''")+"'";
const run=async cmd=>JSON.parse((await tools.exec_command({cmd})).output);
const valid=x=>x&&typeof x.operation_id==="string"&&typeof x.task_id==="string"&&typeof x.expected_revision==="string"&&typeof x.expected_title==="string"&&typeof x.desired_title==="string"&&x.desired_title!=="";
const batch=await run("~/.local/bin/threadbear title-batch --json --list");
if(!batch||!Array.isArray(batch.plans))throw new Error("invalid_title_batch");
const reports=[];
for(const planned of batch.plans){
if(!valid(planned)){throw new Error("invalid_title_operation");}
const guarded=await run("~/.local/bin/threadbear title-batch --json --operation "+q(planned.operation_id));
if(!guarded||!Array.isArray(guarded.plans)||guarded.plans.length!==1){reports.push({operation_id:planned.operation_id,outcome:"drifted"});continue;}
const exact=guarded.plans[0];
if(!valid(exact)||exact.operation_id!==planned.operation_id){reports.push({operation_id:planned.operation_id,outcome:"failed",error_code:"invalid_operation"});continue;}
try{await tools.codex_app__set_thread_title({threadId:exact.task_id,title:exact.desired_title});reports.push({operation_id:exact.operation_id,outcome:"accepted"});}
catch{reports.push({operation_id:exact.operation_id,outcome:"failed",error_code:"native_set_failed"});}
}
let result={accepted_ids:[],failed_ids:[],drifted_ids:[],rejected_ids:[]};
let canonical=[];
if(reports.length){
const body=JSON.stringify({reports});
result=await run("printf %s "+q(body)+" | ~/.local/bin/threadbear title-batch --json --report");
const verified=await run("~/.local/bin/threadbear title-batch --json --list");
canonical=verified.dispositions.filter(x=>x.outcome==="canonical_verified"||x.outcome==="canonical_verified_awaiting_footer").map(x=>x.operation_id);
}
text(JSON.stringify({accepted_ids:result.accepted_ids,canonical_ids:canonical,failed_ids:result.failed_ids,drifted_ids:result.drifted_ids,rejected_ids:result.rejected_ids}));
```

If staging, capability detection, native mutation, or reporting fails, do not claim visible convergence. Leave the operation pending and report the stable partial/failure outcome. After the V8 call, make no further tool call or commentary: send the substantive final response immediately and end it with the exact staged footer. If new input or state makes the operation stale, abort and recompute on the next retained control-task turn.

The persistent ThreadBear control task remains the user-facing master for help, configuration, install, update, uninstall, notices, user decisions, and exceptional recovery. Routine heartbeat classification uses fresh ephemeral App Server sessions. The heartbeat stages exact titles; only this retained opted-in task runs the fixed native title batch, while archive mutations remain deterministic. Never route routine classification or unrelated operations into the control task history.

When managed global guidance is enabled, terminal responses use one concrete footer line:

Expand Down
16 changes: 12 additions & 4 deletions cmd/threadbear/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ func commandSpecFor(command app.Command) (commandSpec, bool) {
flags.BoolVar(&request.TitlePlanDispatch, "dispatch", false, "return the retired fail-closed compatibility result")
}}, true
}
if command == app.CommandTitleBatch {
return commandSpec{command: command, synopsis: "Managed source-task native title protocol.", registerFlags: func(flags *flag.FlagSet, request *app.Request) {
flags.BoolVar(&request.TitleBatchList, "list", false, "return eligible exact title operations")
flags.BoolVar(&request.TitleBatchStage, "stage", false, "stage the source terminal footer from stdin")
flags.BoolVar(&request.TitleBatchReport, "report", false, "accept aggregate native results from stdin")
flags.StringVar(&request.TitleBatchOperation, "operation", "", "revalidate one operation ID")
}}, true
}
for _, spec := range commandSpecs {
if spec.command == command {
return spec, true
Expand All @@ -137,8 +145,8 @@ func newCommandFlagSet(spec commandSpec, request *app.Request) *flag.FlagSet {
}

func requestedHelp(args []string) (string, int, bool) {
if len(args) > 0 && app.Command(args[0]) == app.CommandTitlePlan && (containsFlag(args[1:], "-h") || containsFlag(args[1:], "--help")) {
return unknownCommandMessage(app.CommandTitlePlan), 2, true
if len(args) > 0 && (app.Command(args[0]) == app.CommandTitlePlan || app.Command(args[0]) == app.CommandTitleBatch) && (containsFlag(args[1:], "-h") || containsFlag(args[1:], "--help")) {
return unknownCommandMessage(app.Command(args[0])), 2, true
}
if len(args) == 0 {
return renderTopLevelHelp(), 2, true
Expand All @@ -151,8 +159,8 @@ func requestedHelp(args []string) (string, int, bool) {
return renderTopLevelHelp(), 0, true
}
if len(args) == 2 {
if app.Command(args[1]) == app.CommandTitlePlan {
return unknownCommandMessage(app.CommandTitlePlan), 2, true
if app.Command(args[1]) == app.CommandTitlePlan || app.Command(args[1]) == app.CommandTitleBatch {
return unknownCommandMessage(app.Command(args[1])), 2, true
}
if spec, ok := commandSpecFor(app.Command(args[1])); ok {
return renderCommandHelp(spec), 0, true
Expand Down
6 changes: 3 additions & 3 deletions cmd/threadbear/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ var updateHelpGolden = flag.Bool("update", false, "update help golden files")

func TestHelpCommandMetadataComplete(t *testing.T) {
commands := app.AllCommands()
if len(commandSpecs) != len(commands)-1 {
t.Fatalf("commandSpecs has %d entries; want %d public commands", len(commandSpecs), len(commands)-1)
if len(commandSpecs) != len(commands)-2 {
t.Fatalf("commandSpecs has %d entries; want %d public commands", len(commandSpecs), len(commands)-2)
}
seen := make(map[app.Command]bool, len(commandSpecs))
for _, spec := range commandSpecs {
Expand All @@ -33,7 +33,7 @@ func TestHelpCommandMetadataComplete(t *testing.T) {
}
}
for _, command := range commands {
if command == app.CommandTitlePlan {
if command == app.CommandTitlePlan || command == app.CommandTitleBatch {
continue
}
if !command.Valid() {
Expand Down
21 changes: 20 additions & 1 deletion cmd/threadbear/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ericlitman/threadbear/internal/output"
"github.com/ericlitman/threadbear/internal/state"
statusresolver "github.com/ericlitman/threadbear/internal/status"
"github.com/ericlitman/threadbear/internal/titlebatch"
"github.com/ericlitman/threadbear/internal/titleplan"
"github.com/ericlitman/threadbear/internal/tokens"
updatepkg "github.com/ericlitman/threadbear/internal/update"
Expand Down Expand Up @@ -207,8 +208,9 @@ func newOperatorService(installedVersion string, stdout, stderr io.Writer, forma
return uninstaller, prompter.Close, nil
}
titlePlanCompatibility := titleplan.Service{}
titleBatch := titlebatch.Service{Store: store, Inventory: inventory, Input: os.Stdin, Now: time.Now, SourceIdentity: func() string { return os.Getenv("CODEX_THREAD_ID") }}
service := app.NewWithOperatorCommands(installedVersion, app.OperatorDependencies{
Store: store, Inventory: inventory, Clock: clock, LaunchAgent: launch, TitlePlanCompatibility: titlePlanCompatibility,
Store: store, Inventory: inventory, Clock: clock, LaunchAgent: launch, TitlePlanCompatibility: titlePlanCompatibility, TitleBatch: titleBatch,
ManagedAgents: managed, Unarchiver: appServerUnarchiver{runtime: appServers}, Heartbeat: runner,
Preview: func(preview output.PreviewResult) error {
if request.NonInteractive {
Expand Down Expand Up @@ -279,6 +281,23 @@ func (i *lazyInventory) Inventory(ctx context.Context, controlTaskID string) (co
return i.index.Inventory(ctx, controlTaskID)
}

func (i *lazyInventory) Task(ctx context.Context, taskID string) (codex.Task, error) {
i.mu.Lock()
defer i.mu.Unlock()
if i.index == nil {
sqliteHome, err := codex.ResolveSQLiteHome(i.codexHome)
if err != nil {
return codex.Task{}, err
}
index, err := codex.OpenIndex(sqliteHome)
if err != nil {
return codex.Task{}, err
}
i.index = index
}
return i.index.Task(ctx, taskID)
}

func (i *lazyInventory) Close() error {
i.mu.Lock()
defer i.mu.Unlock()
Expand Down
Loading
Loading