What's New
Release notes for K2. Updates are published to GitHub.
v0.40.140
Latest0.40.140 — Project pane shortcuts follow Message agent
On a project board, ⌘1–⌘9 now follow When moving between workspaces, auto-select. If that’s Message agent, the shortcut lands in that pane’s message box — not the terminal. Terminal still focuses the grid when that’s the setting.
---
v0.40.139
0.40.139 — Skin guests can have an email for password reset
Skin Access guests have an optional email. Username is still required. Forgot-password only mints a reset when that guest has both a password and an email — then the site (not the browser) gets the address to send mail. Guests can type the username or the email on login and forgot. K2 still does not email guests. Official --skin still cannot mint or send. Grid and the terminal stay off.
Owner sets email in Skin Access or k2 skin user add --email / k2 skin user email. Empty email clears it. Guests with a password but no email cannot use forgot until the owner fills the address.
---
v0.40.138
0.40.138 — Skin guests can reset and change their password
A logged-in skin guest can change their own password. A guest who forgot can set a new one from a reset link the site operator sends — K2 does not email guests. Official k2 publish run --skin hosts /reset and saves the new password; it cannot mint or send the mail. Old sessions die. The pass stays on the server (cookie), never in the browser. Grid and the terminal stay off.
Owner password in Skin Access is unchanged. Guests with no K2 password reset at their identity provider.
---
v0.40.137
0.40.137 — Skin guests can CRUD that agent's database tables, as themselves
A logged-in skin guest can list tables and read, insert, update, and delete rows in that agent's Postgres — that workspace only. Store on Documents does not grant store on Sales. Unassigned guests stay Thread-only. The pass stays on the server (cookie), never in the browser. Guests never get a database password. Grid and the terminal stay off.
k2 publish run --skin proxies GET /cli/db/tables and GET|POST /cli/db/rows on the published origin. Session reads and writes stamp k2.skin_principal so dump RLS can filter per guest. Named platform tokens cannot use store. _k2_store writes stay off.
---
v0.40.136
0.40.136 — Skin guests can read that agent's store, as themselves
A logged-in skin guest can list, get, and query that agent's store — that workspace only. Store on Documents does not grant store on Sales. Unassigned guests stay Thread-only. The pass stays on the server (cookie), never in the browser. Guests never get a database password. Grid and the terminal stay off.
k2 publish run --skin proxies GET /cli/store/list, get, and query on the published origin. Session reads stamp k2.skin_principal so dump policies can filter per guest. Named platform tokens cannot use store. Writes stay off.
---
v0.40.135
0.40.135 — Skin guests can read wiki on the agents you grant
A logged-in skin guest can list and open that agent's wiki — that workspace only. Wiki on Documents does not grant wiki on Sales. Unassigned guests stay Thread-only. The pass stays on the server (cookie), never in the browser. Grid and the terminal stay off.
k2 publish run --skin proxies GET /cli/wiki/index and GET /cli/wiki/note on the published origin. Fleet wiki, seed, serve, and public chat stay off. Chat history and Chatter are not in this cut.
---
v0.40.134
0.40.134 — Skin guests can use Tickets on the agents you grant
A logged-in skin guest can list, open, comment, answer, and resolve Tickets on that agent only. Tickets on Documents does not grant Tickets on Sales. Unassigned guests stay Thread-only. The pass stays on the server (cookie), never in the browser. Grid and the terminal stay off.
k2 publish run --skin proxies those Ticket routes on the published origin (/cli/feedback/list, show, create, comment, answer, resolve). Waiting-count and assign stay off. Wiki, chat history, and Chatter are not in this cut.
---
v0.40.133
0.40.133 — Skin guests can use files on the agents you grant
A logged-in skin guest can list, read, write, and watch files in that agent's folder — not the whole box. Files on Documents does not grant files on Sales. Unassigned guests stay Thread-only. The pass stays on the server (cookie), never in the browser. Grid and the terminal stay off.
k2 publish run --skin now proxies those file routes on the published origin (read-dir, read-file, write-file, and a per-agent live watch). Login still guards Thread and files; / and /assets/* stay public.
---
v0.40.132
0.40.132 — Skin access is per agent, then what they may do there
Skin Access roles grant a guest specific agents, and specific functions on each one (Thread, files). Files on Documents does not grant files on Sales. Guests still log in with a username and password; they never copy a key. Grid and the terminal stay off.
k2 publish run --skin serves your login.html when that file is in the folder (otherwise the bundled sign-in). Guests can tap Thread choice cards and fill secrets. A workspace Agent-tab toggle (off by default) lets that agent run existing k2 skin / k2 skin-token commands.
---
v0.40.131
0.40.131 — Skin platform tokens are not per-guest keys
Skin Access mint is a named platform token (k2 skin-token create --name vercel --agent sales), not a key hung off a guest. Guests still sign in; that session is their access. Login does not hand them a copyable key. Grid and the terminal stay off. Existing static mints become platform tokens on first boot (name from the old username).
---
v0.40.130
0.40.130 — Skin gateway login page and no stale assets
k2 publish run --skin always serves a sign-in page at /login (session expiry no longer 404s). Static files send Cache-Control: no-store so a published UI updates without a hard refresh. / and /assets/* stay public — login only guards Thread; do not put private files in that folder.
---
v0.40.129
0.40.129 — Host a skin UI with k2 publish
k2 publish run puts a login + Thread site on a nested URL (https://). Guests use the username and password from Skin Access. The pass stays on the server — not in the browser. Grid and the terminal stay off. Your own static files: --skin . k2 skin is still the guest list, tokens, and rooms; it does not serve the site. Caddy / skin. as a special hostname is not required.
---
v0.40.128
0.40.128 — Granted workspaces run SQL as that workspace’s Postgres role
A workspace granted onto a shared database — and k2 store from that workspace — connect as that workspace’s Postgres role, not the owner’s agent and not the migrator. Dump RLS keyed to the role now applies to both the agent (k2 db dsn / k2 store) and a human who shares that DSN. The owner still connects as {dbname}_agent. Migrate, dump, and restore stay the migrator. k2 db dsn --workspace fetches that workspace’s LOGIN (owner backend), and restore recreates grant roles so dump policies bind on a fresh box.
---
v0.40.127
0.40.127 — Agents can publish from a cell
k2 publish run works from an agent session (scoped cell token), not only from an owner shell. Status, ps, and Connect are unchanged.
---
v0.40.126
0.40.126 — Skin agent display names
GET /cli/skin/agents includes displayName (guest-facing label; handle stays the id). Agent Thread posts stamp the room handle, not k2. Skin guest from is still the username.
k2 msg agent::host --inbox-wake uses the same federation plane as live k2 msg. Connected peer is the gate — not a Connect token. Wake is a tray pointer, not file bytes in the PTY.
The create-DB grant lives on each workspace’s Agent tab (Settings → Workspaces), not inside Settings → Data.
---
v0.40.125
0.40.125 — Skin files read/write + live events
A customer key can list, read, write, and watch that agent's folder when you mint files:read / files:write — same rooms as Thread. Missing files cap stays Thread-only. Empty rooms stay dark. Grid/PTY still never. Not host-wide /cli/sessions/events. Skin Thread posts inject [from into the agent's terminal; via=compose stays 403.
---
v0.40.124
0.40.124 — Skin agent rooms, study, store 403 names the DB
Skin Access keys name which agents may use Thread. Empty list is no Thread, not every agent on the box. New mint requires --agent. Existing keys go dark on Thread until you assign rooms (same secret). Overlay WS 403s before upgrade if that conversation is not the allowed agent’s pinned Chat. Sidecar chats (sales/reviewer) stay 403. Grid still never.
Skin Access username/password is plumbing: the skin POSTs /cli/skin/login and gets an HttpOnly k2_skin_session cookie. The skin owns the login UI. Static k2skn_ keys stay for servers. This is not Connect login (k2_session / Server Access).
CLI. k2 study is daemon-optional pages (Fair Source, people lists, errors) — not a second --help. k2 agent list reports local_transport_denied when the OS blocked the socket (daemon health unobserved). k2 skin hydra on|off. Linux: Hydra starts on daemon boot if enabled.
Database. Unscoped k2 store / migrate 403s name the resolved DB (dbId, dbName, resolvedVia). A write grant on a newer DB does not unlock put on an older read grant.
---
v0.40.123
0.40.123 — Skin SPA door, migrate that sticks, Hydra toggle
Skin Direct can serve an on-box UI: if you set a UI port, Caddy proxies /, /assets, /_next, and /app to that loopback app (not the whole daemon). Grid, login, and /v1 stay 403. Mail Enable re-applies Caddy so the mail hostname shows up without a second front-door click. Direct custom domains still need :80 (or dns-01) for certificates.
Database. k2 db migrate applies 0001_name.sql files and says so; empty or init.sql is a loud error, not “already applied.” A second run with unchanged files skips. A rewritten already-applied file is refused. The workspace agent role can SELECT _k2_store and the migration ledger (repair GRANT on put/migrate). Granting another workspace write uses sequence privileges Postgres actually accepts (USAGE/SELECT/UPDATE, not INSERT). Settings → Data “Add workspace…” opens down and to the right.
OIDC. Settings → Skin Access Hydra toggle starts a Linux sidecar if hydra is on PATH (loopback 4444/4445). Enabling skins does not start it. Mac shows the Linux banner. Login/consent UI and public OIDC on :443 are next.
---
v0.40.122
0.40.122 — Database passport, Skin Direct + mail on one :443
Database. The workspace flag Agents can create databases (Settings → Data) only gates k2 db create. If a workspace already owns a DB — or has a grant — its agent can list, fetch a DSN, migrate, dump/restore, and use k2 store without flipping that flag. Cross-workspace read grants stay read (write still 403). Email Hosting Enable now pulls the Stalwart tarball from Alakazam Labs' pin (same 0.16.10).
Skin roster. Workspace agents can k2 skin user list / k2 skin-token list (no raw secrets). Minting and the front-door stay owner-only; a valid agent passport gets owner_only (exit 3), not “invalid token.”
Box :443. Skin Direct and Email Hosting no longer coin-flip for the box's port 443. One Caddy (the Skin front door) Host-routes Direct to the daemon (Thread path-filter) and the mail hostname to Stalwart on loopback 8443. Nested skin. is still Connect. Mail Enable uses HTTP-01 (not tls-alpn on 443) when Skin Direct will own 443. Do not Enable mail tls-alpn and Skin Direct on the same 443 until you apply this cut.
---
v0.40.121
0.40.121 — Skin Access, quieter Thread/Chatter, Grok one Return
Skin Access is a guest list for custom UIs that talk to agents without a terminal. Settings → Skin Access: add a username, mint a k2skn_ pass with Thread read/post. Those tokens never open the grid. A Caddy front door (Caddy on PATH) path-filters Thread/overlay//boot-status and can listen as nested skin.. Opt-in catalog pack: k2 agent context add skin:roster.
Thread and Chatter no longer stay rendered behind Terminal. The PTY keeps running when you leave it; overlay tabs load on demand, 25 messages at a time (Load older / scroll up). A message you send on Thread shows in the Thread list (it still wakes the agent in the terminal with [thread:…]).
Message the agent: Ctrl+B injects STX (with Esc / Ctrl+C / empty Return). Grok’s default submit is paste + one Return — the extra Return was starting a new turn after steer. Other models stay two Returns unless you changed Submit keys.
Agents told [thread:addr] should reply with k2 thread, not the TUI. Generated .k2/agent/SKILL.md is no longer planted (leftovers on disk are left alone).
---
v0.40.120
0.40.120 — Chatter tab, database sidecar, compose slash, Settings regroup
Agent sessions are now Terminal | Thread | Chatter | split. Chatter is the agent-to-agent mailbox (k2 msg / k2 talk) with the same bubbles as Thread and no compose box. Thread is still the human overlay.
Message the agent: / typeahead for /compact and /goal; + uses the native file picker. Esc and Ctrl+C from the box cancel the current turn (PTY bytes); empty Return confirms a TUI prompt. Typed Return still sends. Settings → LLMs Submit keys is per-model (which keys finish a live inject).
Settings sidebar is grouped: K2 Server (Tunnel, Server Access, Connected Servers, API Keys, Companion), Editors / Fonts, Logs, Sidecars (Database). Companion has App Store and Play QR codes. Connected Servers: add at the top, then search. Server Access: search the user list; pick a starting role when adding a user.
Linux boxes can grow a database sidecar the way they grew mail: k2 db enable supervises distro Postgres (loopback only — not a static-IP feature). Agents mint a per-workspace DB with k2 db create, apply .k2/db/migrations, dump/restore inside the workspace, and store JSON documents with k2 store. Settings → Database is the owner surface.
Off-box *.k2.dev is the existing publish door: k2 publish subdomain create (the port is already listening — do not k2 publish run Postgres). k2 db status --json reports port and that hint. There is no k2 db expose.
Hire an interview workspace with write in one shot: k2 agent hire … --db-access write then k2 db create (create is still not implicit on hire). GET /v1/w/ returns applied migrations + size; POST /v1/w/ restores onto a fresh workspace. Re-running migrate with the same checksum is a no-op; a rewritten already-applied file is refused.
Postgres is fenced so it cannot starve agents (systemd memory cap + query GUCs). k2 db doctor reports RSS vs the cap.
k2 hostmail enable now requires --hostname mail.acme.dev (the daemon already 400'd an empty body). k2 db enable still POSTs {}.
---
v0.40.119
0.40.119 — LAN federated connections use the saved IP:port
After you Pair a LAN peer, picking an agent under a workspace's Federated connections no longer looks up (that host was never in Settings → Connections). The address is agent:: against the server you already signed in.
What's New star drawer: K2 logo on the tag, the card stays centered, the drawer sits behind it.
---
v0.40.118
0.40.118 — Pair as federated peers over LAN (no tunnel)
Two machines on the same network can Pair as a federated peer without buying a *.k2.dev tunnel. Add Server as http://, enable federation, Pair. k2 msg sales::10.2.40.28:38471 is the address shape. HTTPS to a private IP is still refused.
What's New has a little drawer on the right — if you're enjoying K2, a star on GitHub helps a lot. Hidden in air-gap builds.
---
v0.40.117
0.40.117 — Terminal hitch; inbox files keep the note
Quiet agent sessions no longer freeze the window for a second or two while you type in Message the agent. The grid still pauses a runaway TUI; catch-up no longer stop-the-worlds the compose bar, and idle panes no longer log a false stall.
k2 msg --inbox-wake / --inbox-silent with files now keeps the cover note you typed (it used to drop the prose and only attach the files). A leftover tray-teardown bug that printed exit 1 on a successful send is gone.
Agents extra columns: the divider between columns now stays under the cursor while you drag (including when the window is zoomed). It used to run ahead, pause, then leap.
k2 mail link add for an IMAP app-password account no longer dies with Query returned no rows before it talks to the server (Gmail OAuth was fine). Pipe the password as before.
Message the agent has a / picker next to attach — /compact and /goal go to the TUI as real slash commands, not as typed text.
A paper-note button in the top bar (next to the timer) opens a K2 cheat sheet of CLI nouns (k2 msg, k2 thread, k2 inbox, …).
---
v0.40.116
0.40.116 — Codex yolo; pinned chat uses your LLM launch script
Switching the pinned Chat dropdown now launches that session with the command from Settings → LLMs, not a stripped resume line. Codex’s default is codex --yolo. If you already customized Codex, that command is left alone.
---
v0.40.115
0.40.115 — Final air-gapping patch
A last air-gapping patch.
---
v0.40.114
0.40.114 — Thread tab, agent-to-agent message log
Agent sessions get Thread | Terminal tabs (default Terminal; the PTY stays running when you open Thread). The agent can post to the Thread with k2 thread, including choice cards and a secret field that never lands in the log. k2 msg / k2 talk are still injected into the terminal, and a copy is recorded so you can see chatter later — not mixed into the human Thread.
What to try
1. Open pinned Chat — underline Thread | Terminal. Switch to Thread; the agent should keep running in the background.
2. From an agent: k2 thread — appears on Thread, not as a TUI line.
3. k2 thread ask — card on Thread; tap Go, or type in chat instead (voids the card).
4. k2 msg another workspace — that still wakes them; a chatter record is stored (not on the Thread tab).
---
v0.40.113
0.40.113 — Switching servers no longer keeps the last machine's tabs
Switching this window from This Mac to a remote server now clears the tab strip immediately. A leftover screenshot or HTML dashboard from your Mac is not requested on the remote — those /var/folders/… 400s stop. Switch back and your Mac tabs restore from that machine.
A background window no longer polls HTML/markdown files every 2 seconds while it is unfocused.
What to try
1. Open a screenshot on This Mac, switch that window to a remote — strip empties, no 400 storm in the console.
2. Switch back — Mac workspaces return, including the screenshot tab (the tmp file itself may already be gone; an error pane is fine).
3. Two windows (Local + remote): blur the remote window; its HTML dashboards stop polling.
---
v0.40.112
0.40.112 — Linked mail lists without walking the whole mailbox
Linked Gmail/IMAP is live IMAP, not a local store. Unfiltered k2 mail messages now fetches the newest page of one folder (IMAP sequence numbers). It does not SEARCH ALL tens of thousands of UIDs. --limit is still 25 (max 200).
Filtered search (--from, --query, --unread) is a ≤30-day window. --since still means on/after that date. To look at a month in the past, pair it: --since 2017-03-01 --before 2017-04-01. --since 2017-03-01 alone (years of mail) errors — add --before. --since 7d is still the last seven days through now. --from/--query with no dates inject last 30 days and print both bounds on every result (hit or miss), so empty cannot mean “does not exist.”
SEARCH that matches more than 1000 messages fails loud (narrow --since/--before). Hosted (on-box) mail is unchanged.
What to try
1. k2 mail messages on a huge linked Gmail — should return the newest 25 without a 30s stall.
2. k2 mail messages --from someone — prints searched last 30 days… even if empty.
3. k2 mail messages --since 2017-03-01 — usage error asking for --before, not one silent month.
---
v0.40.111
0.40.111 — Don't hide your workspaces behind a stub `k2.db`
If both ~/.k2/k2.db and ~/.k2/k2so.db exist as real files, K2 now opens the one that actually has your workspaces. A stray empty k2.db (touch, sqlite3 ~/.k2/k2.db, a test) used to win on name alone — the app looked factory-reset, mail and chats gone. Nothing was deleted. The live file is still k2so.db until a later rename. This update just stops picking the stub.
Gmail k2 mail read no longer reports daemon_unreachable when the daemon is up and the mailbox is large. One IMAP session, cached folder STATUS, longer HTTP timeout.
What to try
1. If workspaces vanished after an update: look in ~/.k2/ — if both k2.db and k2so.db are real files, restart this build. The sidebar should come back. Do not delete either file.
2. Linked Gmail: k2 mail read of a Sent or Inbox id should return a body, not hang until timeout.
---