Skip to content

TUI "edit task" silently resets session ID, pin, permission mode, tags, and other persisted fields #560

@kylecarbonneau

Description

@kylecarbonneau

Summary

Editing a task through the TUI (e on a selected task) and saving resets several
persisted columns to their zero value, even when the user only changed the title or body.
The edit form models a subset of fields; everything it doesn't model — and that the
save-reconciliation doesn't explicitly re-apply — is overwritten with empty/zero on
UpdateTask.

Affected fields

On every TUI edit-save, these are silently reset:

  • claude_session_id""breaks conversation resume for the task
  • daemon_session"" — loses the tmux daemon-session association
  • port0
  • pr_info_json"" — cached PR/CI state dropped (PR URL/number survive)
  • permission_mode"" and dangerous_modefalsesilently reverts the task
    to prompt mode
    , even if it was set to auto/dangerous
  • pinnedfalsesilently unpins a pinned task
  • tags"" — tags lost
  • source_branch""

Fields the form does preserve (so they're safe): title, body, status, type, project,
executor, effort level, PR URL/number, worktree path, branch name, timestamps.

Root cause

internal/ui/form.go::NewEditFormModel reads only Title, Body, Type, Project, Executor,
EffortLevel, PRURL, PRNumber from the task. On save,
internal/ui/app.go::updateEditTaskForm calls FormModel.GetDBTask() (which rebuilds a
fresh Task from just those form fields) and then re-applies only a hand-picked subset
(ID, Status, WorktreePath, BranchName, CreatedAt, StartedAt, CompletedAt). It then calls
db.UpdateTask, whose UPDATE tasks SET ... writes a fixed column set — so any column it
writes that was neither in the form nor re-applied gets the zero value.

The same shape affects the project-move paths
(internal/ui/app.go::moveTaskToProject, cmd/task/main.go::moveTask), which rebuild the
task and only copy a subset of fields.

Reproduction

  1. Create a task; pin it (p) and set it to auto/dangerous permission mode.
  2. Let it run so it has a claude_session_id.
  3. Select it, press e, change only the title, save.
  4. Observe: the task is unpinned, permission mode is back to prompt, and resuming the
    conversation no longer finds the prior session.

Suggested fix

Two reasonable directions:

  • Targeted: in updateEditTaskForm's reconciliation block, carry through every
    persisted field the edit form doesn't expose (mirror how Status/WorktreePath are
    preserved) — i.e. start from the original task and overlay only the form-edited fields,
    rather than starting from a blank GetDBTask() result.
  • Structural (preferred): have the edit form load and round-trip the full task, or
    give UpdateTask a field-mask / partial-update variant so callers only write the
    columns they actually intend to change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions