Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixed

- Scoped installation completion to native-addressable local Codex tasks and disclosed that older signed-in ChatGPT chat-history rows are outside the current native title API, preventing a zero-local-inventory result from being presented as complete sidebar migration.

## v2.1.6 - 2026-08-03

### Fixed
Expand Down
14 changes: 8 additions & 6 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Open with this complete orientation before running a command:
>
> ThreadBear keeps Codex Desktop task titles useful with a running mark while work is underway and a clear outcome when each response finishes. It uses two native title calls per ordinary turn and two small deterministic hooks.
>
> I'll check this Mac, show you exactly what will change, and answer questions before installing anything. After you consent, I'll install it and update existing titles without taking you away from this ThreadBear task.
> I'll check this Mac, show you exactly what will change, and answer questions before installing anything. After you consent, I'll install it and update native-addressable local Codex task titles without taking you away from this ThreadBear task. Older signed-in ChatGPT chat-history rows are outside Codex's current task-title API and will stay unchanged.

Codex collapses commentary after a turn finishes. The welcome may appear there while checks run, but commentary copies do not satisfy this contract. Every terminal final answer in this first turn must be self-contained. If every check and the dry run succeeds, `phase: final_answer` must include the complete orientation above, the readiness sentence, the full recommendation card, and the consent question. Do not end a successful turn with only the consent question. If any check fails, keep the complete orientation and truthful failure visible in `phase: final_answer`; do not claim readiness, show the recommendation card, or ask for consent.

Expand Down Expand Up @@ -64,7 +64,7 @@ Only after every check and the dry run succeeds, compose one terminal final answ

> ## Recommended setup
>
> - Status icon in each thread's title.
> - Status icon in each native-addressable local Codex task title.
> - Next action added to the thread title → like this.
> - Codex limits title length limited to 60 UTF-16 units, so I'll truncate as needed.
> - Small local footprint: one binary in ~/.local/bin, a skill, and two hooks.
Expand Down Expand Up @@ -104,13 +104,15 @@ Then verify the installed surfaces:

The install result must show `installed:true`, the exact `main_task_id`, and `phase:migration_pending` unless a prior migration state is being preserved. Pending means the background controller has not started; it is never described as running. `ready:true` means `migration_complete`, not merely that artifacts were written. Do not claim the hooks work merely because files were written.

Inventory and migration cover local Codex Desktop and CLI tasks that the native explicit-target title setter can address. They do not enumerate or rename older signed-in ChatGPT chat-history rows that may also appear in the Desktop sidebar. Disclose that boundary before migration and never describe zero local inventory rows as proof that every visible sidebar row changed.

## 4. Migrate without leaving this task

Read `~/.codex/skills/threadbear/SKILL.md` and follow its **Install** and **Migration controller** sections. The installed skill is the canonical operation guide.

Before migration, tell the user:

> ThreadBear will stay selected while one background controller updates existing titles. This usually takes several minutes, and a large or ambiguous history can take longer. `migration_running` means the controller is actively working; I'll report every 25 applied titles or phase change and won't finish this installation turn until it reaches `migration_complete` or `migration_failed`.
> ThreadBear will stay selected while one background controller updates native-addressable local Codex task titles. Older signed-in ChatGPT chat-history rows are outside Codex's current task-title API and will stay unchanged. This usually takes several minutes, and a large or ambiguous local history can take longer. `migration_running` means the controller is actively working; I'll report every 25 applied titles or phase change and won't finish this installation turn until it reaches `migration_complete` or `migration_failed`.

Before any bulk work, use `codex_app__set_thread_title` to set the initiating task to exactly `🧵🐻 ThreadBear 🐻🧵`, use `codex_app__set_thread_pinned` to pin it, and keep this task selected. For an ordinary guided installation, do not use visual inspection, computer control, screenshots, or Codex `/hooks`, and do not ask the user to do so. The candidate self-test, installed `self-test --json`, and read-only ThreadBear inventory are the installation gate; visual hook verification is outside this ordinary installation flow.

Expand All @@ -134,15 +136,15 @@ Only after that command succeeds may the controller archive itself. A stopped co

Keep this ThreadBear task selected and supervise the controller with compact task waits. Report only each 25-title milestone or phase change. When the controller returns, run `status --json` and `inventory --json`. `migration_pending` always means no controller was recorded; status repairs an older running-without-controller state to pending. `migration_running` always names the active controller. Status reconciles a missing controller or a terminal lifecycle event from the current attempt from stale `migration_running` to `migration_failed`; it never infers failure from age, slow progress, or a prior attempt's terminal event. If the controller or this turn is interrupted, begin the next turn with status so the durable phase is truthful.

Do not send a final installation answer while status still says `migration_pending` or `migration_running`. At `migration_pending`, say that migration has not started and nothing is running, then give the exact start action. At `migration_failed`, say plainly that migration stopped and is not still working, give the applied and remaining counts, name the cause, and give one exact resume action. At `migration_complete`, require zero remaining rows before closing.
Do not send a final installation answer while status still says `migration_pending` or `migration_running`. At `migration_pending`, say that migration has not started and nothing is running, then give the exact start action. At `migration_failed`, say plainly that migration stopped and is not still working, give the applied and remaining counts, name the cause, and give one exact resume action. At `migration_complete`, require zero remaining native-addressable local rows before closing and repeat that older signed-in ChatGPT chat-history rows were not part of the migration.

## 5. Close precisely

On complete success, use this shape in natural prose:

> ## ThreadBear is installed
>
> Everything passed: ThreadBear VERSION is installed, its managed guidance and two hooks are healthy, this task is its persistent home, and the migration controller completed with zero remaining titles.
> Everything passed: ThreadBear VERSION is installed, its managed guidance and two hooks are healthy, this task is its persistent home, and the migration controller completed with zero remaining native-addressable local Codex task titles. Older signed-in ChatGPT chat-history rows were outside this migration and may remain unchanged in the sidebar.
>
> From here, you can ask “how are you?”, “what tasks do you see?”, or “uninstall ThreadBear.”

Expand All @@ -165,7 +167,7 @@ The installed binary's help is the authoritative public command list.

Read the installed skill's **Title cleanup** and **Uninstall** sections. Run status and inventory, then ask:

> Want me to uninstall ThreadBear? I'll tidy the ThreadBear icons from your task titles, remove ThreadBear's local files and two hooks, and leave your tasks and other Codex settings alone. When it's done, I'll ask you to restart Codex.
> Want me to uninstall ThreadBear? I'll tidy the ThreadBear icons from native-addressable local Codex task titles, remove ThreadBear's local files and two hooks, and leave your tasks and other Codex settings alone. Older signed-in ChatGPT chat-history rows are outside this cleanup. When it's done, I'll ask you to restart Codex.
>
> Should I go ahead?

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ threadbear uninstall
threadbear version
```

Every command accepts `--json`. `inventory` is read-only and includes every native-addressable unarchived Desktop or CLI task, including projectless tasks, excluding the persisted main and controller tasks. Rollout-only internal records that Codex's native title setter cannot rename are excluded. `status` reports `ready:true` only after `migration_complete`; the installed binary's `help` output is authoritative.
Every command accepts `--json`. `inventory` is read-only and includes every native-addressable unarchived local Codex Desktop or CLI task, including projectless tasks, excluding the persisted main and controller tasks. Rollout-only internal records and older signed-in ChatGPT chat-history rows that Codex's native title setter cannot enumerate or rename are excluded. Those chat-history rows may remain unchanged in the Desktop sidebar even after local migration completes. `status` reports `ready:true` only after `migration_complete`; the installed binary's `help` output is authoritative.

From the persistent ThreadBear task, ask to “strip title icons” at any time. The control task serially removes all leading ThreadBear status marks through the same native setter and exact Pre/Post verification used by ordinary turns. Guided uninstall always completes that cleanup before removing ThreadBear's local state and hooks.

Expand Down
10 changes: 5 additions & 5 deletions assets/skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,26 @@ Show a command before running it. Ask for explicit consent before any lifecycle
## Install

1. Read the current install guide and the candidate's help output. Check macOS, architecture, Codex, HTTPS access, and candidate self-test without changing the machine. Resolve the exact current task ID with supported Codex task tooling.
2. Run the exact dry run with `--control-task-id CURRENT_TASK_ID`. Explain the complete effect: adopting that task as the persistent home, the local binary, one small private state file, one managed AGENTS block, this skill, and two hook entries.
2. Run the exact dry run with `--control-task-id CURRENT_TASK_ID`. Explain the complete effect: adopting that task as the persistent home, the local binary, one small private state file, one managed AGENTS block, this skill, and two hook entries. Explain that migration covers native-addressable local Codex tasks; older signed-in ChatGPT chat-history rows are outside Codex's current task-title API and stay unchanged.
3. Show the recommended setup and ask once for consent. A clear yes to the unchanged complete recommendation is installation consent. Ask again only if the recommendation changed, the answer was ambiguous, or this is a reinstall with a different effect.
4. Run the confirmed install with the same ID and verify `version`, `self-test`, and `inventory`. A fresh result is `migration_pending`: no controller has started and nothing is running yet. On reinstall, omit the flag only when `status --json` already reports the persisted main task; never replace it with the launching task.
5. Before any migration, use `codex_app__set_thread_title` to set the initiating task to exactly `🧵🐻 ThreadBear 🐻🧵`, use `codex_app__set_thread_pinned` to pin it, and keep that task selected.
6. For an ordinary guided installation, never use visual inspection, computer control, screenshots, or Codex `/hooks`, and never ask the user to do so. The candidate self-test, installed `self-test --json`, and read-only ThreadBear inventory are the installation gate. Visual hook verification belongs only to **Debug canaries** when the install result explicitly contains `debug_canaries:true`.
7. Create exactly one background migration controller without opening, selecting, or navigating to it, then immediately record it with `migration --phase migration_running`. On a compatible machine with the candidate already downloaded, dispatch it within 60 seconds of consent; do not insert UI inspection, App Server schema generation, native-catalog comparison, or tool-surface discovery before dispatch. If creation fails, leave `migration_pending` unchanged and report that nothing is running plus the exact retry action.
8. Give the controller the **Migration controller** protocol below. Supervise it from the persistent task with compact task waits, reporting only each 25-title milestone or phase change. Do not end the installation turn while durable status is `migration_pending` or `migration_running`.
9. After the controller returns, run `status --json` and `inventory --json`. Claim success only at `migration_complete` with zero remaining rows. At `migration_failed`, say migration stopped and is not still working, report applied and remaining counts, name the cause, and give one exact resume action using the same controller ID.
9. After the controller returns, run `status --json` and `inventory --json`. Claim success only at `migration_complete` with zero remaining native-addressable local rows, and repeat that older signed-in ChatGPT chat-history rows were not part of the migration. At `migration_failed`, say migration stopped and is not still working, report applied and remaining counts, name the cause, and give one exact resume action using the same controller ID.

For a large existing workspace, say this before migration:

> ThreadBear will stay selected while one background controller updates existing titles. This usually takes several minutes, and a large or ambiguous history can take longer. `migration_running` means the controller is actively working; I'll report every 25 applied titles or phase change and won't finish this installation turn until it reaches `migration_complete` or `migration_failed`.
> ThreadBear will stay selected while one background controller updates native-addressable local Codex task titles. Older signed-in ChatGPT chat-history rows are outside Codex's current task-title API and will stay unchanged. This usually takes several minutes, and a large or ambiguous local history can take longer. `migration_running` means the controller is actively working; I'll report every 25 applied titles or phase change and won't finish this installation turn until it reaches `migration_complete` or `migration_failed`.

Do not claim success from installed files, a native setter return, or partial counts.

## Status and inventory

`status --json` checks the installed binary, managed files, hooks, and state readability. It reports `installed:true` while artifacts are present, but `ready:true` only for `phase:migration_complete`. It does not mutate titles. `migration_pending` means no controller was recorded and returns the exact start action; status also repairs an older running-without-controller state to pending. `migration_running` always names the active controller. If that controller is missing or has a terminal lifecycle event from the current attempt, status atomically records `migration_failed`, explains that the controller stopped, and returns the exact resume action. It never infers failure from age, slow progress, or a prior attempt's terminal event.

`inventory --json` reads every native-addressable, unarchived Desktop or CLI task, including projectless tasks, excluding the persisted main and controller IDs. It excludes rollout-only internal records that Codex's native title setter cannot rename. Treat its deterministic classifications, `status`, `action`, and `applied` evidence as authoritative. Do not infer ThreadBear ownership from an icon or arrow alone.
`inventory --json` reads every native-addressable, unarchived local Codex Desktop or CLI task, including projectless tasks, excluding the persisted main and controller IDs. It excludes rollout-only internal records and older signed-in ChatGPT chat-history rows that Codex's native title setter cannot enumerate or rename. Treat its deterministic classifications, `status`, `action`, and `applied` evidence as authoritative only for that local catalog. Never describe zero inventory rows as proof that every visible sidebar row changed, and do not infer ThreadBear ownership from an icon or arrow alone.

## Migration controller

Expand Down Expand Up @@ -99,7 +99,7 @@ For ordinary on-demand cleanup, do not target the active control task: its requi
## Uninstall

1. Run `help`, `status --json`, and `inventory --json`. If `phase:migration_running`, stop the controller and let it record `migration_failed` before uninstalling.
2. Ask: “Want me to uninstall ThreadBear? I'll tidy the ThreadBear icons from your task titles, remove ThreadBear's local files and two hooks, and leave your tasks and other Codex settings alone. When it's done, I'll ask you to restart Codex. Should I go ahead?” Continue only after a clear yes.
2. Ask: “Want me to uninstall ThreadBear? I'll tidy the ThreadBear icons from native-addressable local Codex task titles, remove ThreadBear's local files and two hooks, and leave your tasks and other Codex settings alone. Older signed-in ChatGPT chat-history rows are outside this cleanup. When it's done, I'll ask you to restart Codex. Should I go ahead?” Continue only after a clear yes.
3. Follow **Title cleanup** for every regular and controller task. Re-read and clean this persisted ThreadBear task last. Any drift, unknown result, or remaining decorated title stops uninstall before artifacts or ownership state are removed.
4. Run the confirmed uninstall. It refuses while migration is running, then removes only ThreadBear's recorded hook entries, managed AGENTS block, installed skill, private state, and binary while preserving unrelated content and hook order.
5. Use the managed uninstall-turn exception: make no terminal title call and append no ThreadBear footer. Ask the user to restart Codex so already-open sessions cannot keep using snapshotted guidance.
Expand Down
4 changes: 3 additions & 1 deletion cmd/threadbear/site_contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestPublishedInstallGuideMatchesCurrentCLI(t *testing.T) {
for _, required := range []string{
"## Hi. Let's install ThreadBear.",
"## Recommended setup",
"Status icon in each thread's title.",
"Status icon in each native-addressable local Codex task title.",
"Next action added to the thread title → like this.",
"Codex limits title length limited to 60 UTF-16 units, so I'll truncate as needed.",
"Small local footprint: one binary in ~/.local/bin, a skill, and two hooks.",
Expand All @@ -61,6 +61,8 @@ func TestPublishedInstallGuideMatchesCurrentCLI(t *testing.T) {
"codex_app__set_thread_title",
"codex_app__set_thread_pinned",
"do not use visual inspection, computer control, screenshots, or Codex `/hooks`",
"Older signed-in ChatGPT chat-history rows are outside Codex's current task-title API and will stay unchanged.",
"never describe zero local inventory rows as proof that every visible sidebar row changed",
"dispatch it within 60 seconds of consent",
"first title mutation issued within 60 seconds of controller start and within 15 seconds of the inventory result",
"fixed `codex_app__create_thread` surface with Luna medium",
Expand Down
Loading
Loading