Skip to content

Releases: speakeasy-api/granary

v1.6.0

11 Mar 12:03

Choose a tag to compare

Entity metadata

Tasks, projects, and initiatives now support an optional free-form JSON metadata field. This lets you attach arbitrary structured information — environment config, tracking IDs, custom fields — to any entity without being limited to text-only tags.

CLI usage:

granary project my-proj tasks create "deploy service" \
  --metadata '{"env": "production", "region": "us-east-1"}'

granary tasks update proj-task-1 \
  --metadata '{"env": "staging", "retries": 3}'

Metadata works the same way on projects (project create/update --metadata) and initiatives (initiative create/update --metadata).

Output behavior:

Metadata is included in --output json / --json output but is intentionally excluded from prompt and text formats, keeping those outputs clean for human and LLM consumption.

Event template access:

Metadata is embedded as a nested JSON object in all event payloads (task.created, task.updated, task.next, project.created, etc.), so event templates can reference individual metadata fields:

{metadata.env}
{metadata.region}
{metadata.config.timeout}

This enables metadata-driven automation — for example, a task.next handler that routes work based on {metadata.env} or {metadata.worktree}.

v1.5.0

07 Mar 12:56

Choose a tag to compare

Review mode workflow

Granary now supports an optional review gate in the task and project lifecycle. When enabled, completed work transitions to in_review instead of going straight to done/completed, giving a reviewer (human or agent) the chance to approve or reject it before it's finalized.

Two scopes:

  • task modegranary work done moves the task to in_review and emits a task.review event. A reviewer approves or rejects individual tasks.
  • project mode — Tasks still complete normally, but when all tasks are done, the project enters in_review instead of completed. Reviewers approve the project as a whole, or reject it by creating follow-up tasks and reopening the project.

New granary review command:

  • granary review <id> — displays reviewer context (task/project details, comments, suggested actions)
  • granary review <id> approve ["comment"] — approves and completes the entity
  • granary review <id> reject "feedback" — rejects with feedback; tasks return to todo, projects reopen to active with draft tasks promoted to todo

Review comments use a new review comment kind, and review events (task.review, project.review) are emitted so downstream agents or integrations can react.

Review mode configuration

Review mode is stored in the workspace database (config table) under the key workflow.review_mode. Enable it with:

granary config set workflow.review_mode task    # or 'project'
granary config unset workflow.review_mode       # disable

Updated SQL triggers

The trg_project_auto_complete trigger is now config-aware — when workflow.review_mode is set to project, it transitions the project to in_review instead of completed. New triggers emit task.review and project.review events on status transitions.

v1.4.6

22 Feb 23:21

Choose a tag to compare

Daemon shutdown now cleans up worker and run state

Previously, when the granary daemon shut down (via granary daemon stop, signals, or any other reason), workers were signalled to stop but their database status was never updated. This left workers permanently marked as running in the global database with their active runs also stuck in running state.

On next daemon start, restore_workers would find these stale "running" workers and attempt to respawn them — potentially picking up orphaned runs from completely unrelated workspaces. Manually stopping individual workers worked correctly because stop_worker properly updated the DB, but the bulk shutdown_all path (used on daemon exit) skipped this cleanup entirely.

shutdown_all now mirrors the same cleanup that stop_worker does: after signalling and waiting for workers to finish, it marks each worker as stopped and cancels any active runs in the database.

Fix: unblock returns tasks to `todo` and clears stale claims

Previously, `unblock_task` checked `started_at` to decide whether to return a task to `in_progress` or `todo`. Since agents set `started_at` when they begin work, unblocking always returned tasks to `in_progress` — even when the block was due to external factors (e.g., missing files from concurrent projects) and the task needed to re-enter the scheduling queue.

Additionally, unblock didn't clear `claim_owner` or `claim_lease_expires_at`. This meant the `task.next` SQLite trigger's claim guard would suppress the event even after manually cycling the task through `draft → todo`. The net effect was that unblocked tasks became invisible to the worker daemon — no `task.next` event fired, so no worker would pick them up.

What changed:

  • `unblock_task` now always transitions to `todo`, regardless of `started_at`
  • Stale claim fields (`claim_owner`, `claim_claimed_at`, `claim_lease_expires_at`) are cleared on unblock
  • The `task.next` trigger now fires correctly when tasks are unblocked

v1.4.5

22 Feb 20:21

Choose a tag to compare

1.4.5

Fixed progress bars showing as fully filled or empty

Progress bars throughout the initiative and project detail screens were rendering as binary — either completely empty or completely full — instead of showing actual proportional progress. A project at 15% completion would display an entirely filled bar.

The root cause was that FillPortion in Iced only distributes space among sibling elements. Each progress bar had a single child container inside the track, so FillPortion(15) behaved identically to FillPortion(100) — always taking 100% of the parent.

The fix adds a second container as a sibling to split the space proportionally, with conditional logic to omit the unused portion at 0% and 100% so both edge cases render correctly.

Affected locations:

  • Reusable ProgressBar widget
  • Initiative detail screen (main progress bar and per-project mini bars)
  • Project detail screen progress section
  • Project card progress bar

Fix task.next event loop on todo task updates

Workers subscribing to task.next events experienced an event loop where the same task would emit repeated task.next events approximately every second. This caused unnecessary event spam and wasted runner capacity.

Root cause: The trg_task_next_on_status_todo trigger fired on any update to a task with status = 'todo', not just on transitions to todo. When a worker claimed a task (setting owner, worker_ids, etc.), the update triggered another task.next event, which the daemon dispatched back to a worker, creating an infinite loop at the poll interval.

What changed:

  • Added AND OLD.status != 'todo' guard to trg_task_next_on_status_todo, so it only fires on actual status transitions to todo — not on metadata updates to tasks already in todo status
  • Added e2e tests verifying that owner/worker updates on todo tasks don't re-emit task.next
  • Added full lifecycle test covering project dependency cascade through worker-style updates

v1.4.4

22 Feb 20:05

Choose a tag to compare

1.4.4

Improved agent workflow prompts to prevent initiative planning mistakes

Agents planning multi-project initiatives were incorrectly creating tasks directly instead of delegating to sub-agents. The root cause: granary plan showed inviting task-creation templates, and granary initiate buried the delegation requirement in Step 3 of 4.

All agent-facing prompts have been redesigned to make the correct workflow path unmistakable.

granary initiate now front-loads a delegation constraint

The output now begins with a ## CRITICAL: Delegation-Only Workflow section before any steps:

## CRITICAL: Delegation-Only Workflow

You are the initiative coordinator. Your job is to create projects and delegate.
Do NOT create tasks directly. Do NOT use `granary project <id> tasks create`.
Task creation is handled by sub-agents via `granary plan --project <id>`.

Step 3 was also renamed from "Launch Sub-Agents for Planning" to "Delegate Planning to Sub-Agents" with reinforcement:

Do NOT create tasks yourself — this is the sub-agent's responsibility.

granary plan now warns initiative agents to stop

When an agent runs granary plan "Feature name" (without --project), the output now includes a scope guard:

## Scope: Single-Project Planning

This workflow is for planning ONE project with tasks.
If this is part of a multi-project initiative, stop here.
Use `granary initiate "Initiative name"` instead — it guides you through
creating projects and delegating task planning to sub-agents.

Entrypoint and help text now distinguish the two paths

Both granary (bare command) and granary --help now present a decision tree instead of a flat list:

Choose ONE entry point based on scope:
- Single project (one feature/fix): `granary plan "Feature name"`
- Multiple projects (cross-cutting work): `granary initiate "Initiative name"`

The --help text also adds an explicit note:

NOTE: Do NOT use `granary plan` for multi-project work.
`initiate` guides you through creating projects and delegating task planning to sub-agents.

v1.4.3

22 Feb 18:40

Choose a tag to compare

1.4.3

Fix task.next events not firing on project dependency completion

Workers subscribing to task.next events were never notified when a project dependency was satisfied through auto-completion. This caused tasks in dependent projects to sit idle even though granary next --all correctly showed them as actionable.

Root cause: The trg_task_next_on_project_dep_completed trigger fired when a project's status changed to 'done' or 'archived', but the auto-complete system sets projects to 'completed' — a status the trigger didn't recognize. Since no code path ever sets a project to 'done', this cascade trigger has never fired.

What changed:

  • The trg_task_next_on_project_dep_completed trigger now recognizes 'completed' as a valid completion status, so it fires when auto-complete transitions a project
  • All other task.next triggers updated to include 'completed' in project dependency status checks for consistency
  • Rust-side next queries updated to treat 'completed' projects as satisfied dependencies (defensive, previously handled by the task-existence subquery)

Impact: Workers will now correctly pick up tasks as soon as all tasks in a dependency project are done, without needing the dependency project to be manually archived.

v1.4.2

19 Feb 14:44

Choose a tag to compare

1.4.2

FTS5 search no longer fails on special characters

Queries containing FTS5 operator characters like -, +, *, or keywords like NOT/OR/AND are now properly escaped before being passed to SQLite's FTS5 MATCH clause.

Previously, running something like granary plan "Fix TypeScript v2 build failures - 11 root causes from SDK battery tests" would fail because the - was interpreted as FTS5's NOT operator. Now, each token is individually quoted and purely-punctuation tokens (like a bare -) are dropped, so the search works regardless of what characters appear in the plan name.

Search queries also now use OR semantics instead of implicit AND, which makes prior-art matching more lenient — a project only needs to match some of the query terms to appear in results, rather than requiring all of them.

v1.4.1

17 Feb 17:38

Choose a tag to compare

1.4.1

Project dependency filtering in next commands

The next, next --all, project.next, and task.next mechanisms now correctly respect project-level dependencies. Previously, only task dependencies were checked — so when Project A depended on Project B, tasks from both projects would appear as actionable even if Project B still had incomplete work.

Now, tasks in a project with unmet project dependencies are excluded from all next-task queries and event triggers. A project dependency is considered met when the dependency project is either done or archived.

This also fixes the initiative ... next command, which had a similar issue where archiving a dependency project would leave dependents permanently blocked (it only checked task status, not project status).

Cascade trigger for project completion

A new SQLite trigger (trg_task_next_on_project_dep_completed) automatically emits task.next events when a dependency project transitions to done or archived. This ensures workers subscribed to task.next are notified when project-level blockers are resolved, without requiring any manual intervention.

E2E test coverage for project dependency blocking

Added a dedicated end-to-end test suite (tests/project_dep_next_e2e.rs) that runs the actual granary binary in an isolated sandbox to verify project dependency filtering works correctly across next, next --all, and initiative next. Tests cover blocking, unblocking via completion, unblocking via archival, and partial dependency satisfaction.

v1.4.0

16 Feb 23:01

Choose a tag to compare

1.4.0

Task–worker/run association

When a worker picks up a task event, granary now automatically records which workers and runs have operated on it. Each task gains two new JSON-array columns — worker_ids and run_ids — that accumulate IDs as work is performed. The first run to claim an unowned task also sets itself as the task's owner, giving downstream automation a single ID to query for the "current" run.

This means you can trace exactly which workers touched a task and in what order, without having to join across run tables manually.

Environment variables for spawned processes

Every process spawned by a worker now receives two new environment variables:

  • GRANARY_WORKER_ID — the ID of the worker that spawned the process
  • GRANARY_RUN_ID — the ID of the current run

Scripts and actions can use these to call back into granary, tag artifacts, or correlate logs without needing to parse context from the event payload.

Clickable worker/run links in Silo

Task detail views across all three screens (initiative detail, project detail, and task list) now display worker and run IDs as clickable links that navigate directly to the corresponding worker or run detail screen.

v1.3.0

16 Feb 16:56

Choose a tag to compare

1.3.0

FTS5 full-text search

Search now uses SQLite's FTS5 full-text search engine instead of LIKE '%query%' pattern matching. This is a significant upgrade to how granary search and granary plan find relevant results.

What changed

A new shared FTS5 virtual table (search_index) indexes projects, tasks, and initiatives across their names/titles, descriptions, and tags. SQLite triggers keep the index in sync automatically on every insert, update, and delete.

Search results are now relevance-ranked using BM25 scoring, with title matches weighted higher than body or tag matches. Previously, results were returned in created_at DESC order with no relevance signal.

New capabilities

  • Multi-word queries: auth login matches documents containing both terms (implicit AND), instead of requiring the exact substring
  • Phrase matching: "auth login" finds the exact phrase
  • Prefix matching: auth* matches any term starting with "auth"
  • Boolean operators: auth OR login for explicit OR queries
  • Broader coverage: descriptions and tags are now searched, not just names/titles

Impact on granary plan

Prior art discovery in granary plan benefits directly — it now finds related projects even when the name doesn't contain the exact query substring, and results are ordered by relevance rather than creation date.

Includes an RFC document at docs/rfcs/fts5-search.md with full design rationale.