Changelog

Every release, in the words of the person who shipped it. Issue keys link into the public backlog, so a line here leads to the issue that asked for it.

Rendered from CHANGELOG.md in the repository. View on GitHub

v0.24.1 — 2026-10-01

The app opens a shell that can see your tools. A serve launched from Finder or the Dock inherits launchd’s environment — PATH=/usr/bin:/bin: /usr/sbin:/sbin and no locale at all, measured on Gadak.app 0.24.0 — and the pane’s shell is not a login shell, so it never read the two files that would fix either. On exactly the installs that get gadak from the cask, the bare gadak a pane promises was unfindable, every brew-installed tool was missing, and zsh’s line editor could not see multibyte input. The login shell is asked once what its environment is and two things cross: PATH keeps every entry it had and gains what only the login shell knew, and the locale is filled only when there was none. A shell that is slow or unresolvable leaves the environment alone and the pane opens anyway, and gadak doctor says which of those happened (GDK-2032).

Columns you set stay where you put them. Pinning the issue list’s width — by dragging its right edge or with gadak config set ui.tokens.layout.list — used to leave the detail panel beside it unable to take the slack: narrow the list and a strip of nothing opened down the right edge of the window, widen it and the seam would not move while the width was saved anyway, after which the in-app browser spent that number out of its own column. The column beside a pinned list can now take what the list gave up, and a drag saves the width it painted rather than the one the pointer asked for (GDK-2047). On the same screen, a bulk selection can be started and extended from the keyboard — Enter and Shift+Enter had been opening the detail instead — and the two actions no origin can undo, revoking a pairing and clearing history, now ask twice like their quieter neighbours already did (GDK-2005, GDK-2006).

The phone reads the retro, and the catalogs answer agents straight. How the last week went is now a phone screen: the sentence the desk opens with, its four summary numbers, the stalled tail, and what closed — the desk’s own arithmetic, not a squeezed copy of its week-column table (GDK-1827). A status whose category gadak has never seen folds the same way on the desk, on the phone and in Go, so a feature keyed on it stops working on half the accounts and not the other half (GDK-2004, GDK-2042). Agents get four things the binary already accepted and the catalog never mentioned — gadak sql --layout, issue --link, labels from gadak_search, and sync --source (GDK-2017) — a no such column hint now guesses the suffixed spellings too (GDK-2029), and on an iPhone an address the app will not dial says so instead of reporting a network error (GDK-2009).

v0.24.0 — 2026-09-18

The terminal works on a phone. Open a shell in the phone app, or in a phone browser through tailscale serve, and it takes the screen it is given and keeps the keyboard up while you type (GDK-1987, GDK-1986). Under the pane is a strip carrying the keys a phone keyboard does not have — Esc, Tab, Ctrl, Alt and the arrows, with the same three states for a held modifier the phone app already used — so a shell reached from a browser can be driven and not only read (GDK-1995). In the phone app, Korean typed into the shell arrives as words, and what is still being assembled shows above the keys (GDK-1988).

The phone’s list is the desktop’s list. Every built-in view reads in the order it was written for — Handed off quietest first, Reopened by how often work came back — and sections by what the view says to section by, a sprint the way the desk does it (GDK-1992, GDK-1993). The header says where to tap: a rule under the heading, one set of controls at its right end, and search back among them in the slot manual refresh gave up — Sync now is in Settings (GDK-1989, GDK-1990).

Those two controls open different things. The magnifier opens the palette, to find one issue anywhere in the cache, where a row that leads somewhere now says so (GDK-1949, GDK-1997); the view’s name opens this list — the view it belongs to, and under it the toggles that narrow what is on screen. That second half is new. Narrowing a list had meant going back to the desktop and saving a view there. The toggles are found in the list itself, one that would change nothing is not offered, and nothing is saved: the narrowing goes when you pick another view (GDK-1994).

Korean and Japanese read whole. Japanese search finds what is there. A Japanese sentence has no spaces, and a term with nothing separating it had not been indexed as a term at all — across the cache this release ships with, Japanese lost 625 terms in 334 of 605 items while English lost none (GDK-1978). The retro’s Korean numbers stop counting 나머지 as a merge (GDK-1946), a Japanese sprint goal gets the second line its 34 full-width characters need (GDK-1977), and the Korean and Japanese demo data translates its labels like everything else on that screen (GDK-1976).

v0.23.1 — 2026-09-17

A status the apps offered but the server refused. On the built-in tracker a workflow that has been migrated carries two statuses named the same, and the transition ids it hands out then overlap with status ids — so the Done the web and phone apps showed was answered with “a bare number is ambiguous” every time, and Done was the one transition no button could apply. The id a client picked out of the transition list is now matched exactly and never re-read as a status id, a name or a category token; a stale list is refused by name, with the ids the issue actually offers. Typing a status name at the CLI still means what it did (GDK-1982). A write that the server refuses now says so in its log — that 400 was the one branch that left nothing behind.

One door on the phone’s list, and it says search. The header carried two controls that opened the same palette — the heading and a magnifier beside the create action — and neither closed it again. The heading is the only door now and it wears the palette’s own magnifier, so the screen still says search without a second control, and a second tap on it closes what the first opened and puts the list back where it was (GDK-1985, GDK-1984). The 44px it buys back goes to the view’s name: in English and Japanese the longest built-in views stop shedding their count, and three more stop stepping down a size at all.

v0.23.0 — 2026-09-17

The phone is the whole app. The bottom tab bar is gone. Tap the list heading and a palette opens in its place: recent issues, built-in and saved views, Jira filters, spaces, and the terminal once one is paired. Typing in it searches issues and pages, so Search is no longer a screen of its own, and Settings sits behind a gear in the heading (GDK-901, GDK-902). An active sprint reads as one line under the heading, and tapping it scopes the list to that sprint; every sprint the cache holds, with its window, its progress and its goal, is a row in the palette (GDK-1867, GDK-1827). The detail draws everything the cache has for an issue: labels, components, fix versions, parent, epic and the site’s own custom fields, with attachments three across (GDK-1870, GDK-1882). And it writes. From an epic, + files a child, the Labels row toggles the workspace’s labels, the due date opens the phone’s date wheel, and a photo goes with a comment on an issue or a wiki page (GDK-1871, GDK-1872, GDK-1873, GDK-1879). Each write ends in one short line saying it landed, a comment or a title you were typing survives a relaunch, and what stays on the desk says so where you would look for it (GDK-1969, GDK-1863, GDK-1874).

A phone on your tailnet needs no install at all. A serve bound to a Tailscale address answers its own MagicDNS name and carries the phone bundle at /m/, so https://<node>.<tailnet>.ts.net/m/ in Safari is the whole app: no store build and no pairing, because reaching the address is the credential the admin console already granted the device. Behind tailscale serve the person’s Tailscale login rides each request and their writes are attributed to them; reached directly, the serve stays the single-user surface it was. The desktop’s Devices tab shows that address as a QR code (GDK-1966). There an open issue is a real history entry with its key in the address, so the back swipe lands on the list, an issue’s address can be pasted to a teammate, and the page installs to the Home Screen as a full-screen app (GDK-1970). The shell follows the same rule: behind tailscale serve the account that owns the machine opens one with no pairing (GDK-1972). On the built-in tracker you can say who you are, with gadak me set "Your Name" or a name field in Settings, and every surface records its writes under it (GDK-1973).

What the cache holds answers to the origin. A wiki page removed at the origin used to stay in the local cache for as long as its space did. A full wiki sync now compares each space’s listing with the cache, and the hourly reconcile does the same by page id (GDK-1884; #104, thanks @wafe). A page moved between two synced spaces follows on that reconcile (GDK-1886), an attachment or comment added to a page arrives even when the page itself was not edited (GDK-1888), and a Linear issue deleted at the origin leaves the cache the next time gadak re-reads it (GDK-1889). The retrospective answers to the same rule: under sprint columns the table carries two rows about what is in the sprint beside the interval rows that say what moved during it (GDK-1846), and its mismatch row no longer reads ordinary Korean scheduling vocabulary as a claim that the work is finished (GDK-1943).

An agent’s page renders on the issue. Attach an HTML file and the detail shows it as an artifact: the page runs in a sandboxed frame with no network and no access to gadak’s own origin, with its issue pushed in as data. That is the contract dashboards already run under, so an agent that can write a dashboard can write a page for one issue, and a dashboard opened from a pasted URL is held the same way (GDK-1897, GDK-1898). Your tracker stores it as an ordinary attachment. And gadak demo --writable serves the bundled snapshot as a tracker of its own rather than as a cache with no credential, which is how the recorded walks on the site and in the three READMEs show the phone writing (GDK-1959, GDK-1932).

v0.22.1 — 2026-09-14

gadak installs into Claude Desktop as one file. Every release now carries gadak-<version>.mcpb, a Claude Desktop extension holding that release’s own binary — a universal one on macOS, the x64 exe on Windows — so the tools arrive without editing claude_desktop_config.json, and the extension asks which workspace to read and nothing else. gadak is in the official MCP Registry under io.github.midagedev/gadak, and a tag now builds the extension from its own published archives and publishes the registry entry that points at it (GDK-1822).

gadak takes its own name and its own address off surfaces they do not belong on. It stopped answering to its old name: the SCRY_* environment variables are no longer read, and a ~/.scry home, a scry.db, the old binary-name hint and the scry: localStorage migrations are all gone. gadak doctor still reports a leftover ~/.scry directory, because that stays true (GDK-1143). The detail header’s copy-link does the same thing one surface over: on a Jira or Linear workspace it puts that issue’s own page on the clipboard and nothing else. It used to append a gadak:// deep link under that page — and, on a served workspace, an http line under that — so every paste into chat carried an address only the sender’s machine could open, while the toast said a Jira link had been copied (GDK-1858). A workspace on the built-in tracker has no origin page and keeps copying the app links: there, they are the address. The list’s copy-link follows the same rule where it holds: a view whose clauses all became JQL copies the navigator address alone, and when a clause could not travel, the app link comes along and the toast names the clause that is the reason. A copied http address also carries the mount it was copied from now — on the hosted demo it pointed at the site’s root rather than at the app (GDK-1860).

What a reader sees is what is true. The Korean and the Japanese read like they were written that way. The retro screen’s Korean carried a sentence whose subject could not do its verb, a lagging-and-leading framing the English line never made, and two names for one number; the Japanese hint ended two sentences on the same predicate (GDK-1848). A reader then said the site’s Japanese read as though it had been spaced and lettered by someone who does not use the language, and both halves of that measured. 162 ASCII spaces sat beside a Japanese character on /ja/ alone — between a numeral and its counter as much as wherever Latin met kana — and font-probe read Latin on a lang=ja page as Hiragino Sans, so gadak, Jira, SQL and every number on the page were drawn in a Japanese face’s Latin (GDK-1853, GDK-1854). Every line was rewritten against what the English says, the spaces are gone and gated (tools/ja-spacing.py, doc-checks #60), a source line break between Japanese characters stopped rendering as a space on /ja/changelog/, and the system Latin faces now sit in front of the Japanese ones — the order the product’s own stylesheet already used.

The retro’s density strip drew the week it was asked about, except on the first day of one: a bucket still running ends hours after it begins, the strip truncated that end to its own date, and the day count came back zero — so the section vanished on the morning it had the least to say, which is also the morning someone opens a retro to find out (GDK-1859).

v0.22.0 — 2026-09-13

Self-hosted Jira is an origin type. gadak init --site <base-url> --server opens a workspace against Jira Server or Data Center with a Personal Access Token and no email. What Server sends differently is read the way Server sends it, wiki markup carried verbatim where Cloud sends ADF (GDK-1637). docs/SUPPORT_MATRIX.md has a Jira Server column beside Cloud, Linear and Built-in, every cell of it run against a Jira Software 11.3.11 lab — including the two things that do not work (GDK-1635, GDK-1634).

A sprint is an object, and a retrospective is a screen. A sprint used to be three columns on an issue, so an empty one did not exist and its goal and dates lived nowhere. gadak sprint — list, add, remove, create, start, close — writes through the origin and re-reads (GDK-1653); the built-in tracker serves sprints with no Atlassian account (GDK-1666); the board takes a scope of active sprint, backlog or all (GDK-1656); and the active sprint has a line of its own with goal, dates, days left and a progress bar (GDK-1709). The palette’s Weekly retro opens a table that reads like a report — a column per week, a row per metric with its definition under it, a sparkline and a delta on each row, a cell that holds issues a door onto them (GDK-1660, GDK-1712) — and it cuts by sprint as well as by ISO week (GDK-1693). reopen_count counts the reopen teams actually fire: where resolved statuses sit in the in-progress category, the old done→new rule had been reading 59% of real reopens as zero (GDK-1753).

gadak stopped phoning home, and says more about itself. No daily question to GitHub about a newer release: no background request, no updateCheck setting, no banner, five outbound destinations where there were six (GDK-1626). gadak doctor prints a binary line — the executable’s real path with the symlink resolved, and the signature on it, developer-id for the release and adhoc for a local build — the pair that separates “the release is broken” from “you are not running the release” (GDK-1798). gadak comment edit and gadak comment rm work on all three origins (GDK-1647). gadak mcp install claude-desktop registers with Claude Desktop, where every front door used to teach Desktop users claude mcp add, which belongs to Claude Code (GDK-1633). The built-in tracker’s attachment cap is gadak config set attachmentMaxMB <n>, 1 GiB by default where 32 MiB had been hard-coded (GDK-1617). The terminal dock becomes a sheet under 1420 pixels when a detail panel is open, rather than covering the list it is there to drive (GDK-1833). And watching the Korean and Japanese clips frame by frame caught what copy review had not: Backlog and Selected for Development standing in English one line above 진행 중, 内蔵 on one screen and 組み込み on the next, 未担当 where the rest of the product says 未割り当て (GDK-1837, GDK-1839).

v0.21.0 — 2026-09-08

What happened while you were away, answered from the mirror. Every status change, comment and visit is already there, so 0.21 answers the questions you ask on coming back (what changed, how long has this sat, did we get faster) from that data, in numbers with their definition beside them. Everything here is read-only over the mirror. Nothing new leaves the machine. gadak retro gives a weekly retrospective: sessions, resume time, how old the work in progress is, what closed and how long it took, and mismatch (the newest comment says done, the status does not). Every row prints its definition, and --open puts the issues behind a cell on the app. The list opens with one dim line, 7 changed · 2 of them yours, and the detail panel says what moved on that issue since you last opened it; the boundary is your own previous session, and that line no longer vanishes on a quiet morning (GDK-1537). The stale mark learns its threshold from the workspace’s last 90 days of cycle times; list, ready and next carry age_days; the durations chip shows the team’s p85 on hover; a done-sounding comment under an open status offers Move to done. Five built-in views (GDK-1493) hold the sidebar now: My issues, Handed off, All open, Unassigned new, Reopened. Aging, Epics, Stale and the rest leave it, one Save as view away.

Agent writes say so, and the skill installs on seven hosts. A comment, transition or issue written from the CLI against Jira Cloud or Linear ends with — via gadak · Name, so a team can tell an agent’s write from the person whose credential it used. actor.trailer=false turns it off. And gadak skill install --client codex|agents|cursor|gemini|opencode|grok beside claude (GDK-1508).

Japanese, the phone, and a round of fixes. The site reads at /ja/, the app picks Japanese type under :lang(ja), and every landing clip, including the live-Claude hero, is recorded in en, ko and ja over a mirror in that language (GDK-1500, GDK-1501). On the phone (TestFlight), descriptions, comments and wiki pages render like the desk; assignee, priority, summary and description are edited from the header; one pairing scan carries both tokens (GDK-1497, GDK-1498).

A serve host’s mirror could drift from its origin until --full; reconcile now looks both ways and doctor flags a short mirror (GDK-1400). gadak transition KEY inprogress no longer refuses two destinations with one display name (GDK-1356). Clicking the terminal to focus it no longer opens the key under the pointer (GDK-1186). gadak migrate keeps priorities when the mirror has no priority ids (GDK-1491). One Esc closes a picker, not the panel (GDK-1401).

v0.20.2 — 2026-09-06

The Windows app is on the Microsoft Store. The desktop app is on the Microsoft Store. The Store signs it, so neither SmartScreen nor Smart App Control objects, and every install guide leads with it (GDK-1380). gadak-desktop.exe is a GUI-subsystem image at last: no console window beside the app (every zip since 0.16 and the first Store package had one), and the pack refuses to ship one again. The Store package declares an app-execution alias, so a Store install puts gadak on PATH, and ja-JP as a third language.

Linear relations arrive, and one field has one name. Linear relations are mirrored as links (blocks, duplicate, related), so the linked-issues panel and the blockers recipes work on a Linear workspace (GDK-1299). One field, one name: the breakdown axes read the same labels as the filter and the columns (GDK-1399), and the link-type catalog is fetched once per workspace, so a linked issue’s direction phrase no longer flashes its bare type name on every open (GDK-1297). wiki, wiki.enabled and wiki.spaces are aliases of the confluence.* config paths, and config get/set says where the value lives (GDK-1289). In the terminal, an issue key printed under the resting pointer is clickable at once, not after the mouse moves (GDK-1172).

Fixes, and the window speaks three languages. A Confluence page-version write that fails degrades the mirror instead of killing the wiki pass (GDK-1307); the transition refusal for a number that is both a transition id and a status id names the two forms that cannot collide (GDK-1305); and two CI flakes are gone, the pairing mint test and the create-dialog e2e (GDK-1306, GDK-1295). The window speaks English, Korean and Japanese, and the READMEs and install pages now say so.

v0.20.1 — 2026-09-03

Bodies are markdown, and a formatted one survives the round trip. Markdown in, ADF out. create -m, edit -m, comment, the page verbs and the web editors take markdown (headings, lists, code, tables, links) and store what Jira or the Built-in tracker holds (decision 0012, GDK-1384, GDK-1383). The detail renders every body as markdown, so the issues that showed as one grey wall since the cutover read as their blocks again, and the editor has Write / Preview (GDK-1385). Linear gets the same formatting on the wire (GDK-1386).

An edit of a formatted body is lossless. gadak issue prints the markdown (GDK-1394) with a placeholder for each node markdown cannot say (a panel, a mention, an image, a coloured run), and edit -m - puts every node back where its marker stands; delete a marker and that node goes, and the write says so; a stale marker is refused (GDK-1396). edit --adf-file and comment --adf-file send an ADF document as it is (GDK-1395). migrate --from carries bodies as ADF, not flattened text (GDK-1382).

One menu for the list, real names for the shells. The list toolbar has one view-settings menu for layout, sort, columns and “save as view”, where the board and columns buttons used to share a glyph (GDK-1391), and the status breakdown axis is “Status”, second, on every origin (GDK-1390). In the terminal a shell is “shell 3”, not eight hex digits; rename it with F2 or a double-click; the issue header opens or focuses the issue’s shell (GDK-1387, GDK-1195, GDK-1388).

A Store package on Windows, and fixes. build-windows.ps1 --msix packs a Microsoft Store package; the zip is unchanged (GDK-1380). close --resolution works on a new Built-in workspace (GDK-1347); edit --batch takes label / component / fix_version (GDK-1259); avatar initials skip punctuation (GDK-1351); placeholder markers quoted in code are text (GDK-1398); and a terminal resize the kernel did not take is re-issued until it holds, which was the CI flake (GDK-1192).

v0.20.0 — 2026-09-03

The shell is in the window, and it is the issue’s shell. The terminal dock is a band across the whole window now: one horizontal seam under the sidebar, the list and a docked detail alike, a quarter of the height by default, every column of the width (GDK-1352). The session roster is a column on its left, as wide as the sidebar above it, so the window keeps reading as navigation on the left and content on the right (GDK-1355). The dock has an appearance of its own, dark under every app theme, because xterm’s sixteen are a dark-ground palette and nine of them fell under 3.0:1 on paper. Set follow if you want it in the app’s colours; a Settings → Terminal tab covers that, the font, scrollback and the cursor (GDK-1357). The light palette declares its own sixteen (brick, moss, ochre, indigo, plum, teal, readable greys for the two whites) as tokens like any other, overridable through ui.tokens.colors (GDK-1358). The block cursor is ink on its ground rather than a fill (GDK-1359), and the pane paints its ground under the last row too (GDK-1354).

gadak claim typed in that pane binds the shell to the issue, and the roster tab is named by the key. The README and the landing show exactly that now, in gadak’s own pane: the paper-terminal composites are retired (GDK-1353).

A pass over the surface, and back works everywhere. The sidebar is a return path rather than a table of contents: a workspace row on top, quiet sections, one footer row (GDK-1335). The list toolbar is one row until you narrow the view, rows are 36px, the stale age is a number rather than a box, and the palette has one entry point (GDK-1336). Every column screen (Documents, spaces, History, dashboards, the feed) shares one header band (GDK-1339). The detail is one property list under a chip row that keeps only what changes (GDK-1337), its prose has a type scale and a wide-reading toggle (GDK-1311), and the board’s recent actors are faces (GDK-1338). Every control reacts and nothing takes longer than 160ms; hover is a wash of ink over whatever it sits on (GDK-1341). Copy link to this view pastes the Jira navigator URL first and the app links after, the way the issue detail’s copy link already did (GDK-1343); the key of an issue you have opened goes quiet, and one changed since carries a dot (GDK-1344); the breakdown legend folds to +N more instead of squeezing labels to slivers (GDK-1348); Switch to workspace is a palette action (GDK-1340). The first run opens on “where do your issues live?” with nothing preselected, says what gadak is before it asks for anything, and on the built-in tracker the empty list invites the first issue instead of promising a sync (GDK-1342, GDK-1345, GDK-1286, GDK-1287).

The first inbound round shipped in full. @woojing brought five reports (discussion #80, issue #85), and every one is in this release. Thank you. Every place change goes through history (a linked issue, a person, a view, a query), so the browser’s back button does what it says (GDK-1296). The detail’s copy link pastes the origin’s page first (GDK-1290); the settings dialog keeps one width across tabs (GDK-1291); a dock click on a fullscreen window stays fullscreen (GDK-1294); and a gadak:// link naming a workspace this machine lacks is refused in a dialog instead of replacing the app with a 404 page (GDK-1309). Along the way, issue links open on their own origin, one branch per tracker with no fallback across them (GDK-1149, GDK-1308).

Leaving, keeping, and what was fixed. migrate --to linear sends a mirror into a Linear team, idempotently (GDK-1265). gadak backup copies the built-in tracker’s record with the serve running (GDK-1277). A paired workspace mirrors the home origin’s wiki (GDK-1276), and pairing mint refuses a loopback offer that could never bind (GDK-1266). Confluence sync excludes personal spaces only, so team space types stay (GDK-1302). docs/SUPPORT_MATRIX.md is the one table for Jira, Linear and the built-in tracker, a citation per cell (GDK-1300), and the built-in tracker is named once across the CLI and the docs (GDK-1285, GDK-1288).

edit -m - refuses an empty stdin instead of clearing the description (GDK-1360). migrate onto the built-in tracker kept every status name and lost every status category on a mirror whose status_catalog had never been filled: Done and In Progress arrived as open issues, and claim had no in-progress state to land on (GDK-1361). A write typed into a named workspace’s pane no longer opens with warning: workspace: … (from GADAK_WORKSPACE), which the serve had set to name the window’s own workspace (GDK-1362). The freshness chip names the origin’s tracker, not Jira (GDK-1325); the phone’s pairing tab says Built-in (GDK-1321). Three defects the pre-tag audit found are in: init --replace-standalone is accepted again, an issue with no origin page no longer advertises “Open in Built-in”, and migrate --to linear maps a team whose only done state is canceled (GDK-1312, GDK-1313, GDK-1314).

v0.19.3 — 2026-09-02

Two words for two questions. A workspace answered “what kind are you?” with one word, and that word was carrying two facts at once: which tracker the origin is, and whether it runs here. A paired workspace made the seam visible: it reported connected, a word that reads as someone else’s tracker, while its origin was gadak’s own tracker one machine away, and the only way to tell was a separate pairing object. So the field is two now. origin_type is jira, linear or gadak, and transport is local (in this process) or remote (across a serve API). No new vocabulary was invented, because sources already keyed on those tracker names (GDK-1278, GDK-1279, GDK-1280).

gadak status --json, doctor --json, workspaces --json, the served config and the MCP status tool all carry both. kind still ships and still means what it meant, because the skill, the phone and the desktop shell all read it; it is simply the coarser field now.

The flag that creates such a workspace follows: gadak init --local. --standalone keeps working, because a flag already sitting in someone’s script is a contract. It is translated rather than registered as an alias, though, so the help teaches one name instead of two (GDK-1281). The word is gone from the app’s copy, the docs, the skill an agent reads, and the source itself: identifiers, filenames, test names (GDK-1283, GDK-1282). Four places keep the old spelling on purpose, because they are wire contracts rather than vocabulary: the stored kind value, the standalone_data_present error code, the replace_standalone request field, and the onboarding/standalone/ route.

Fixed. migrate warned and carried on when it could not read the source’s attachment bytes, and everything downstream reported success, including the count table, which reads attachments 26 26 because it counts rows and bytes are what went missing. Since the procedure for leaving a tracker is freeze the source, then migrate, that was the ordinary path, not an edge case. It refuses before exporting now, naming both ways forward (GDK-1275). A workspace migrated out of a localized site arrived with two issue types rendering as “Epic” and two statuses as “In Progress”: the seeded defaults stood beside the migrated catalog under ids the display overlay maps to the same word. That left --type Epic with no answer at all (GDK-1284).

v0.19.2 — 2026-09-01

Leaving a tracker, data in hand. gadak --workspace <new> migrate --from <old> exports a synced workspace’s mirror into a brand-new standalone workspace: issues, comments, the full changelog, links, attachment bytes, and wiki pages, ending with a source-vs-migrated count table that includes the derived columns. Reopen counts and epic keys have to re-derive from the migrated history, so equality there is the real proof. Losses are reported rather than silent: bodies migrate as plain text and the report says how many code blocks, media nodes and tables that flattened; links and parents outside the migrated set are counted as dropped. Measured on this project’s own backlog: 1,268 issues, 3,811 history rows, 26 of 26 attachments, every row equal (GDK-1264).

That first full export moved the seed document to JSON: YAML’s emitter writes block scalars its own parser rejects on real tracker text, where a value that starts with newlines, nested deep enough, fails to load back (GDK-1269). The embedded tracker now proves its own snapshots by parsing them before they leave.

An issue can point at an issue in another workspace. gadak ref STD-1 work/NMA-9 records a pointer, stored as a Jira remote issue link on your own origin. Nothing is written to the workspace you point at, so a personal note about a team ticket stays personal. The other half is what makes it worth having: gadak ref STD-1 --list, and the issue’s References section in the app, show the target’s current status, assignee and summary, read out of that workspace’s own mirror on this machine. No network call, no second tab. A target this machine does not mirror still lists, and the row says so (GDK-1032).

The app now says you can make a workspace. Creating, pairing and removing workspaces has lived in Settings → Workspaces since 0.19, but the sidebar’s workspace section only appeared once you already had two, so the main surface never said the feature existed. It now shows with one workspace and carries a “New workspace” row into that panel (GDK-1270).

v0.19.1 — 2026-09-01

The patch where the intuitive query becomes the correct one, written the day after 0.19.0 shipped.

SELECT key, summary, status FROM issues just works now. The mirror’s most common agent miss was structural: the intuitive name held a narrow internal table while the answer lived on issues_full. The names now match the intent: issues is the full view (title and description included), issues_full stays as a compatibility alias, and the physical table steps back to an internal name (GDK-1258). A SELECT * on issues therefore carries two more columns than before. When a query does name a column that lives elsewhere, the error says where: column "summary" exists on issues — query issues, instead of the silence that used to cost three guesses (GDK-974).

gadak claim survives a board with two in-progress lanes. On a workflow where two transitions land in progress, every bare claim used to refuse with both candidates named and no way to pick one. --transition <id|name> chooses the lane, on the atomic route and the Cloud fallback alike. A destination outside in-progress is refused, because claim is not a general transition (GDK-1174). The claim’s other half got faster too: the terminal strip now renames the session on the tick the write landed, instead of waiting out its own two-second poll (GDK-1182).

Two agents on one standalone workspace no longer mint the same id. Comment, history, and attachment ids came from per-process counters seeded once at open, so three concurrent writers handed the same id to three different issues. The counters now live in the working copy itself, one atomic allocation per id, with no persist format change (GDK-1180).

Also: the AUR verify script’s scratch directory moves inside the repo, where Docker Desktop can actually mount it. A green container run that left no .SRCINFO on the host now fails loudly (GDK-1256).

v0.19.0 — 2026-09-01

The release where the issues become a board, and the terminal takes its Beta mark off.

The board. The list you already filter is now also a board: one toggle lays the same issues across columns, with the same filters, the same thirteen grouping axes and the same search. Dragging a card is a real transition, with a menu when more than one status matches. A move made anywhere else, in another window or from an agent’s gadak transition, flies across the board with a landing ring, because on this screen the movement is the only evidence it happened. The three status columns are always all three: “Done is empty” is an answer, not a missing column (GDK-1175, GDK-1176, GDK-1190). A view can say it is a board: saved in board layout it reopens as one, from the app and from the CLI: gadak views save "Sprint board" --jql '…' --layout board, with views open carrying the layout in the deeplink (GDK-1248).

The terminal takes its Beta mark off (GDK-1024), and its sessions belong to issues. gadak claim in a pane’s shell binds that session to the issue, and the tab wears the issue key (GDK-1158). A command in an issue’s body gets a ▶ that places it at that issue’s shell prompt; the board card and the ⌘K palette both open an issue’s session (GDK-1196, GDK-1197). The pane lies down as a dock under the whole row, its chrome is one row, and a tab can end its session (GDK-1194, GDK-1199, GDK-1200). A focused terminal is no longer a keyboard trap either: Ctrl+Shift+[ and ] walk the sessions, Ctrl+Shift+` steps out without closing anything, and Ctrl+Shift+O opens the session’s issue (GDK-1250, GDK-1251).

The phone holds more than one home, and the CLI learned the verbs sessions actually type. A host roster with per-host caches switches between paired machines; workspaces can be created and removed from the web and the CLI; a bundled demo workspace shows every surface with zero pairing. A glance strip answers “what moved while I was away”, and the terminal scrolls under a finger (GDK-1097, GDK-1096, GDK-1098, GDK-1051, GDK-871, GDK-899).

On the CLI: gadak list, next, show, done, recent and pick, measured against what blind sessions reached for, plus memory add/memory search for agent notes, edit --type to refile a misfiled issue, unlink (the reverse verb link never had), and workspaces rm. A write confirms itself, and edit -m refuses to silently flatten a formatted description (GDK-992, GDK-1030, GDK-1205, GDK-1098, GDK-1001).

Refusals got louder, writes got safer, and sync got faster. A JQL clause the mirror’s subset cannot express is refused out loud instead of silently widening the list (GDK-1234). Config and credential saves go through one atomic stage-then-rename owner, so two saves can no longer torch each other (GDK-1233, GDK-1244). A desktop boot that fails before the window opens says so in a dialog instead of exiting silently (GDK-1243), and Linear assignee edits go through the same write surface the UI advertises (GDK-1235). gadak link now points the link the way Jira will display it; the outward and inward ends were swapped, on the CLI and REST both (GDK-1204; #79, thanks @wafe). On quiet mirrors, Jira incremental answers overlap-window echoes from the mirror instead of refetching them, and Confluence incremental asks one CQL pair per tick and stops re-reading bodies whose comments have not moved (GDK-1075, GDK-1074).

Also: pairing offers render as a scannable QR and the desktop gets a Devices tab (GDK-1047); the update dialog announces the version and points at the release page instead of dumping raw markdown (GDK-1246); a standalone workspace stops offering a Jira credential dialog that cannot help it (GDK-1122); and the installed agent skill follows the binary, once a day (GDK-996). A full-codebase audit ran before this tag (parent GDK-1128).

v0.18.1 — 2026-08-26

Closing a terminal closes everything it started. The terminal 0.18.0 shipped learned to clean up after itself the same day. A shell puts a background job in its own process group, so closing a session used to leave sleep 999 &, or a forgotten agent, running forever. The close now walks every process on the session’s terminal once, while the walk can still be trusted. It walks once because in a measured Linux failure a second walk found another session’s shell (GDK-950). When the pane cannot open at all it says why in words, with a retry: no PTY on Windows, a token without the terminal scope, a network drop, on the web and on the phone from the same source (GDK-944).

gadak views open reaches every open window. The CLI’s focus used to be consumed by whichever window polled first, and the window you were looking at stayed put. Two views open in the same second no longer lose the second one: the payload is deduped on what it says, not just when it was written (GDK-960, GDK-981). A CLI exit path that used to leave a stale “open” marker behind clears it (GDK-971).

gadak keeps a log file, and doctor hands it to you. A Finder-launched app used to discard every diagnostic line; now gadak doctor names the file and quotes its recent errors. Credentials are scrubbed before a line is written (GDK-967). The agent skill teaches an agent to diagnose the wall it hit and to report the friction instead of silently working around it (GDK-968), and the hosted demo’s mirror is published as a file you can download and open in your own gadak (GDK-975). The benchmark tables were re-measured on a quiet machine, on the corpus the demo actually ships, and a release audit of this delta ran before the tag (parent GDK-980).

v0.18.0 — 2026-08-26

A terminal, inside gadak. ⌘K → Terminal, or `Ctrl+“. It is a real shell in the same window as your issues, so you can run a coding agent there and watch it move the board next to it. Same terminal in the web tab, in the macOS app, and on a paired phone. Korean composition lands on the cursor, where a terminal canvas does not make that automatic. It ships as Beta: useful, with rough edges named (GDK-862, GDK-864, GDK-865, GDK-892, GDK-895, GDK-956).

A token can open a shell and nothing else. gadak pairing mint --scope terminal is the only kind that opens one; a serve or origin token opens none, though a serve token now reaches the whole mirror REST rather than a 13-path allowlist. Revoke a terminal token and the shells it opened close within seconds, and are told why. Loopback still needs no token at all (GDK-863, GDK-883).

The phone app is something you can use. Issues in your own saved views, wiki pages beside them, search that shows page hits, an issue detail that lands on the thread, and notifications only for what is actually yours: assigned, mentioned, reopened. It reaches the terminal too, over a second token, and unpairing forgets that shell too. Internal TestFlight builds ship in one command (GDK-805, GDK-867, GDK-870, GDK-879, GDK-884, GDK-885, GDK-886, GDK-887, GDK-888, GDK-905, GDK-906, GDK-907, GDK-908, GDK-910).

gadak says what it will mirror before you install it. The wiki was always opt-in and always per-space (gadak init --spaces ENG,PROD, or Settings → Sources), but nothing said so until you had already installed and run a sync. Someone told us they had not tried gadak because a whole Confluence looked like too much to mirror. It never was (GDK-964). The changelog you are reading is on the site now, in both languages, rendered from the repository rather than copied, plus the search-engine basics the site never had: canonical links, a sitemap, and structured data for the releases. gadak dev --help lists every verb it has, and gadak pairing lists, like every other list command (GDK-946, GDK-947). The agent skill carries a complete, working dashboard example instead of pointing at a file that was never installed beside it (GDK-963).

gadak create --type Bug works on a non-English Jira. It used to fail once on every localised site and make you look up the type id. Names, ids, epic/subtask, and a small locale table all resolve now; two matches is a clear error rather than a guess (GDK-741). A dashboard link opens an issue without losing the wall (GDK-880). gadak open no longer scans ports to find a running serve (GDK-859). WebSocket upgrades are origin-checked (GDK-860). One stale cached row can no longer blank the whole UI (GDK-835).

v0.17.3 — 2026-08-25

The phone stopped being a skeleton. A paired iPhone reads your mirror over its own serve pairing scope, a one-way door: that token cannot ride the origin passthrough, and an origin token cannot dump the mirror. pairing mint works on a connected workspace. On the phone: a quiet queue as the first screen with real status names, pairing that proves the connection it claims and explains each failure, search that answers before you type (recent searches, your saved views as chips), an issue detail whose comment draft survives a failed send, and notifications only for assigned, mentioned and reopened, silent while you are looking at the app (GDK-796, GDK-797, GDK-798, GDK-799, GDK-800, GDK-801, GDK-802, GDK-837).

Spacing, layout and type are yours too, not just colour. ui.tokens grew three more axes, and setting one no longer risks the rest: each is a key-wise merge, so a bad write leaves the config untouched. One token is a path of its own: gadak config set ui.tokens.type.terminal 15px, no JSON and no quoting, with an unknown name refused rather than stored as a typo. gadak config get ui.tokens.dim-catalog lists every name with its default, its range, and what it has to move together with (GDK-842, GDK-849, GDK-850, GDK-852, GDK-853).

Validation warns and saves instead of refusing. Contrast, colour distance, deuteranopia and the token relations all still run and still tell you what you are about to get, but only what the machine genuinely cannot honour is rejected. The warnings carry the next move as well as the diagnosis: a contrast line names the palettes that fail and where to fix them, a type line prints the whole ladder that has to move together. Any look can be undone with one CLI line (GDK-856, GDK-857, GDK-858).

A dashboard link can open an issue. A wall can now navigate the app to any of its own routes (an issue, a saved view, a filtered list, a search), and an external link opens a new tab instead of replacing the wall (GDK-854).

v0.17.2 — 2026-08-25

Your agent can build you a dashboard. One HTML document plus named queries, saved like a view and rendered full-tab in the running web UI. The host runs the SQL (or JQL) and hands the rows in; the page itself never reaches the network. Saving re-renders an open tab in about a second, and new mirror data re-pushes on its own. Charts work offline: uPlot ships inside gadak, so there is no CDN and no loosened policy (GDK-781, GDK-782, GDK-792, GDK-793). A dashboard can no longer paint over the issue list (GDK-815, GDK-821), and it answers Esc like everything else (GDK-827).

Any chart library you want, downloaded once. gadak dashboards lib add <url> fetches a library, pins its hash, and serves it locally, re-hashed on every request, so a file tampered with after the fact fails closed instead of running. Dashboards name the libraries they use; ones that do not are unaffected. three.js stopped shipping inside the binary and became the documented example instead, which is 750 KB off every download (GDK-808).

Colours are yours. ui.tokens, ui.tokensByTheme and ui.dataColors let you repaint the window, with ui.tokens.catalog to discover the names. Writes are checked against the same contrast rules the shipped palettes had to pass, an open tab repaints without a reload, and a boot cache means a customised install never flashes the default palette first (GDK-785, GDK-786, GDK-787, GDK-791).

Every answer names the source it came from. gadak sql stopped answering from a stale copy: an unprefixed table name now falls through to the live local.db rather than a snapshot frozen at migration time, which had been answering quietly and wrong (GDK-824). The staleness warning names which source is stale: mirror last synced 154h ago came from the oldest row across every source, so one quiet Confluence space made the whole mirror read as six days old while status showed a watermark ten minutes back: two screens, opposite stories, and no way to tell which to believe. It now names the source and prints the same timestamp status does (GDK-810). A page id you read is a page id you can write to: search prints it, the JSON help admits pages exist, and the agent recipes emit the id the origin actually accepts (GDK-816).

Two typos the CLI used to swallow. gadak create GDK "…" filed an issue whose title began with a project key; it is now refused with the --project spelling, and only when the first word really is a key this workspace knows. config set projects accepted any string; keys are shape-checked, the site is asked whether they exist, and status and sync name both sides of a scope that has drifted (GDK-594, GDK-809). A collapsed documents tree stays collapsed across a sync (GDK-817). The feed takes the column instead of overlaying it, so Esc from the feed lands on the list. Fourteen error messages across three languages now name the next move rather than only the problem (GDK-828, GDK-829, GDK-831). The excerpt a list shows and the text search indexes come from one place, so they cannot drift apart (GDK-814).

v0.17.1 — 2026-08-24

Two gadak processes can share one mirror. A day of using gadak on a 20,000-issue mirror found every way two of them could end up waiting on one file. A standalone workspace keeps its record in SQLite: the embedded tracker writes to origin/issuetap.db, one transaction per write, instead of rewriting a whole YAML file on a timer. An existing YAML seeds it once and is left alone as your rollback; export still speaks YAML. Backup is that file: stop the app and copy it, or use sqlite3 .backup while it runs (GDK-202).

“Database is busy” tells you who is holding it. A write that reached Jira no longer fails just because the local re-read collided with another process, and a genuine refusal names the neighbour (another app, a serve, a CLI) instead of an error code. gadak doctor lists them. Browsing history took its own connection, so reading no longer queues behind a sync, and an agent’s reads wait for the file rather than failing instantly (GDK-740, GDK-753, GDK-754, GDK-757, GDK-755). It is faster where it was slowest, measured at 20k issues: gadak issue KEY reads that one key instead of loading the mirror, search --jql resolves people narrowly, on the CLI and on the server, and doctor samples instead of scanning every document (GDK-747, GDK-748, GDK-749, GDK-756).

Exclude works on every filter. A ⊘ on any value in any picker (Alt-click too), replacing a modal toggle that only some menus had. Copy JQL writes not in where JQL can say it and tells you which axes it left out, and search --jql matches the same negations (GDK-771). Narrow windows stop clipping: an audit of every seam below 1100px closed three, a chip that would not hide, row columns cut mid-character, and a minimum width that disagreed with the layout it was supposed to describe. A CI check keeps all three closed (GDK-758, GDK-766).

On gadak.dev: a Korean browser is offered the Korean page: a suggestion, never a redirect, and the answer is remembered (GDK-770). Plus llms.txt for agents reading the site, and landing media that shows the product at readable scale instead of full-screen video (GDK-751, GDK-752).

v0.17.0 — 2026-08-23

An issue knows its pull requests. PRs, commits, deployments, builds and the people on them, mirrored from a connected site and writable on a standalone one. gadak dev scan sweeps a repository’s PRs into an issue in one pass, gadak dev link writes one, and the web opens a GitHub link in-app. Those links survive the next sync. When the panel is empty it says why (GDK-495, GDK-496, GDK-497, GDK-527, GDK-531, GDK-536, GDK-537, GDK-538, GDK-539, GDK-540, GDK-541, GDK-555, GDK-562, GDK-589, GDK-592). Issue links are no longer a reason to leave the app: gadak link A B --type blocks, or the detail panel (GDK-19, GDK-85).

Write verbs that do what a project requires. create and edit take --field alias=value for required custom fields, and the create dialog learns what this project and this issue type actually demand. transition carries --resolution, --field and a comment. edit writes fix versions and components by name. assign takes a name or an account id, not only an email. A wrong-typed field is refused rather than written as an empty string. A rejected parent lists the epics you could have picked (GDK-254, GDK-330, GDK-509, GDK-513, GDK-514, GDK-515, GDK-516, GDK-517, GDK-635, GDK-643). A write that reached Jira counts as a success even if the local re-read right afterwards did not (GDK-740). Bulk reads take many keys, or --keys -, with nothing silently dropped (GDK-328, GDK-425). gadak claim KEY takes an issue in one move, and gadak issue shows how long the work sat: wait 3d · progress 5h (GDK-591).

Writes carry who made them. GADAK_ACTOR names the agent, and the web marks bot work with a badge, so a machine’s edit can be told apart from yours. A standalone workspace speaks your language, and a restricted issue looks different from a public one (GDK-519, GDK-586, GDK-588, GDK-590, GDK-593, GDK-597). For agents there is more: gadak pick chooses work, gadak recents walks back what the CLI has read, gadak sync --if-stale 15m is the session opener an agent can call blind, batch writes answer per key, honestly, and closing an issue is one round trip that is safe to retry (GDK-500, GDK-501, GDK-502, GDK-503, GDK-598, GDK-599).

A workspace stays chosen, and the window behaves the same everywhere. gadak workspace use <name> stores a default. Pairing tells the truth about what it is and what failed, a bound workspace cannot be quietly repointed at a different site, and replacing an origin takes its derived rows with it (GDK-418, GDK-433, GDK-449, GDK-452, GDK-453, GDK-490, GDK-561, GDK-677, GDK-678). rm gadak.db no longer costs you anything: saved views, visits and search history moved out of the mirror, which is supposed to be the throwaway half (GDK-105). Korean search finds the word inside the compound; fix versions keep their ids and the project’s release catalog reaches the mirror, sprint is a column you can query, and JQL parent = / parent IN filter locally (GDK-259, GDK-444, GDK-518, GDK-521, GDK-532, GDK-329).

Esc closes the thing it was aimed at and nothing else. Four type sizes and nothing between them. Empty is a state with words, not a blank. A transition that needs a screen asks inline; components and parent edit in place; a story shows its children. There is one kind of saved view. A read that finishes quickly paints no skeleton at all. And a full Japanese catalog (GDK-83, GDK-86, GDK-121, GDK-129, GDK-130, GDK-316, GDK-437, GDK-604, GDK-613, GDK-617, GDK-626, GDK-737, GDK-738, GDK-739). On the desktop, a second launch raises the window you have instead of starting a second one; on Windows, gadak:// links work, install-cli speaks Windows, and the app stops claiming it notified you when it did not (GDK-349, GDK-350, GDK-351, GDK-353, GDK-658, GDK-700).

The network was audited too. An empty host counts as a non-loopback bind, so serve demands --allow-remote for it like any other exposure (GDK-542). Linear’s rate limit is retried rather than fatal, and a Linear-only workspace is a configured workspace (GDK-263, GDK-654). The Web Push client is gone: it called endpoints the server answers 404 to, and vendor push services are outbound traffic this project does not make (GDK-711). gadak’s own backlog is public, at gadak.dev, with a front door, a demo beside it, and a page explaining that Windows warning (GDK-211, GDK-389, GDK-676).

v0.16.1 — 2026-08-20

Linear is a third tracker, and gadak writes to it. This release finishes what 0.16 started. A "linear" block in your workspace config and gadak sync --source linear mirror issues, comments, labels and attachments. Writes route by whichever origin owns the row. What Linear cannot do yet is refused outright rather than half-applied. Jira, standalone and Linear all answer the same write verbs (GDK-263, GDK-359, GDK-360, GDK-361). The wiki stops being read-only in the same release: you can create a page, edit its title or body, and comment on it, all through the origin, from the CLI or the REST API (GDK-344, GDK-380, GDK-381, GDK-382).

Two gadak processes can no longer both write a standalone workspace. The desktop app advertises its origin the way serve does, so an app and a CLI cannot both hold the record file. An acknowledged write is on disk before you get the answer, and a write that could not be persisted returns an error instead of success. A standalone failure no longer reports itself as a missing credential, and converting a workspace says what conversion actually does to your local-only issues (GDK-241, GDK-333, GDK-340, GDK-342, GDK-343, GDK-345, GDK-346, GDK-347, GDK-348).

Agents and docs learn that standalone exists. The embedded skill knows the word, and the CLI says which origin it means. transition names each target’s status_id and accepts the one the read path just handed out; that round trip is where agents kept failing. issues_full gained description_text, and a standalone init fills the mirror so nothing starts empty (GDK-239, GDK-312, GDK-313, GDK-363, GDK-364, GDK-365, GDK-366, GDK-367, GDK-368, GDK-371, GDK-376). The install page covers standalone, the FAQ no longer tells you to rm -rf ~/.gadak, the network has its own page, and export/import finally has a paragraph (GDK-271, GDK-372, GDK-373, GDK-374, GDK-375, GDK-601).

v0.16.0 — 2026-08-19

A workspace without an Atlassian account. Standalone: the origin is a minimal tracker that runs inside gadak and travels with it. The mirror is still a disposable cache, and every write still goes through the origin. The only change is who the origin is. A workspace is bound to one origin, so connecting a credential cannot quietly repoint it somewhere else. Standalone wikis write through the same path (GDK-183, GDK-237, GDK-238, GDK-247, GDK-267). A read-only Linear client landed as groundwork, deliberately not wired to workspaces yet. That is 0.16.1 (GDK-258, GDK-261, GDK-263, GDK-274).

Windows and Linux. gadak stops needing a Mac to run. Windows gets a portable pack, an installer path, a working install-cli, a Scoop manifest, and gadak:// links that survive first launch. Linux gets a tarball install beside brew and an AUR packaging kit. Omarchy gets a bar widget showing what changed in your mirror (GDK-115, GDK-116, GDK-208, GDK-209, GDK-225, GDK-229, GDK-246, GDK-293). gadak notices a new release, says the right thing for your platform, and renders the notes in the app. It never updates itself (GDK-213, GDK-214, GDK-215, GDK-216). A cold open no longer serialises everyone behind it, a contended write waits instead of failing immediately, and a background sync stops outliving the server that started it (GDK-270, GDK-282, GDK-305). The hosted demo opens on the product, and feedback channels live in Settings and the macOS Help menu (GDK-335, GDK-336).

Edit an issue where you read it. Due dates set and cleared from the detail panel, with Jira’s refusal shown as a sentence you can read. Descriptions edit as plain text, with a guard before anything rich gets destroyed. p opens a priority menu wherever s/a/l already work. What is editable comes from the issue’s own metadata rather than a fixed list, so your site’s custom fields are included (GDK-82, GDK-223, GDK-249, GDK-250, GDK-251, GDK-322, GDK-323, GDK-331, GDK-332). The palette can file an issue from whatever you just typed. Required fields with obvious answers are no longer asked, and posting a comment now confirms that it was posted (GDK-217, GDK-218, GDK-300, GDK-301, GDK-302).

A non-English Jira stops silently returning nothing. Status, priority and issue type key on ids and categories everywhere instead of display names. status = 'In Progress' returns zero rows on a Korean account; that class of quiet wrong answer is closed (GDK-161, GDK-248, GDK-272, GDK-275). Korean mid-compound search works too (GDK-259).

v0.15.2 — 2026-08-17

Every field the settings dialog edits is also a CLI verb. gadak config list | get | set and the settings API go through one table, so they cannot disagree. An agent can now set up a workspace end to end. Themes live in the workspace config file, so picking one in the UI and setting it from a terminal do the same thing (GDK-190, GDK-193).

Three dark themes. dark is a neutral-cool charcoal, ink is a new blue-black, and ember keeps the previous warm dark exactly as it was (GDK-190).

Search and menus stop surprising you. A bare number finds that issue in any project, on every search surface (GDK-186). The settings dialog stops repeating its mirror block above every tab (GDK-188). Menus no longer install things without asking. Settings → Integrations does that, and lists what is already installed (GDK-189, GDK-191).

v0.15.1 — 2026-08-17

Three ways in, none of them needing a checkout. gadak raycast install carries the Raycast extension inside the binary, so a brew or app install needs no checkout (GDK-182). The ⌘K palette is never blank: an empty query shows recently updated issues under recently viewed, plus your saved views (GDK-184). Settings → Integrations (desktop) lists the agent surfaces gadak installs into, detects honestly what is already there, and shows a live log (GDK-185).

v0.15.0 — 2026-08-17

Any part of gadak can be handed over as a link. gadak:// deep links, with every place in the app addressable. gadak also produces the links it consumes: a copy-link action in the UI, and gadak issue KEY --link on the CLI (GDK-119, GDK-124, GDK-163, GDK-164). Search is fast enough to drive another app’s UI: typing an issue key finds that issue, and on a 20,000-issue mirror the worst case went from 1.6s to 110ms. That is what makes a launcher extension feel local (GDK-117, GDK-166, GDK-170).

A dark theme. Warm ground, ink foregrounds, the same paper metaphor as light, and no flash on first paint. Both palettes clear the same measured floors: status colours stay distinguishable in normal and colour-blind vision, and success and failure are never told by colour alone (GDK-154, GDK-156, GDK-157, GDK-158, GDK-159, GDK-162, GDK-171).

The list behaves like a list. The right side of a row is a column you can scan, the last row stops being cut in half, Esc closes what you are looking at, and a panel that covers the list says so (GDK-128, GDK-131, GDK-132, GDK-133). Korean input works in the search box: a half-composed syllable is not a query, and chosung matching is gone product-wide, because it matched things you did not mean (GDK-168, GDK-169). An issue can name its parent, with gadak create --parent and gadak edit --parent writing the sub-issue relationship through Jira (GDK-19, GDK-86).

At the edges, the hosted demo stops advertising verbs it cannot answer (GDK-52). A read-only home is a warning, not a refusal to start (GDK-149, GDK-173). Copy means copied, an attachment is fetched at most once, and the desktop app stops loading its runtime twice (GDK-150, GDK-177, GDK-178).

v0.14.2 — 2026-08-16

A rejected or expiring token says so up front. Every token trap is named before you paste rather than after the 401 arrives, and a rejected token is recoverable without having to write anything first (GDK-68, GDK-69, GDK-98). Expiry is warned about before the sync fails (GDK-67).

Setup and the skill install finish where you leave them. Picking no projects is a choice, not an unfinished form (GDK-99). gadak skill install treats an upgrade as an upgrade, and the embedded skill knows the verbs the CLI actually has (GDK-91, GDK-92).

Existing surfaces report what they are doing. A tick over an unchanged Confluence reads zero page bodies (GDK-113), and gadak issue <KEY> --derive shows where the derived columns came from (GDK-111). History keeps its order (GDK-26), gadak sql warns on a stale mirror (GDK-90), and opening a mirror repairs a search index this build cannot write (GDK-112). The browse pane yields to Escape (GDK-78), and search help works on touch (GDK-53).

v0.14.1 — 2026-08-15

The first CLI write verbs: gadak create, gadak attach, gadak edit. One day of using gadak on gadak’s own backlog, shipped as it landed.

The macOS app is notify-only, and the demo works where people tap it. The in-app self-updater, which was never exercised, is gone, and this release deliberately ships no desktop zip (GDK-58, GDK-61). The hosted demo runs inside in-app browsers, with a first paint readable at phone width (GDK-23, GDK-51).

Failures say what happened. A truncated key list says how many were dropped, and a rejected credential stops the watch loop for every source rather than one (GDK-24, GDK-35, GDK-48). Priority colours read the rank, not the account’s language. Keystrokes during boot are held rather than dropped (GDK-46, GDK-76).

v0.14.0 — 2026-08-15

Agents get a surface they can build on. gadak_search takes query, every tool error starts with ERROR: and echoes the keys it got, and a response over the size cap sheds the oldest comments and says truncated rather than lying about completeness. Three things are a promise you can build on: issues_full plus the RECIPES queries, gadak sql stdout, and views open --keys -.

Numbers, with the rows where gadak loses. Measured against a live 2,853-issue Cloud project: 42× on a simple filter, 162× on an epic GROUP BY, and a reopen count that takes about twenty minutes over REST against 14.5 ms locally.

brew install midagedev/tap/gadak is the app now; gadak-cli is the CLI-only formula. gadak export / gadak import round-trip what you would actually miss: saved views, watches, favourites, in a file that carries no credentials and no site URL. Plus a Korean README, and a settings dialog that stops claiming things about project selection that were not true.

v0.13.0 — 2026-08-14

One search box that searches everything, and a history that outlives the mirror. ⌘K queries every issue and document in one index, ignoring the filter chips on the list; the box above the list keeps its old job, narrowing what is already there. Issues, documents and searches land on one timeline in ~/.gadak/local.db, so throwing away the mirror does not throw that away, and an agent can join what you visited to what you have in a single gadak sql.

The window follows the agent, and a Jira URL brings its filters with it. An arbitrary set of issue keys is a first-class view, so gadak views open --keys - puts an agent’s answer on your running window. gadak views open opens in gadak; gadak open leaves for Jira. Hosts without a shell get the same through a new MCP tool.

A navigator URL or a jql= clause applies the matching chips, Copy JQL is the way back, and anything in the unsupported subset is listed rather than silently dropped. Your Jira saved filters show up in the sidebar, and gadak views lists, shows, opens and saves them.

Wiki scope is per space, and the rest is repair. Each Confluence space carries its own watermark, a newly selected space backfills in full, and a space that leaves the scope is removed. Comment-only wiki edits reach the mirror, an unchanged page stops bumping its version, and a deleted issue is tombstoned by a single-item sync. An unknown --profile errors with the real list, and a failed mirror re-read after an upload returns the documented error.

Two fixes came from outside. People are matched by account id rather than by email, so person filters no longer depend on your site making email addresses visible, across JQL, saved views, filters and the member directory (#1, thanks @elppaaa). The macOS window can be dragged (#2, thanks @wafe).

v0.12.0 — 2026-08-13

Paper, not a dark dashboard. gadak is a strand (가닥): uncoated paper, sumi ink, one 쪽빛 thread. The mark is 가 drawn as two strokes, and the crystal-ball dashboard and the TUI are gone.

The rename reaches the binary, home directory (~/.gadak), environment prefix (GADAK_*), MCP tools, module path and desktop bundle id. An existing ~/.scry tree is renamed on first launch, and SCRY_* is still read wherever the GADAK_* equivalent is unset.

Labels, priority and the title are editable. Labels stay visible on the list, edit on the issue, and apply to a selection from the bulk bar (l, beside s and a). Priority writes by id from the site’s own catalog. Workspaces work in the desktop app, and every workspace with a credential gets its own sync loop. Document lists stopped freezing on a large mirror: 4,433 ms to 68 ms on a 10,000-page window.

Smaller things. The native title bar is gone; window controls moved into the sidebar. gadak skill install embeds the Claude Code skill without needing MCP, and gadak install-cli puts the running binary on your PATH. gadak doctor prints redacted diagnostics you can paste into a bug report. gadak api is the raw Atlassian REST escape hatch, refused at a foreign host.

v0.9.0 — 2026-08-06

A name in ⌘K opens a person. The people axis is web-only this version, and the demo has more than one person in it. Search says why it matched, with a snippet of the field that hit, and every page in the list carries a one-line body preview.

One type scale and one orb. A real type scale, muted text at 6.2:1, one monochrome icon family, and an avatar palette where red stays reserved for meaning. The wordmark’s sphere sits on the x-height, every icon derives from that same drawing, and the crescent logo is retired. The geometry matches: a two-step height grid, corner radius that follows nesting, pinned detail-panel headers, and consecutive comments by one author grouped under a single header.

v0.8.0 — 2026-08-06

Gadak.app, the macOS desktop app. The web UI in its own signed, notarized window, with no local server at all; a second launch focuses the running window, and the bundle carries the CLI. Sync starts after in-app onboarding, without a restart.

v0.7.0 — 2026-08-06

An agent gets pinned to the right mirror. gadak mcp install <client> pins the current profile and absolute binary path into an MCP host registration. The local API stops being an open proxy: cross-origin writes and DNS-rebinding reads are rejected, and mirror file permissions tighten to 0600 / 0700 on open.

The window gets faster and easier to live in. serve opens http://gadak.localhost when the resolver maps it; a busy listen port hands off to a running gadak or falls back to a free port. Space names, a docs UX wave (Viewed / Updated / By author), and an epics built-in view. Keyboard triage, a freshness chip, a warm-boot cache, and an interaction performance gate against a 10k-issue fixture. Confluence sync hardened for real sites.

A face: wordmark, logo, and a favicon the app never had. The README leads with the live demo, the demo speaks English (Korean narrative pages remain for CJK search), and docs/FAQ.md answers the hard questions with evidence.

v0.6.0 — 2026-08-06

Confluence pages join the items spine. A second source on that spine, with docs in the web UI and a TUI docs navigator (D). Page labels are collected on fetch and shown everywhere pages appear.

Issues grow an honest epic hierarchy. A derived epic_key (the nearest level-1 ancestor) groups a sub-task under its epic rather than its story, and in the web UI it becomes group labels, row chips, breadcrumb, and rollup. Phones render the desktop layout instead of a squeezed column.

v0.5.0 — 2026-08-05

Workspaces, a neon TUI, and Korean that is found. serve mounts every profile under /w/<name>/. The TUI gets ambient animation, mouse support, a palette, and match highlight. Search does prefix match, so inflected Korean is found.

v0.4.0 — 2026-08-05

Three surfaces say more about what they are doing. The TUI edits custom fields, with Jira-allowed values only. An update notice does a daily anonymous check on every surface, with opt-out. The hosted-demo service-worker handshake times out cleanly and says so when the browser cannot run the demo.

v0.3.0 — 2026-08-05

Custom fields configure themselves. The first full sync discovers and configures custom fields itself, and the filter axes come from what it found, including multi-select editors. Sync progress carries a real total, projects are optional on sync, and sync history sits behind the sidebar timestamp.

v0.2.1 — 2026-08-05

Signed binaries, and a demo that says it is one. The macOS release binaries are signed and notarized. The hosted demo simulates writes locally, says the change was not saved, and carries copy that identifies the surface as a demo.

v0.2.0 — 2026-08-05

The foundation, and a demo with nothing to install. The storage schema, plus HTTP, sync and agent contracts, and the SQLite implementation with WAL, FTS5, and the derived-field calculator. gadak serve serves the built UI and refuses a non-loopback bind without --allow-remote. Built-in views key on axes that mean the same thing on every Jira site: resolution and reopen detection key on status category, not a localized name. The hosted demo is a static snapshot served by a demo-only service worker: no binary, no account.

Keeping up with the site. gadak serve starts the sync watch loop by default when a credential is configured, and gadak install-service writes a launchd agent or systemd user unit; one OS desktop notification may fire for new personal feed events. The personal watch feed is computed from the mirror at query time over a 30-day window. gadak’s own call volume shows in gadak status and the settings runtime panel, hidden while the count is zero.

Handing a workspace to someone else, and the command line that does it. gadak team export / import writes the views, field map, group rules and thresholds a team agrees on; credentials never travel, and a file containing credential keys is refused on import. gadak snapshot builds a shareable copy: --spread restates timestamps across a window while preserving every issue’s internal ordering, --scale clones issues onto new keys, --now pins the clock, and a credential scan runs before the file is published.

gadak fields reports which custom fields are actually populated. Per-command help is generated from the FlagSet, so it cannot drift. Favorites live in the mirror, so gadak sql and agents can see them; the hosted demo falls back to local storage. TUI parity: feed focus tabs, saved-view sort/dir/group_by, and priority sorting keyed on priority_rank.