Search

    MENU

    CHANGELOG

    Markdown

    Notable changes to Zinn and its integrations. Each CLI release names the core version it includes, and integrations release on their own versions. Breaking changes include the action needed when upgrading.

    0.44.0

    Added

    • Telemetry: Zinn now records local usage by default. Each run appends a line to a record file in telemetry/ in the Zinn directory. Records never leave the machine. See Data and backups and Settings.
    • task blame <task-key> and core’s task.blame(taskKey) attribute current fields, label membership, parent, relations and description lines to recorded activity, including actor and session identity. Unchanged lines keep their attribution through exact-line comparisons. Incomplete history is shown as unrecorded. See CLI and core.
    • Activity records include actor_client, which is intended as a record of the chain of programs making a change. The CLI records its version and any ZINN_CLIENT declaration. whoami, activity text and JSON expose the client, and activity list --client <name> filters by program or part. Library callers can supply Actor.client and read chains with parseClientChain. See Client chains.
      • Schema version 4 adds the nullable field. Existing events keep a null client. A published release upgrades the database to schema 4 on first use, after saving a backup. An older Zinn can read the upgraded database but refuses changes to it.
    • activity.getCurrentTaskIdentities({ taskIds, taskKeys }) returns the ID, key, title and status of existing active and archived tasks matching the given IDs or keys, without reading history. See Core.
    • activity.getDeletedTaskIdentities({ taskIds, taskKeys }) returns the ID, key, title and deleted status of deleted tasks matching the given IDs or keys, read from task and project deletions at once. See Core.
    • A command that fails with a storage or internal error writes a log under logs/ in the Zinn directory, with the stack, the cause chain, the run, the store and the arguments as typed. error.details.logPath in the --json error and the last stderr line name the file, and the newest 10 logs are kept. See Scripting.
    • zinn --help lists what Zinn can do and the command or flag for each: deadlines, several tasks per command, text from a file or stdin, search, continuing long lists and activity. See CLI.
    • task search now accepts --column <name> and filters by an exact column name, ignoring case, together with the text query, labels, deadlines and archive filters. See CLI.

    Changed

    • Breaking CLI: task list --starting-after takes the cursor printed by the continuation command instead of a task ID. A script that passes a task ID must switch to that cursor.
      • Continuation survives changes to the last listed task. task.getPage and activity.getAll return nextCursor when more results remain. See Core and CLI.
    • Column names are now colored by board position instead of by name in CLI. A board’s first column is gray and its last column is green, whatever they are called, so renaming a column keeps its color. A column appended after Done takes over the green, and a board with a single column colors it gray. Task rows, relation rows and project column list show the same colors. --json task, relation and column results add is_first and is_last for the column’s board placement. See CLI and Scripting.
    • activity list reads only the history and tasks a page needs instead of every event. On a database with 50,000 events, --project and --project-id pages list in under a third of the time and global pages in under half. Project and task selections in activity.getAll gain the same way.
    • activity list without --project or --task checks reused task keys and deleted tasks across the whole database. --limit, --starting-after and filters no longer change whether a row names a deleted task or adds its task ID. Each row shows as it does in the full list.
    • --limit on task list, task search and activity list accepts any integer from 1 through 9007199254740991, and the core limit option accepts up to Number.MAX_SAFE_INTEGER. Values above 11871 are no longer refused. Omitting --limit still returns every match. See CLI.

    Fixed

    • Breaking core API: database paths and backup folders use the same filesystem resolution for migration results, backups, storage inspection and diagnostics.
      • getStorage() returns a fresh snapshot from the cached configuration on each call and resolves the database destination. Keep the snapshot for an operation instead of relying on object identity between calls. getBackupStorage() resolves the backup folder for an operation that writes a backup, so a dangling backups link fails only zinn backup, zinn migrate, zinn restore or an automatic upgrade, with an error that names the folder, and other commands keep working. backup.restore accepts an optional BackupStorage snapshot to retain a previously selected destination. See Core and Data and backups.
    • Backups on macOS and Linux sync their directory entries before reporting success. A sync failure stops an upgrade or restore before it changes the database. See Data and backups.

    Security

    • @zinn-dev/core and @zinn-dev/cli now depend on zod 4.6.7, outside the affected range of GHSA-mrhx-c7xc-m3w5.

    OpenCode 0.4.0

    Added

    • Task details show a short excerpt of the latest mention in the conversation.
    • Select a related task to open it in the same dialog, then use back to return. Long relation lists scroll in place, and the dialog closes from its close control or Esc.

    OpenCode 0.3.1

    Fixed

    • The inspector ships a compiled TUI module, so task rows render in a registry install instead of stopping at ZINN [loading…].

    0.43.0

    Added

    • Tasks can have deadlines. task create and task edit accept --due <timestamp>, and --due none clears it. task list and task search select deadlines with --due-since and --due-until, and task list --sort due puts the earliest first. See CLI.
      • Timestamps are integer epoch milliseconds or a complete timestamp with Z or a numeric offset. Task JSON includes due_at, and activity records deadline changes. Core adds dueSince, dueUntil and timestampSchema.
    • task list and activity list continue a long result with --starting-after <id>. When --limit cuts the results short, stderr prints the command that continues them. Core adds task.getPage, which returns { tasks, hasMore }.
    • task list --sort activity lists the most recently active tasks first, counting comments and relations. task list also accepts --limit.
    • activity list selects history with --changed, --action, --since and --until.
      • --changed <field> matches a change to column, priority, labels, title, description or due_at. column, priority and labels also take a value, as in --changed column=Review.
      • --action <action> matches recorded actions such as move or comment_create. --since and --until bound the recorded time, inclusively.
      • Repeat a flag to match any of its values. Core accepts the same filters as changed, actions, since and until.
    • project column delete deletes an empty column after confirmation. A project can have no columns, and creating a task in it fails until a column is added. Core adds column.delete and column.getByName.
    • project list shows each project’s active and archived task counts. JSON entries include taskCounts, and core adds project.getAllWithTaskCounts.
    • Parser and routing failures report error.details.reason, such as unknown_option or missing_argument. zinn capabilities --json lists every value. See Scripting.
    • Core exports isSqliteErrorCode and isSqliteErrorFamily, which match SQLite result codes and narrow the error to SqliteError. See Core.

    Changed

    • A published release upgrades databases at schema version 1 or 2 to version 3 on first use, after saving a backup.
    • Breaking store initialization: only project create and label create create a database when the store has none. Other commands fail with not_found, details.entity: "database" and details.databasePath, exit with code 1 and write nothing.
      • Core operations other than project.create and label.create throw a CoreError with kind missing and entity database. See Core.
    • Breaking relations: a task pair holds one relation across all types and directions. task relation create names the conflicting links and asks before replacing them, and --yes replaces them without asking, including with --json. task create refuses two relation types for the same target.
      • Core callers pass replace to relation.create, with the IDs from relation.getConflicts or true, or receive a conflict. See Core.
    • Breaking core API: activity.getAll returns { events, hasMore } instead of an array and accepts startingAfter. Read the records from events. activity list --json still prints an array.
    • Breaking limits: --limit on task list, task search and activity list accepts an integer from 1 through 11871. Scripts that passed a larger value must lower it. task list and activity list can continue with --starting-after.
    • Full task objects in every --json result include created_at, updated_at and due_at. Consumers validating results against a previous release’s schemas must refresh zinn capabilities --json. See Scripting.
    • Deleting a project records a relation_delete event on each surviving task that loses a cross-project relation, including archived tasks, without changing its updated_at.
    • Namespace help, such as zinn task --help, lists each command on its own line with a short summary.
    • Table columns stay aligned with wide characters, emoji and combining marks. Description previews and comment echoes never split a character.
    • Parser and routing error messages are capped at 1,024 UTF-16 units. error.help and error.details keep their complete values.

    OpenCode 0.3.0

    Changed

    • Installing the inspector no longer pulls @opencode/plugin and its server and GUI dependencies. OpenCode provides the plugin API at runtime, so an install only needs the OpenTUI and solid-js peers.

    OpenCode 0.2.0

    Changed

    • Visuals adjusted so that the inspector sidepanel has one rail from the header to the footer. Each task’s state glyph sits in the rail, Done tasks highlight it.
    • Tasks created during the session show + next to the key.

    OpenCode 0.1.0

    Added

    • The OpenCode sidepanel lists the Zinn tasks mentioned in the current conversation, read through the local Zinn CLI. Selecting a task opens its details. Requires OpenCode 2.2.0 and Zinn CLI 0.41.0 or newer. See OpenCode task inspector.
    • Task details show status, priority, labels, relations, comment count and the first paragraph of the description. Opened from a mention, they also count the task’s mentions in this conversation.
    • /zinn finds a loaded active task. The command palette also offers Zinn: task keys in this chat and Zinn: pick a task from the board.
    • The rows option set to 2 adds column, priority and labels to each task in the sidepanel. The current option set to "glyph" marks tasks with recorded activity from this conversation, and the mark animates while the conversation is busy.

    0.42.0

    Added

    • Hooks are now available. Configure post-change hooks in global settings. They receive activity records on stdin after the change commits. See Hooks.
    • zinn whoami reports the actor identity a change would record in the current environment and directory.
    • task order and task delete accept multiple task keys and apply each batch atomically. Core exposes task.orderMany and task.deleteMany.
    • activity list selects history with --project, --project-id, --task or --task-id. Use --show-deleted with a project or task key to include history for deleted identities.
    • Read descriptions with --description-file and comments with --text-file. Use - to read stdin.
    • Use show, ls, rm and new as aliases for view, list, delete and create.
    • label view shows a label’s full description.

    Changed

    • Breaking core API: task.edit, task.label.add, task.label.remove and task.order return { task, changed }.
      • project.edit, column.edit, column.order, label.edit and comment.edit return the corresponding entity field and changed. Read the record from that field and use changed to distinguish saved changes from no-op requests.
    • JSON results include stored entity IDs, and additional mutation results report changed. Consumers validating results against a previous release’s schemas must refresh zinn capabilities --json. See Scripting.
    • Breaking text input: descriptions and comment text are limited to 1 MiB of UTF-8 input. Keep each input and the resulting text of a partial edit within that limit.
      • Oversized input fails without writing changes.
    • Descriptions and comment text normalize CRLF pairs to LF, including append, find and replacement inputs. Other whitespace, including lone carriage returns is preserved.
    • task view includes creation and update times.
    • Breaking storage: a folder chosen through ZINN_DIR or storage.directory must already exist. Create it with mkdir -p <path> first.
      • A missing folder, a path that is not a folder, or an empty ZINN_DIR fails with error.code storage and error.details.reason invalid_storage. The default ~/.zinn folder is still created on first use. See Settings.

    Fixed

    • Invalid text-source flag combinations fail before reading files or stdin.
    • Upgrades from schema version 1 preserve SQLite execution errors on older Bun versions and roll back the failed migration.
    • The manifest schema in zinn capabilities --json describes the manifest exactly, including the fixed order of invocation.canonicalArgv.

    0.41.0

    Added

    • zinn capabilities describes every installed command: its inputs, effects, confirmations, and result schemas. With --json it emits the full contract, including reusable JSON Schemas.
    • zinn info reports the selected store, the settings files, the configured default project, the database schema state, and the CLI, core and runtime versions. Unusable settings and database problems are reported there, and the command still exits with code 0.
    • zinn task comment view <comment-key> shows a comment’s full text, keeping its line breaks.
    • Activity records the declared actor identity. Declarations use ZINN_SESSION_ID, ZINN_THREAD_ID, ZINN_AGENT, ZINN_MODEL and ZINN_EFFORT. Without these, CLAUDE_CODE_SESSION_ID, CODEX_SESSION_ID/CODEX_THREAD_ID or OPENCODE_SESSION_ID fills the session or thread, and OpenCode’s ID is recorded as the thread.
    • zinn activity list --session <id> and --thread <id> match complete stored IDs exactly, and rows without the identity do not match. activity view reports the declared identity.
    • The CLI package ships the Zinn workflow skill at skills/zinn/SKILL.md. Install it using npx skills add yethranayeh/zinn --skill zinn -g -y. The skill covers picking up work, keeping task context, recording follow-ups, and handing off for review.
    • Core exposes the info operation, defaultProject resolution, and validation schemas for settings, activity records, and label, priority, and relation values.

    Changed

    • Breaking JSON: handled failures carry required error.code (invalid_input, not_found, conflict, storage, internal) and optional details and diagnostics alongside message and help. Scripts must match on code and read failure facts from details instead of message text, and notices, including lock waits, print only after a --json command completes.
    • Breaking core API: Actor.name is nullable, null only for unnamed agents, and Activity gains the six nullable actor_* keys. Expected failures throw CoreError or InputValidationError, which carry a failure kind and typed facts, instead of plain Error, and SQLite failures throw SqliteError. Consumers must handle null actor names and catch these error classes.
    • A published release upgrades databases at schema version 1 to version 2 on first use, after saving a backup.
    • Priority values on task create and task edit are case-insensitive, and stored values and JSON use lowercase. Relations in task relation list and task view read oldest first.
    • Refusals of likely mistakes name the fix: an unrecognized --status or --column on task edit or task move suggests zinn task move with the same task keys, and a dash-leading option value suggests the command joined with =, as in --description='- item'.

    Fixed

    • zinn restore attaches the backup by plain path, so backup paths containing ?, # or other special URI characters, including non-ASCII names, restore correctly.

    0.40.0

    Changed

    • Install the CLI with npm i -g @zinn-dev/cli. The CLI and core ship as ESM JavaScript with TypeScript declarations and run on Node.js 24.15.0 or newer. Bun remains supported. See installation.
    • Confirmation prompts use stderr. Enter declines, and y or Y confirms.
    • Breaking core API: readReleaseMode is removed from the public exports. Pass your client’s release identity directly to configureDatabase with source for development or published for prepared release artifacts. Core determines its own identity independently.

    0.39.0

    Added

    • Configure defaultProject in settings.json or zinn.local.json to use a project when its key is omitted. Use --all-projects to list or search tasks across projects.
    • Read task activity with zinn task view <task-key> --history.
    • Validate settings files with the published JSON Schema.

    Changed

    • Breaking confirmations: project delete, task delete and restore require --yes when stdin or stdout is redirected. Unanswered confirmations exit with code 1 before changing data. Scripts must pass --yes and type the project key when deleting a project. Piped answers do not confirm an operation.
    • Breaking settings isolation: ZINN_DIR reads settings only from the selected store’s settings.json. Put settings needed by that store there. Global and per-codebase files are ignored.

    Fixed

    • Activity history marks deleted entities and distinguishes task IDs when a task key is reused.
    • Migrations and restores refuse to commit if foreign keys reference missing tables, as well as missing rows.

    0.38.0

    Added

    • Read recorded changes with zinn activity list and zinn activity view.
    • Assign a column and relations when creating a task, and filter task lists by column.
    • Append text or replace matching text when editing descriptions and comments, using --append or --replacing.
    • Core exposes activity reads and structured text edits.

    Changed

    • Breaking arguments: extra positional words, repeated single-use options and conflicting options fail with usage help. Remove extra arguments and pass each single use option once.
    • Breaking validation: task titles and project, column and label names are trimmed and must be nonblank single lines without control characters. Use descriptions for multiline text.

    0.37.0Eridu

    Added

    • Move, archive or unarchive several tasks in one command. Each operation applies to all supplied tasks atomically.
    • Restore a database with zinn restore, repair its search index with zinn reindex, and apply supported schema upgrades with zinn migrate.
    • Configure storage.directory in global settings.json or per-codebase zinn.local.json. Note that ZINN_DIR overrides both.
    • Core exposes database configuration, migration and recovery operations, plus bulk task operations.

    Changed

    • Breaking database compatibility: databases now record a schema version. Published releases upgrade supported older versions after saving a backup. Unmarked databases created before version tracking require --allow-legacy-read for best-effort read-only access and cannot be upgraded with zinn migrate. Save a snapshot with zinn backup before upgrading. See database upgrades.
    • Breaking JSON: zinn project view --json replaces tasks with columns containing name and taskCount, plus archivedTaskCount. Use zinn task list <project-key> --json to read tasks. Move, archive and unarchive return an object for one task or an array for several, with a changed flag on each result.

    Fixed

    • Backups use unique filenames and become available only after the snapshot is complete.
    • SQLite writes use stronger commit durability, and statements created inside a transaction cannot outlive it.