Skip to content

TaskWraith v1.9.0

Latest

Choose a tag to compare

@boggspa boggspa released this 27 Jul 04:57

If 1.8.9 gave every agent room to work, 1.9.0 connects those rooms into a
workshop with a front door. Parallel lanes can return work you choose to keep,
top-level threads can leave one another durable notes, and human collaborators
can enter a host-reviewed People space without becoming agent authority. The
dock holds the documents, canvases, mail, and calendar context around the code;
Pi opens a broad BYOK model bench; and Mistral Vibe adds a plan-backed door. The
same local authority still decides what each seat may touch—or which colours it
may change—while product observation remains a clear, optional choice.

Branches come back as candidates

Write-capable fan-out lanes can now ask for an isolated worktree instead of
sharing the checkout. Each lane forks from the committed workspace boundary,
returns a durable candidate, and appears in a Compare dock where its patch can
be inspected and promoted deliberately. The composer exposes that choice as an
Isolate toggle, while ensemble_await and ensemble_lane_result give agent-run
workflows a real join-and-read step rather than making a synthesizer scrape the
panel transcript.

Git work is easier to follow before and after the fan-out. Main owns a
per-thread workflow marker, the sidebar groups marked threads under Git with
their true repository name, and worktree patches have explicit capture/apply
contracts. Read-only postures can inspect git status, git diff, and
git log without an approval card, so review lanes can gather evidence without
borrowing mutation authority.

A panel stays a panel

Turning a normal thread into an Ensemble now creates at least two seats, so the
extra orchestration chrome always opens onto an actual panel. If a two-seat
panel loses one participant through the ordinary composer controls, the thread
returns to a solo chat on the remaining seat instead of persisting a one-agent
Ensemble. Explicit agent-authored or saved-preset one-seat rosters remain
untouched: TaskWraith does not rewrite a roster that was deliberately stated.

Threads can knock on another door

Top-level threads gain peer messages: a durable, permission-gated inbox for
passing a note to another task without pretending the two provider sessions
share context. A message enters the target's next turn exactly once, visibly
labelled as untrusted relayed content; an optional wake remains a separate,
more privileged choice. Exact ids and unambiguous titles resolve in main, the
startup sweep catches queued delivery, and user- plus agent-originated sends
converge on the same authority.

The Peers dock makes that path visible on desktop, and the paired iPhone/iPad
companion can read the inbox, send a reply, and show the same pending indicator.
Sub-thread return still flows child to parent; peer messaging is the deliberate
sideways path between independent top-level tasks.

People can enter without becoming an agent

Human collaboration now calls itself People instead of Shares and makes the
host boundary easier to read. Invite-issued, offline, and live states are
distinct; contribution-rule presets say what a collaborator may request;
participants can be removed individually; and an expandable activity log
explains admission, disconnect, duplicate/rejected contributions, and draft
insertion instead of making a dropped comment look like it vanished. Even the
strongest preset only prepares a host draft—the user still decides whether to
send it to an agent.

Unpackaged builds also gain a same-Mac rehearsal lane: separately named
instances receive separate app data, single-instance locks, identities, and
relay and Tailscale Serve ports. An explicit LAN-only or loopback invite appears
only after the corresponding remote-reachability guard refuses that invite, so
the rehearsal does not weaken the packaged remote boundary. Side-by-side boot,
data isolation, and port separation have been exercised; the collaboration
handshake and unrelated-network two-Mac flow have not, so this remains a test
path rather than a production-connectivity claim.

The dock becomes a desk

A new Office dock brings focused editors for Word documents, spreadsheets,
slide decks, calendars, and mail drafts into the workspace. TaskWraith can
round-trip DOCX, XLSX, PPTX, and ICS through bounded local codecs, preserve
deck speaker notes and document images, import dropped files, and open or reveal
grant-covered documents outside the workspace without turning a reference into
silent access.

An optional Outlook connector uses Microsoft's device-code sign-in to read
mail and calendar context, save email drafts, and create personal time blocks.
It deliberately has no send-mail permission, refuses invite-producing attendee
creation, bounds Graph responses, and treats message/event text as untrusted
third-party content. Canvas work also joins the right dock with sketch embeds
and chat-scoped list/close controls, so visual and document context can stay
beside the thread that owns it.

Agent-driven Canvas actions now fail closed when a target or human-input
snapshot is stale, serialize per surface, and stand down while a human is driving.
Credential fields remain human-only, in-progress sketch strokes survive agent
updates, and the audit receipt is persisted before a liveness check can fail.
Canvas drivers remain bound to their isolated surfaces and must never target
TaskWraith's own consent chrome; pausing for recent human input is courtesy,
not a substitute for that structural boundary.

Canvas consent follows the surface

Permission to let an agent interact with a preview now applies only to the
surface you approved
, not to every preview opened afterwards in the same run
— an agent can enumerate a chat's canvases, so an unscoped grant reached
windows you never saw a prompt for. Because a workspace-wide "interact with any
preview, in any chat, until revoked" grant is not a scope anyone can
meaningfully consent to, it can no longer authorize an interaction; a broader
grant persisted by an older build is inert rather than honoured.

Relatedly, and worth stating plainly: when an agent asked to type into a field,
the approval record kept the text it was about to type, and that record reached
TaskWraith's durable history — even though the tool contract told agents the
typed value was never recorded. New runs no longer store it. Existing history
is not rewritten
, so if a previously typed value was sensitive, clear that
chat's history.

Pi opens the model bench

Pi joins as a first-class coding-agent seat with isolated runtime homes and
bring-your-own-key access to DeepSeek, Z.ai/GLM, Qwen, MiniMax, Mistral, Groq,
and Cerebras models. Each upstream has its own key boundary, model names,
pricing row, spend attribution, and brand hue; pickers show only configured
upstreams, transcript attribution keeps the actual upstream's hue, and desktop
plus iOS carry the same provider/model map. The New Additions card now leads
with that upstream lineup.

AntiGravity becomes steadier at the same time: conversations resume, successful
model discovery is cached, unservable catalogue rows are filtered, Gemini 3.x
thought signatures survive tool replay, and schema unions stay real unions.
Denied services remain denied, cache reads are disclosed, and throttling is
distinguished from a genuinely empty allowance.

Mistral gets its own door

Mistral Vibe joins as a first-class ACP seat for the user's Mistral plan,
separate from Pi's metered mistral/* API-key upstream. Devstral Small is the
fast, frugal default beside Mistral Medium 3.5; both carry their 262K context
map onto iOS, and a clearly heuristic plan-burn meter gives the otherwise
unmetered subscription a cautious early warning.

The distinction is authority, not just branding. Read-only and write-capable
seats select Vibe's gated plan and default session modes over ACP; its
auto-approve modes are unreachable, and inherited Mistral API credentials are
scrubbed so a plan-backed run cannot silently cross into Pi's pay-as-you-go
bill. Fresh sessions receive explicit host-composed context instead of
pretending provider history was retained. Provably read-only shell commands
remain useful in Plan, while short Vibe throttles surface as retryable warnings
instead of masquerading as a subscription quota wall.

The composer model picker and iOS first-launch sheet now carry that same
Mistral roster, and New Additions no longer promises an image-input capability
the seat does not expose. An opt-in live exercise against vibe-acp 2.22.0
also proves the normal lane can select Plan plus Devstral Small, use plan
credentials without inheriting an API key, return an answer, and close cleanly.
That source exercise is evidence for the ordinary ACP lane, not a substitute
for the scheduled-seat release seal.

The workshop can wear your colours

Agents on write-capable seats can read and set a small allowlist of typed
theme tokens through theme_tokens_get and theme_tokens_set. This is a
data channel, not arbitrary CSS: selectors, rules, URLs, calculations, provider
identity colours, focus rings, and approval-card geometry stay outside the
writable set, with validation repeated when the renderer applies persisted
values. Successful writes are pushed narrowly to every open window and applied
through the same validated appearance path, so the change appears without a
reload. Read-only review seats can inspect the palette but cannot restyle it.

Two properties of the appearance channel are deliberately not negotiable. A
restyle always asks: theme_tokens_set prompts on every call, and no standing
grant, trusted session, or session-wide auto-approve can quiet it — previously
a single "allow for this session" on any unrelated tool silenced every later
restyle. And the approval card's own controls no longer take their spacing
from values an agent can write, so a restyle cannot crowd Accept and Reject
together and turn a near-miss click into a grant.

Every provider leaves a clearer receipt

Run management now measures lifecycle assurance across all ten stable provider
identities without turning maturity into provider admission. Immutable launch
plans, per-run homes, exact transport close/kill joins, cancellation
settlement, launch evidence, signed posture validation, and honest capability
reports land provider by provider. Missing assurance produces a receipt or
warning and the safest compatible mode; it does not silently hide a seat the
user chose. An ensemble seat that cannot start now carries the reason with it —
a missing sign-in reads as a missing sign-in instead of “dispatch failed” — while
a seat stopped by cancellation stays quiet rather than blaming its provider.

The production adapter registry is checked against that full roster before a
new identity can become a mysterious startup crash. Its test follows the
actual registration graph, and a mismatch now names both the missing adapter
and the construction site that needs repair. Provider selection is exhaustive
at compile time too: an unhandled identity fails type-checking instead of
silently borrowing retired Gemini behavior, while the Settings usage and rate
tables include the newest seats rather than dropping them from the end.

That same discipline reaches smaller authority edges: peer-thread wakes,
fan-out candidates, provider capability projection, grant expiry, and review
or compaction runs all re-check the scope they are about to use. canvas_eval
is available as an approval-visible instrument in Plan rather than disappearing
behind a silent deny.

The phone keeps the same map

iOS gains the full-colour Ensemble identity, anchored participant editors,
Pi's provider/model branding, Mistral Vibe's context map, and a compact
single-row Ensemble composer that adapts to landscape and short viewports.
Above-composer pills stay reachable while typing; fan-out lane results and
provider-run failures get native cards; the workspace/branch pill opens a Git
surface for branch, checkout, and PR-watch actions; and the Peers inspector
carries cross-thread messages. Pairing reconnects no longer flap the app back
to the setup screen.

An in-flight run can now stay visible as a Live Activity on the Lock Screen
and Dynamic Island. Solo, diff, attention, and Ensemble layouts are compiled
into the companion, with a master switch and layout picker on the Mac; the
iPhone's system setting still has the final say. A connected phone updates its
own card, while a Mac with APNs configured can keep it current after the relay
drops and, after a grace period, raise one for a run that began while the app
was closed. Stale and terminal states end honestly rather than leaving a timer
running, and the delayed start stands down if the phone already created the
card.

That card is a deliberate exception to the companion's ordinary encrypted task
projection: ActivityKit must decode its push state, so it cannot be
end-to-end encrypted. The payload is therefore a strict allowlist of coarse
phase, start time, file/add/delete counts, provider product names, bounded
Ensemble seat states, palette/layout, and an opaque per-activity reference. It
contains no prompt, output, title, path, repository/workspace name, or run/chat
identifier. No privacy-sensitive value—including user-authored task/workspace
content or an account/workspace-linkable identifier—may ever be seeded into
that state; adding one requires a fresh privacy and security review. Live
Activity tokens remain memory-only on the Mac.

Foreground and closed-app completion banners now use the same renderer and a
closed, versioned preset contract, so one run no longer gains different wording
or symbols depending on whether the companion happened to be open. The default
remains byte-for-byte compatible, and a Settings preview lets the user choose
the wording safely. APNs delivery also respects each device's sandbox or
production environment and prunes a token only when Apple says it is actually
unregistered—not merely because it was sent to the wrong gateway.

Across both apps, provider rows use cleaner labels, pickers stop calling an
empty model list “loading,” compact tool foldouts retain their diff accents,
and Codex authentication reports revoked credentials honestly and upgrades
that installed runtime instead of a different copy. Codex also stops looking
broken to anyone signed in elsewhere: TaskWraith keeps its own Codex home, so a
terminal codex login authenticates ~/.codex and leaves this one untouched,
and the sign-in notice now says exactly that — the home it uses, the one it does
not, and the in-app route that works.

For anyone who would rather not sign in twice, Settings → Providers → Codex →
“Use my existing Codex sign-in”
borrows the ~/.codex credential instead.
It is off by default and asks plainly, because it trades containment for a
working seat: TaskWraith then reads and writes a file it otherwise never
touches. Borrowed, not copied — ChatGPT rotates its refresh token on use, so
two homes holding one token revoke each other. TaskWraith takes a lease for the
lifetime of the Codex process, commits any rotation straight back to ~/.codex,
refuses a writeback that would move the credential backwards, and hands the
lease back on exit, removing the borrowed credential and nothing else. A second
TaskWraith window, or a machine with nothing to borrow, quietly runs the way it
always did rather than failing a launch that would otherwise have worked.

Provider identity gets the same cleanup. Official Pi and Mistral marks now
replace approximated brand glyphs on desktop and iOS, and the invented
mnemonic provider-glyph set is removed from external identity surfaces.
Neutral pool, sidebar, notice, and collaborator contexts use honest monograms
or product-owned symbols when no approved first-party mark belongs there.

Product observation says exactly what it counts

TaskWraith now has a public privacy notice and a visible, user-disableable
activity-reporting control under Settings → Safety & Privacy. A clear
first-launch choice now keeps first-party observation off until the user
affirmatively selects Share minimal activity; Don't share is equally
prominent and neither choice removes a feature. When enabled, it sends at most
one no-ID check-in per UTC day: schema, event, day, app version,
operating-system family, processor family, and release channel. Both controls
show that complete contract in the app. Prompts, workspaces, provider choices,
usage, and stable installation identifiers are outside it; builds without an
endpoint send nothing.

The same setting can now power an approximate apps online now gauge without
creating a session history. Each running app renews a random, process-only
lease; the receiver holds it in RAM for 150 seconds, returns only the aggregate
unexpired count, and never writes lease values, renewals, start/end times, or
durations to its analytics database. Switching the setting off stops renewals
and retracts the lease when reachable; a crashed or disconnected app simply
ages out.

That boundary also changes how adoption is described. GitHub release requests,
update-manifest checks, repository traffic, App Store aggregates, and optional
desktop activity check-ins are separate measures with separate caveats—none is
silently promoted into a unique-user count. They are used only to understand
adoption, prioritise supported platforms, and verify release/update health,
never for advertising or individual profiling.

The workshop closes without loose ends

A timed-out history deletion now stays honest about what is still happening.
TaskWraith returns control without pretending a slow sink was cancelled, keeps
the exact scope fenced until that continuation settles, and refuses a surprise
late erase. Once the late work is fully reconciled, every hold is released
exactly once and the durable intent remains available for a clean retry in the
same process.

GitHub pull-request links now pass through the same allowlisted shell-opening
policy as every other external link. The transitive HTTP adapter used by the
provider tool bridge is pinned to its patched line too, with registry
signatures, an end-to-end MCP transport exercise, and a zero-finding production
dependency audit behind it.

New doctrine-integrity and formatting-ratchet gates keep future agent work from
turning documentation or unrelated source into collateral churn.