CHANGELOG

Version-by-version log of user-visible changes since v0.1.

16 / 16·log·v0.9.26

v0.9.26 — 2026-06-22 — host plane hardening: atomic peers.yaml, constant-time token compare, no token suffix in auth-failure logs

v0.9.25 — 2026-06-22 — multi-profile organizations are first-class in alpi_knowledge

v0.9.24 — 2026-06-22 — pipe-to-interpreter detector rewritten on shlex.shlex

v0.9.23 — 2026-06-21 — ALP wire contract reconciled with the runtime

v0.9.22 — 2026-06-20 — skills + config docs reconciled with the runtime

v0.9.21 — 2026-06-20 — scheduler, filesystem, and outbound-HTTP hardening

v0.9.20 — 2026-06-20 — current model recommendations + safer org bootstrap

v0.9.19 — 2026-06-19 — faster, more reliable daemon startup

v0.9.18 — 2026-06-19 — skills are fully inspectable

v0.9.17 — 2026-06-18 — accurate per-model context windows

v0.9.16 — 2026-06-18 — notifications can carry a title

v0.9.15 — 2026-06-17 — profile summaries expose the TTS voice

v0.9.14 — 2026-06-17 — interrupted turns read as interrupted

v0.9.13 — 2026-06-17 — session & state hardening

v0.9.12 — 2026-06-17 — resuming a session no longer answers an old unanswered message

v0.9.11 — 2026-06-16 — chat --once can resume a session

v0.9.10 — 2026-06-16 — multi-turn image editing on text-only models

v0.9.9 — 2026-06-15 — scheduled jobs can run longer

v0.9.8 — 2026-06-15 — pause a profile

v0.9.7 — 2026-06-15 — responsive host under a busy fleet

v0.9.6 — 2026-06-14 — update a daemon from the apps

v0.9.5 — 2026-06-13 — simpler notifications

v0.9.4 — 2026-06-13 — name your scheduled jobs

v0.9.3 — 2026-06-12 — system prompt hardening

v0.9.2 — 2026-06-12 — browse past conversations exactly

v0.9.1 — 2026-06-12 — auto-read voice toggles

v0.9.0 — 2026-06-12 — alpi audit security posture scan

v0.8.25 — 2026-06-12 — file tools won't read your .env secrets

v0.8.24 — 2026-06-12 — budgets are dollars or nothing

v0.8.23 — 2026-06-12 — daemon FD limit + clean stream disconnects

v0.8.22 — 2026-06-11 — MCP servers read the profile's own .env

v0.8.21 — 2026-06-11 — local-build browsing, Gemini-safe tools, security docs

v0.8.20 — 2026-06-10 — heavy downloads only when they're needed

v0.8.19 — 2026-06-10 — OpenRouter traffic is credited to alpi

v0.8.18 — 2026-06-10 — settings apply without restarting the daemon

v0.8.17 — 2026-06-10 — event streams announce they're alive

v0.8.16 — 2026-06-10 — every tool in a meaningful group

v0.8.15 — 2026-06-10 — removing a provider removes its models too

v0.8.14 — 2026-06-10 — notifications go to your own apps, not a gateway

v0.8.13 — 2026-06-10 — security hardening pass

v0.8.12 — 2026-06-09 — daily token usage and cost, per profile and workgroup

v0.8.11 — 2026-06-09 — recalled memory is checked for injection

v0.8.10 — 2026-06-09 — agents know the host Python version

v0.8.9 — 2026-06-09 — free models get a higher per-turn step ceiling

v0.8.8 — 2026-06-09 — turns record how long the agent reasoned

v0.8.7 — 2026-06-09 — files you attach keep a preview in history

v0.8.6 — 2026-06-08 — agents can hand you the files they make

v0.8.5 — 2026-06-07 — serve agent-made images to remote clients

v0.8.4 — 2026-06-07 — skill API spend counts toward your budget

v0.8.3 — 2026-06-06 — chat reports the model it used

v0.8.2 — 2026-06-05 — stop stalled providers from hanging a turn

v0.8.1 — 2026-06-05 — a run ledger for unattended turns

v0.8.0 — 2026-06-04 — search a workgroup's history by meaning

v0.7.4 — 2026-06-04 — recall past conversations by meaning

v0.7.3 — 2026-06-04 — learn a file into the workspace

v0.7.2 — 2026-06-03 — attach files to chat

v0.7.1 — 2026-06-03 — one network address

v0.7.0 — 2026-06-03 — curator can apply its own cleanup

v0.6.37 — 2026-06-03 — prompt guidance adapts to the model

v0.6.36 — 2026-06-02 — a task survives a member leaving mid-task

v0.6.35 — 2026-06-02 — the hub serves workgroup task state

v0.6.34 — 2026-06-02 — workgroup turns recover and pipelines stop cleanly

v0.6.33 — 2026-06-02 — workgroup turns die only when truly stuck

v0.6.32 — 2026-06-01 — workgroup handoffs survive, blocks halt cleanly

ALP workgroups got sturdier under autonomous, multi-phase pipelines.

v0.6.31 — 2026-05-30 — Docker deployment, Umbrel retired

Alpi now ships as a plain Docker image for any Linux host; the Umbrel package is gone.

v0.6.30 — 2026-05-29 — #task #<slug>, tools.deny visibility, opus 4.8

Three protocol / catalog tweaks bundled together.

v0.6.29 — 2026-05-28 — workgroup posts reach the hub again

Members on ~/.alpi/profiles/* could not post into workgroups after v0.6.27. The hub opened a #task, members were woken by the poller, and every workgroup_post failed silently with No such file or directory — transcripts stayed at seq 1.

v0.6.28 — 2026-05-28 — per-device profile scope

Pairing a non-admin device can now restrict it to a subset of profiles instead of the whole host. A shared phone reaches @home only; a partner's laptop reaches @finance only.

v0.6.27 — 2026-05-27 — local peer routing centralised

Two more code paths still resolved co-located peer sockets by peer_id instead of pubkey — alpi peers ping CLI and the workgroup client. Both hit the exact bug 0.6.24 closed for the host probe and link.ask: a peer pinned under any alias different from the real profile name would route to the wrong directory and fail.

v0.6.26 — 2026-05-27 — Umbrel container restart hardening

Two boot-time fixes that together stop the Umbrel app from looping through Error: daemon already running (pid 9) after a stop/start or any abnormal exit.

v0.6.25 — 2026-05-27 — device revoke is idempotent

Same UX fix as host.peers.remove (v0.6.23), extended to paired devices: clicking Revoke on a row that's already gone no longer errors out — the user's intent is "be gone", the end state is the same either way.

v0.6.24 — 2026-05-27 — local peer routing + safer reads

Two classes of peer bug closed without adding any hidden state: local peers under an arbitrary alias now route end-to-end, and read-only peer lookups stop materialising ALP secrets on disk. Discard stays honest — it clears the current pending row and nothing else.

v0.6.23 — 2026-05-27 — peer remove is idempotent

Removing a peer no longer fails when the peer is already gone — the user's intent (peer unpinned) is the same end state either way, so a stale UI, a half-succeeded retry or a parallel client should not block the click.

v0.6.22 — 2026-05-27 — per-profile tool denylist

You can now hide individual tools from a profile so the LLM never sees them in its schema and the executor refuses them. Useful for tightening profiles exposed to less-trusted input — e.g. a librarian profile that other peers reach via link.ask and that has no business writing files, running shell, or sending mail.

v0.6.21 — 2026-05-27 — storage report covers the whole profile

host.profile.storage now reports every on-disk shape a user might want to inspect, not just chat transcripts and logs.

v0.6.20 — 2026-05-27 — outputs can be deleted

You can now remove individual entries from the agent's inbox; the backend has the verb, owned clients use it.

v0.6.19 — 2026-05-27 — gateways stay text-first

Telegram and Matrix no longer post intermediate tool-call lines into the chat. You get a single, clean reply per turn — the same one a human would send. If you want to watch what the agent is doing, use a TUI / desktop / mobile session.

v0.6.18 — 2026-05-27 — ask_user (UX.1) + approval gets cwd context

The agent can ask a closed question through a structured primitive that owned clients (desktop / mobile / TUI) render natively, while gateways degrade to a numbered text list. The approval modal also gains the working directory the command will run in.

v0.6.17 — 2026-05-27 — runtime-created profiles come online without a daemon restart

Creating a profile while the daemon was running left it half-alive: chat worked through host.sock, but the per-profile peer-link listener (alp/alp.sock) never bound. Peers that pointed at the new profile by pubkey saw it as offline even though both lived on the same host. The daemon had taken a one-shot snapshot of profiles/ at boot and never looked again.

v0.6.16 — 2026-05-26 — skill curator (AC.1, report-only)

Post-hoc curator that reads skills/.usage.json + the on-disk skills tree and writes a markdown + json report under <home>/logs/curator/<UTC-timestamp>/. Never mutates skills — apply suggestions land in AC.2.

v0.6.15 — 2026-05-26 — prompt caching (CL.1)

Stable cacheable prefix + LiteLLM-native cache_control injection on supported models. No config, no audit logs, no provider table — the SDK's own capability check picks the right behaviour per model and provider.

v0.6.14 — 2026-05-26 — storage hygiene

v0.6.13 / desktop-v0.3.22 — 2026-05-26 — Manage Sessions on desktop

The desktop client gets a real session manager. The Sessions popover in the chat header now has a Manage sessions → footer link that opens a full inbox: every chat thread on the profile, with activity, turns, and disk size; filter chips for All, ≥ 30 days, ≥ 90 days, < 3 turns; sort by size / activity / turns / created. Bulk-select with checkboxes (⌘A / Shift+click range), then delete with a typed-confirm.

v0.6.12 / desktop-v0.3.21 / mobile-v0.1.17 — 2026-05-26 — tts stops trying to be a player

The daemon no longer plays audio. The tts tool still synthesises through Microsoft Edge TTS and caches an MP3 — but local speaker playback, the per-profile autoplay toggle, and the gateway-specific voice-note conversion (mp3 → ogg via ffmpeg) are all gone. The mobile and desktop apps already show a play button on each message, which is now the only delivery surface for free-form audio.

Upgrade note: any tools.tts.autoplay line left in config.yaml is harmless — the loader ignores unknown keys.

v0.6.11 — 2026-05-25 — persistent inbox for proactive messages

Notifications stop being one-shot. Every proactive send_message and every schedule failure now files a durable row in a per-profile inbox at ~/.alpi/[profiles/<name>/]outputs/, capped at 500 entries. Tapping the notification on a paired device deep-links to that row instead of dumping you into the chat window, so the context survives reboots, OS notification-tray clearing, and being offline when the message fired.

Companion mobile / desktop releases will start consuming this foundation in the next builds; this release is the daemon-side contract that everything else builds on.

v0.6.10 — 2026-05-25 — paired devices get a role (admin / member)

Device tokens now carry a role on disk. The dispatcher checks it before sensitive host methods, so an admin device on Tailscale can do remote setup (create profiles, add gateways, mint other devices, restart the daemon) while a member device stays read-mostly. The local socket on the daemon's own machine is unchanged — sovereign authority for bootstrap and recovery.

Re-pair every device after upgrading: this release does not preserve backward compatibility with pre-0.6.10 entries. Anything without an explicit role collapses to member at load time, so an old admin device becomes member until re-paired.

v0.6.9 — 2026-05-25 — Gmail OAuth works against remote daemons

The Gmail OAuth wizard used to fail silently when the daemon wasn't on the same machine as your browser — the consent loopback ran inside the daemon, so on Umbrel (or any headless host) Google's redirect landed nowhere. Two ways out now:

v0.6.8 — 2026-05-25 — workspace index goes back to incremental, with safer corners

The "always rebuild" semantics from v0.6.7's working tree got reverted: on a large vault (Obsidian-class or any repo with thousands of files), paying for a full re-embed on every call is expensive and forces every search-empty turn into minutes of blocked I/O. Restored incremental indexing as the default and closed the correctness gaps that made the original "always rebuild" tempting.

v0.6.7 — 2026-05-24 — alpi self-knowledge moves from skill to first-class tool

The @alpi/knowledge bundled skill is gone. The capability that let alpi answer questions about itself is now an ordinary tool — alpi_knowledge — backed by packaged Markdown under alpi/knowledge/references/. Skills become entirely user-owned; the whole "bundled skill" plumbing is removed.

v0.6.6 — 2026-05-24 — host.version exposes a stable device_id

Mobile / desktop clients had no way to detect that two paired connections referred to the same daemon (e.g. LAN address vs Tailscale address). The ALN background poll was deduping by (ip, port), which still treated those as different daemons → duplicated notifications.

v0.6.5 — 2026-05-22 — host.network.status no longer freezes the UI, agent notification deep link

Opening the default profile's settings used to hang the desktop for ~5s while host.network.status ran the same expensive network probes (Tailscale CLI subprocess, ifconfig, UDP route) three to four times in series. The handler also blocked the host event loop, which queued every other RPC behind it.

v0.6.4 — 2026-05-22 — daemon identifies itself on pair

The daemon now reports its own device_name (set via alpi setup) in the host.version reply. Pairing clients use that as the connection label instead of whatever string the pairing URL carried — fixes mobile showing the device-being-paired label (e.g. "iPhone") as if it were the daemon's name.

v0.6.3 — 2026-05-22 — fire-and-forget schedule

Manual schedule fires from desktop / mobile no longer block the UI for the full duration of the agent's run (often 20-60s, sometimes minutes). The host returns immediately; the job continues in the background and its result still arrives through the existing agent.message / schedule.done events.

v0.6.2 — 2026-05-22 — user message visible mid-turn

Fix: a paired client (desktop / mobile remount) reading a session during a long-running turn no longer has to wait until the assistant replies to see what the user just said.

v0.6.1 — 2026-05-22 — agent.message event + send_message default to alpi channel

Strategic shift: alpi-native notification delivery becomes the default path for the agent reaching the user, gateways become explicit opt-in. This makes the owned mobile / desktop apps the primary notification surface and removes the implicit Telegram coupling that existed in the old send_message tool.

v0.6.0 — 2026-05-22 — evidence digest (OPS.1)

Minor bump closing the v0.6 reliability + operator-diagnostics cycle.

v0.5.10 — 2026-05-22 — gateway containment (GW.1)

Per profile + per platform circuit breaker for the gateway loop. A bad Telegram token, IMAP outage, Gmail refresh failure, or Matrix sync exception now degrades only that one platform; sibling platforms on the same profile keep ticking and other profiles are untouched.

v0.5.9 — 2026-05-21 — skill telemetry (SK.1)

Per-skill view / use / patch counters persisted to <profile>/skills/.usage.json. Pure measurement — no auto-curate, no archive, no pruning. The data feeds the future alpi digest (OPS.1) and unblocks the v0.7 skill curator (AC.1) which will recommend pruning candidates from this history once it has months of real usage to look at.

v0.5.8 — 2026-05-21 — AX Local Notify (ALN) groundwork

Two new host event kinds feeding the AX Local Notify (ALN) mobile notifications path:

These join the existing event family (wg.post, wg.done, approval.request, schedule.done, budget.threshold…) consumed via the host.events.subscribe / host.events.history stream.

Architectural commitment baked in: ALN deliberately avoids APNs / FCM and any Satoshi-operated relay. Mobile uses expo-background-task to wake periodically, polls host.events.history over the user's own Tailscale, and renders local notifications on-device. No device tokens registered with Apple/Google, no central server, no telemetry. The trade-off is latency (15–60 min on iOS, system-paced) in exchange for the alpi promise of zero servers in the middle. Mobile-side wiring lands in mobile-v0.1.4.

v0.5.7 — 2026-05-21 — memory audit CLI (CM.1) + reasoning capability fix

Read-only operator surface for memory quality, and a fix for the reasoning effort dropdown that was silently hidden on direct openai/anthropic models.

v0.5.6 — 2026-05-21 — tool availability probes (TL.1)

Patch on top of v0.5.5. Tools whose optional runtime deps are missing are now hidden from the LLM schema and flagged in alpi doctor, so a partial install can't surface a broken capability that fails at the first call.

v0.5.5 — 2026-05-21 — untrusted-data boundary for tool outputs (CF.1)

Patch on top of v0.5.4. Every tool result, success or error, now re-enters the model's message history wrapped in explicit data-not-instruction markers. Built-in tools and MCP tools share the same hook, so hostile text from web pages, MCP responses, subprocess stderr, file contents or DB rows is consistently boundaried — never treated as latent instructions.

v0.5.4 — 2026-05-21 — reasoning effort per profile model (MC.1)

Patch on top of v0.5.3. Profile setup and settings now expose a off / low / medium / high reasoning effort control for the default model, applied automatically to every flow that uses it (TUI, desktop, mobile, schedules, gateways, skills).

v0.5.3 — 2026-05-21 — memory routing: pronoun-based, not noun-based

Patch on top of v0.5.2. Fixes a misrouting where "your name is Clara" ended up in USER.md (as "the user wants to be called Clara") instead of AGENT.md (as the assistant's own identity).

v0.5.2 — 2026-05-21 — file mutation evidence after each tool batch (CF.2)

Patch on top of v0.5.1. The agent now reasons over what actually got written to disk instead of what it intended to write.

v0.5.1 — 2026-05-21 — terminal approvals over the host plane (CF.3)

First v0.6-cycle release. Caution-command approvals (recursive rm, sudo, force-push, …) are no longer TUI-only — desktop and mobile can answer them through the daemon. The TUI flow is untouched; the daemon and any subscribed client are now equivalent surfaces.

v0.5.0 — 2026-05-21 — v0.5 cycle close: mobile client shipped

Milestone release. No new daemon contract vs. v0.4.54; this bumps the CLI / Python package to mark the close of the v0.5 cycle.

What shipped during the cycle:

Native mobile push notifications are deferred to v0.6. The in-app mobile surface is live; out-of-app APNs / FCM delivery now belongs to the reliability cycle.

Desktop and mobile keep independent release tracks. desktop-v0.3.6 and mobile-v0.1.1 require alpi v0.4.52 or newer and remain compatible with v0.5.0.

v0.4.54 — 2026-05-20 — daemon: skill prose-mode env passthrough, terminal ALPI_HOME/WORKSPACE, send_message profile env

Patch on top of v0.4.53. Four gaps left over from the v0.4.52/.53 env-isolation refactor:

v0.4.53 — 2026-05-20 — daemon: profile-env shortcuts in skills, scheduler, mail, and setup wizards

Patch on top of v0.4.52: that release promised per-profile env isolation but left a handful of skill_eligibility callsites and subprocess-env builders still defaulting to os.environ, plus three setup wizards still mutating it on credential writes. The visible symptom: a chat in profile doc reported coros (and any skill with requires_env) as inactive, because the daemon no longer pre-loaded per-profile .env into the process env and these callsites never picked up effective_profile_env(home). The remaining os.environ mutations after this patch are process-level only (ALPI_PROFILE in cli.py::_resolve_home so child processes inherit the active profile; LITELLM_LOG in llm.py to silence the library at import) — never profile credentials.

v0.4.52 — 2026-05-20 — daemon: multi-profile isolation, seq-only events, lite/detail host plane, Tailscale perf

Daemon-side contract release. Several host.* verbs and the gateway / tools / model-selector internals change at once. The in-repo desktop and mobile clients land their migrations in follow-up commits (desktop-v0.2.20, mobile-v0.1.x); the daemon keeps accepting legacy params silently for older external clients.

Profile isolation — .env is per-profile, daemon never mutates os.environ

Config-merge no longer pollutes DEFAULT_CONFIG

Events — seq-only contract, no more wall-clock pivots

Event invalidations — every mutator now emits something

So clients can refresh without polling:

Workgroup transcript — tail-first contract + group-key reuse

host.chat.sendsession_start is the first frame

Lite/detail split on the hot path

Wire compression

Devices store

Heavy host handlers off the loop

host.profile.summaries, host.profile.storage, host.skills.list, host.workgroups.list, host.workgroup.transcript all run their CPU/IO body via asyncio.to_thread. A 400ms _profile_summary no longer freezes every other coroutine on the host loop.

Tests + packaging

uv run pytest -q: 1837 passed, 76 skipped (--integration / --llm / Linux-only sandbox). Bumped Umbrel package metadata and image tags to 0.4.52.

v0.4.51 — 2026-05-19 — host.network.* RPCs for desktop/mobile pairing config

Closes the parity gap between alpi setup → devices → network (CLI) and the desktop / mobile pairing UI. Previously the desktop's PairDeviceModal could only show whatever host.devices.generate returned and gave no way to switch between Tailscale and LAN or set a custom advertised host — the user had to drop to the terminal. Three new RPCs make the daemon's pairing endpoint queryable and editable over the host plane.

The CLI's _devices_network_setup flow continues to work unchanged. The desktop UI that consumes these RPCs ships in its own release cycle.

v0.4.50 — 2026-05-19 — session list exposes last-turn previews for mobile inbox

Adds two truncated fields to every row returned by host.sessions.list. The mobile inbox previously had to choose between rendering the thread topic (first_user, oldest turn) or pulling the full session per row just to show the latest activity — neither is acceptable for a scrolling list.

v0.4.49 — 2026-05-19 — schedule auto-infers no_agent for shell-style prompts

Closes a foot-gun in the schedule tool: a scheduled job whose prompt looked like a shell command (python3 .../say.py "...") but omitted no_agent=true was accepted as a regular agent prompt — at fire time the daemon then fed the shell line to the LLM as user input instead of running the script. Caller-side mistakes (LLM forgetting the flag) now self-correct at add time.

v0.4.48 — 2026-05-19 — host event backfill + scheduled reply contracts

Host-plane reliability release for desktop/mobile clients and scheduled jobs.

v0.4.47 — 2026-05-18 — host runtime version + Umbrel local package prep

Small compatibility release for desktop/mobile clients and real Umbrel smoke tests.

v0.4.46 — 2026-05-18 — agent date/time grounding

Fix for "hoy es miércoles" hallucinations on long sessions: the agent had zero date/time context in its system prompt and was guessing from training data. New alpi/clock.py module ships two pieces — a cache-stable timezone section baked into the system prompt, and a fresh # NOW block injected as a transient system message before every user turn so the prompt cache never goes stale across midnight, compaction reuse, or 5-min Anthropic cache TTL.

Tests in tests/core/test_clock.py cover TZ env precedence, invalid-TZ fallback, format stability, naive-datetime safety, and DST transitions (Madrid CET/CEST round-trip). tests/core/test_engine_clock.py pins the engine wiring: system prompt carries the TZ section but no rendered local/UTC strings (cache safety), each run_turn appends exactly one # NOW block before the user message, multi-turn sessions keep only the latest block, and stale # NOW blocks planted in session.messages (simulating a reloaded long-running session) get replaced rather than stacked. Full suite 1721 passed / 75 skipped.

v0.4.45 — 2026-05-18 — Telegram profile isolation

Multi-profile daemons now isolate Telegram gateway state per profile. Telegram long-polling allows only one active getUpdates consumer per bot token, so Alpi now treats one Telegram bot per profile as a hard contract and avoids using a sibling profile's env for inbound authorization.

Docs: docs/ARCHITECTURE.md and the bundled knowledge reference document the one-bot-per-profile rule, frozen gateway env snapshots, and the current caveat that Matrix / IMAP still read some credentials directly from os.environ.

v0.4.44 — 2026-05-17 — daemon event bus: 4 new kinds for native desktop notifications

The desktop tray needs daemon-side signals to surface OS-level banners for the moments worth interrupting the user. alpi/host/events.py previously published only session_changed; this release adds four new kinds at the right chokepoints. The desktop consumer ships with desktop-v0.2.19; this release is daemon-only.

Tests in tests/host/test_notification_events.py cover all four kinds at unit level and via a real wc.post() integration that exercises substantive check, gating, encryption, transcript append, and ledger write. Regression test pins profile_name("~/.alpi") == "default". Also fixed test_prune_drops_old_low_confidence which was UTC-vs-local-day flaky (memory writes _today() in UTC; the test used date.today() local).

docs/ARCHITECTURE.md enumerates every wired event kind under the host.events.subscribe section.

v0.4.43 — 2026-05-14 — resource-leak hygiene pass after the RAG bloat hunt

Audit triggered by the v0.4.42 RAG freelist bug. Read-only sweep across SQLite handles, file opens, subprocess pipes, and the live daemon's FD table found a handful of small leaks and one latent deadlock — none catastrophic, but the same shape of slow accumulation that bit us on rag/store.sqlite. Fixed the actionable ones.

What's clean already (per the audit): alpi/tools/db.py uses contextlib.closing on every connection; open_store() callers in workspace._index/_search and core.store.compact/reclaimable_bytes all close in finally; gmail/httpx/Telegram and IMAP/SMTP all use context managers. RAG stores on disk are healthy after v0.4.42 (~23MB / ~2.6MB with negligible reclaimable). No more freelist surprises lurking.

v0.4.42 — 2026-05-14 — whole-machine backup with pre-encrypt preview + RAG bloat fix

Per-profile backup was the wrong primitive: a typical user runs 2–3 profiles and forgetting one defeats the point. alpi backup now archives the entire ~/.alpi/ tree in one shot, shows a per-profile + largest-files preview before prompting for the passphrase, and --force restore is a clean replace instead of an overlay. Surfacing the preview also caught a long-standing bug: a 1.6GB rag/store.sqlite made of 99.997% dead SQLite pages, a force-reindex leak that's now fixed at the source and exposed in setup → Cleanup as a one-click VACUUM.

v0.4.41 — 2026-05-14 — safe_write_secret: atomic credential writes close the TOCTOU window

write_text + chmod 0o600 is two syscalls — between them the file briefly exists at umask perms (0o644) and a local attacker can read it. This release centralizes the pattern in one helper and uses it at every alpi credential write.

v0.4.40 — 2026-05-14 — pre-write lint refuses syntactically broken writes

A malformed jobs.json silently disabled the scheduler in v0.4.39 testing; same class of bug for config.yaml, skill scripts, pyproject.toml. This release runs a parser-based syntax check before every write_file / edit_file lands on disk — on failure the write is refused and the original file (if any) is untouched.

v0.4.39 — 2026-05-13 — no_agent cron mode: skip the LLM for deterministic scripts

Cron jobs whose work is deterministic (data sync, file processors) had no reason to spawn a full agent turn but did, costing ~$0.05–$0.13 and ~20–30s per fire. This release adds an opt-in no_agent: true flag that exec's the prompt as a shell command directly.

v0.4.38 — 2026-05-13 — todo as binding contract: engine re-prompts when the model closes early

The todo tool used to be advisory: a model could add + start a task list and then close the turn with a final text-only message, leaving work unfinished. Cheap models did this routinely ("Hecho" with a 22-byte scaffold). This release turns open todos into a contract the engine enforces.

v0.4.37 — 2026-05-13 — FD leak fix for skill DB calls

Long tool-heavy turns could exhaust the daemon's open-file limit after repeated db tool calls, then surface as unrelated save failures such as ledger.json.tmp.

v0.4.36 — 2026-05-13 — daemon loop isolation + chat event replay sidecar

A scheduled job in one profile could freeze a live chat stream in another because the scheduler tick ran inline on the daemon's asyncio loop. Fixes the cause and adds a client-side recovery path.

v0.4.35 — 2026-05-13 — config surface trim + two save-time bug fixes

v0.4.34 — 2026-05-13 — capability hardening v0.5 (CH.3): memory promotion queue

Auto-compaction must never write to USER.md / MEMORY.md / AGENT.md directly — a single bad summary would otherwise pollute long-term memory. This release introduces a staging queue between compaction and durable memory, with a genuine human-in-the-loop gate.

v0.4.33 — 2026-05-13 — capability hardening v0.5 (CH.2): granular terminal approval allowlist

v0.4.32 — 2026-05-13 — capability hardening v0.5 (CH.1): skill eligibility fields

v0.4.31 — 2026-05-12 — capability hardening v0.5 (CH.0 + CH.4) + compaction event log

v0.4.30 — 2026-05-12 — auto-compact: preemptive context compaction before LLM overflow

v0.4.29 — 2026-05-12 — chat concurrency: interrupt-and-replace on the same session (+ desktop-v0.2.11)

v0.4.28 — 2026-05-12 — per-profile env isolation + silent scheduled jobs + MCP grouping

v0.4.27 — 2026-05-12 — host introspection verbs (tools + skills body)

v0.4.26 — 2026-05-12 — peer status probes + TUI session sync + log rotation

v0.4.25 — 2026-05-12 — streaming link.ask (ALP.4)

v0.4.24 — 2026-05-11 — identity drafting as a primitive

v0.4.23 — 2026-05-11 — memory v2 quality pass (AI(1).c)

v0.4.22 — 2026-05-11 — BA local RAG over workspace/

v0.4.21 — 2026-05-10 — alpi reserved as a profile name

v0.4.20 — 2026-05-09 — robust endpoint detection + diagnostic pairing errors

v0.4.19 — 2026-05-09 — pairing admin is local-only at the transport layer

v0.4.18 — 2026-05-09 — Gmail OAuth from the host plane

v0.4.17 — 2026-05-08 — short timeout on peer-ping probes

v0.4.16 — 2026-05-08 — host plane keeps WebSocket open for multiple RPCs

v0.4.15 — 2026-05-08 — TUI rich-text polish (BB)

v0.4.14 — 2026-05-07 — post-turn memory reviewer (AI(1).b)

v0.4.13 — 2026-05-07 — memory write safety scan (AI(1).a)

v0.4.12 — 2026-05-07 — skill safety primitives (AT)

v0.4.11 — 2026-05-07 — system prompt sharpening for skill quality (AS)

v0.4.10 — 2026-05-07 — desktop connection stability and session listing

v0.4.9 — 2026-05-07 — Umbrel host summaries and pairing labels

v0.4.8 — 2026-05-07 — skill runtime contracts and composition

v0.4.7 — 2026-05-07 — skill execution and schedule guardrails

Five fixes converging on one theme: the agent loop should make it hard to lie about side-effects and easy to do the right thing in one call. Distilled from a real 35-turn session that ended up with a duplicate cron job, a fragmented memory write across 16 calls, and three "done — no, you didn't" exchanges.

v0.4.6 — 2026-05-06 — chat rewrite truncation over host plane

v0.4.5 — 2026-05-06 — schedule no-save + desktop hot-path cleanup

v0.4.4 — 2026-05-06 — daemon PATH for MCP spawns + docs alignment

Fixes MCP servers crashing silently when reached through the daemon (desktop client path): the daemon's launchd / systemd PATH did not see user-installed Node / Python tools, so npx-based servers (e.g. bitbucket-mcp) failed with command not found. The TUI was unaffected — it inherits the user's shell PATH. Plus a docs sweep to match the per-machine daemon reality and a v0.5 roadmap pivot to "owned device access".

v0.4.3 — 2026-05-06 — Umbrel app + companion endpoint cleanup

Closes the first Umbrel-ready deployment of alpi and tightens the device-access story around the host plane. Umbrel now ships as a real app package running the existing TUI behind Umbrel's app proxy, the daemon/setup UX stops pretending systemd or launchd exist inside the container, and Devices gains an explicit network override so mobile and desktop companions can advertise a stable endpoint instead of depending entirely on autodetection.

v0.4.2 — 2026-05-05 — workgroup poller correctness + protocol-aligned language

Tightens workgroup dispatch so peers in the same daemon stop blocking each other, kills a class of wasted dispatches against already-closed tasks, and makes peer agents follow the language of the active #task instead of defaulting to English. ALP wire behaviour is unchanged; alp.v stays at 1. The fixes align the implementation with the protocol description and update ALP.md where the description had drifted.

v0.4.1 — 2026-05-04 — host plane over WebSocket, per-device pairing tokens

Closes the daemon-side foundation for AX-mobile and unifies the desktop control path: the host plane now serves host.* over a WebSocket on Tailscale or LAN in addition to the existing Unix socket, every remote request carries a per-device pairing token, and the desktop Tauri layer routes its previously-shelled-out commands through the same JSON-RPC verbs.

v0.4.0 — 2026-05-03 — secure device access

Closes the alpi side of the v0.4 cycle: profile state now has a shared device-facing host-plane API, profiles are portable through encrypted backup/restore, and desktop/mobile clients can use the daemon contract instead of reading profile files directly.

v0.3.14 — 2026-05-03 — encrypted profile backup / restore

Two new top-level commands close the v0.4 AW roadmap item and make the profile portable between machines: alpi backup writes <profile>.<YYYY-MM-DD>.alpi-backup (single file, 0600, passphrase-encrypted, zero-knowledge); alpi restore PATH reverses it into the active profile, refusing a non-empty target unless --force.

v0.3.12 — 2026-05-03 — default_agent.md slim

Rewrote the persona seed and lifted operative rules into the system prompt. New profiles boot with a 10-line audience-neutral persona (no "engineering-level familiarity assumed", no project- ethos baked in). Project rules live in system_prompt.md where they apply to every profile.

Validation: full reshape via chat (rename to "Mira", add Basque-cuisine expertise, add responsibilities, populate USER + MEMORY) lands cleanly. State integration in follow-up turns works end-to-end — a recipe reply respects expertise, gluten intolerance, family size, the wine-pairing persona rule, and the Thermomix tool note all at once.

v0.3.11 — 2026-05-03 — skills overhaul

Skill surface tightened after a strategic review of comparable agent workflows, plus integration probing on real profiles.

v0.3.10 — 2026-05-02 — alpi diff

What changed in this profile since N hours/days ago — memory edits, sessions, mentions, skills, peer-list mutations, fired schedules, today's budget. mtime-driven, side-effect free, safe from cron or SSH. One primitive (alpi/diff.py) shared by the CLI subcommand and the TUI /diff panel; a host-plane verb will follow once the desktop has a use for it.

v0.3.9 — 2026-05-02 — daemon refactor + host plane

The v0.4 cycle lands as a single 0.3.9 release on the alpi side: a unified per-machine daemon (replacing the per-profile service model), a new host-plane control API for visual / remote clients to talk to, and the cycle of alpi improvements (workgroups protocol overhaul, peer mention via link.ask, mention thread fix, pending invites, gateway session isolation, budget-zone signal, test reorg). The first public Tauri desktop client ships on its own track as desktop-v0.1.0 — see desktop/CHANGELOG.md.

alpi cycle

Daemon

Host plane

Desktop

v0.3.8 — 2026-04-28 — security audit hardening

External audit verdict landed; 9 of 10 verified findings hold. This release closes them in P0/P1/P2 order without changing public behaviour for existing profiles.

v0.3.7 — 2026-04-28 — Email PGP + test env isolation fix

Closes Email PGP from v0.4. Outbound IMAP/Gmail messages are signed with the configured key and encrypted when every recipient has a public key on ~/.gnupg; inbound multipart/encrypted is decrypted before the agent reads it. Default off. Also fixes a test fixture that copied the dev's real ~/.alpi/.env into every test home, leaking TELEGRAM_BOT_TOKEN + API keys into os.environ for the test process.

v0.3.6 — 2026-04-28 — terminal subprocess env scoping (AV)

Closes roadmap AV. The terminal() tool now starts every subprocess with an explicit env= dict instead of inheriting the parent's os.environ — a prompt-injected skill running terminal('env') no longer sees OPENAI_API_KEY or any other secret. Skills opt back into specific vars via SKILL.md frontmatter env: [FOO], scoped per-turn.

v0.3.5 — 2026-04-28 — TUI input responsiveness + multi-line paste

Closes roadmap BG early. Two compounding daily-UX TUI bugs: typing lagged during streaming because every delta re-parsed markdown via Markdown.get_stream().write(), and multi-line paste delivered only the first line because Textual's Input hardcodes splitlines()[0]. Fix renders in-flight tokens into a cheap Static and swaps to Markdown once finalised; a ChatInput subclass flattens pasted newlines to spaces.

v0.3.4 — 2026-04-28 — workgroup hardening for tier-2 models

Workgroups now keep workflow shape on tier-2 models (gpt-5.4-nano). Three failures fixed: members closing tasks they couldn't close, infinite refinement loops, deadlocks when every peer was caught up. Discipline moves from per-workgroup briefings (which small models ignored) into protocol + dispatcher. A 12-post nano run that previously looped now closes at post 6.

v0.3.3 — 2026-04-28 — workgroup poller + capability fixes

Two ALP.3 bugs kept workgroups from cycling: a hub posting #task in its own workgroup didn't wake its local agent, and joiners couldn't pull because workgroup.join doesn't add workgroup.* to the peer's allow:, hitting -32001 capability-denied. Also extracts curated provider model lists into shared YAML for the desktop app + adds two hidden chat flags for desktop GUI drive.

v0.3.2 — 2026-04-27 — @peer and doctor reach remote peers

Two bugs kept ALP.2 (TCP/Noise) traffic from working in practice. A peer pinned with address: (the canonical "remote machine" signal) was rejected by the highest-traffic code paths and misreported by the health check, so a Tailscale- exposed peer looked unreachable from outside even when its TCP listener was accepting Noise handshakes.

v0.3.1 — 2026-04-27 — brand accent unified

Single brand accent #c8a24e across every alpi surface. TUI dropped its orange #ff8800, the marketing site dropped #a89b76, and both adopt the warmer gold the desktop app uses. Existing profiles with custom tui.accent keep their override.

v0.3.0 — 2026-04-26 — public release

First public release of alpi: installable from PyPI (uv tool install alpi-agent); docs, site, and onboarding stable for external users. The v0.3 cycle stacked the work that makes alpi usable beyond a single hacker on a laptop. Per-patch detail preserved in v0.2.x entries below.

v0.2.97 — 2026-04-26

@alpi/knowledge — first bundled skill

alpi's first bundled skill bundles 12 user-facing docs as package resources so the agent answers questions about alpi without web_search or training-data guesses. SKILL.md carries a topic→reference routing table; skills index has an imperative rule biasing small models (~70% follow on nano).

v0.2.96 — 2026-04-26

@<peer> mentions match anywhere in the text — ALP.3.1

The @<peer> shortcut now fires anywhere in the text — "hey @builder can you check?" pings builder naturally. Boundary rules: @ must follow whitespace or be at position 0 (email@gmail.com skips), and the id must resolve to a pinned peer (@property falls to LLM). #task/#done stay strict line-start — state-change markers must not fire by accident.

v0.2.95 — 2026-04-26

alpi update — version check and self-upgrade

alpi tells you when there's a new release on PyPI. Daemon thread on every alpi invocation (8h TTL) writes ~/.alpi/cache/update_check.json; doctor + TUI top bar read the cache. alpi update bypasses the cache, detects install method (uv tool / pipx / dev), upgrades, verifies new version matches PyPI.

v0.2.94 — 2026-04-26

browser tool — Chromium downloads itself on first use

The browser tool already JIT-installed Chromium on first run; docs hadn't caught up and still told users to run playwright install chromium themselves. Aligns docs with code: no separate install step, ~200MB download cached at ~/.cache/ms-playwright/, users who never browse pay nothing.

v0.2.93 — 2026-04-26

distribution — first PyPI publish path

Installable from PyPI as alpi-agent — closes AU. CLI binary + Python import + ~/.alpi/ stay alpi. Auto-publish on push to main when pyproject.toml version differs from PyPI; smoke install across 5 container images (Python 3.10/3.11/3.12-slim, Ubuntu 22.04, Debian 12); OIDC Trusted Publisher; auto-tag + GitHub release with CHANGELOG body.

v0.2.92 — 2026-04-26

self-published member bios in workgroups

Each profile carries an optional one-line public_bio that propagates to every workgroup it joins. Surfaces in roster as @alice (online, "product engineer — velocity") so agents see who-does-what from turn 1. AGENT.md stays private. Inverts earlier creator-assigned roles (which didn't scale).

v0.2.91 — 2026-04-26

alp.3 — workgroups (PR 5): functional autonomy

Closes ALP.3. Workgroups self-drive: each member's service polls the hub on a 30s tick and dispatches one engine turn when a post mentions them, opens a collective #task, or names them in the active task. 60s per-workgroup cooldown rate-limits ping-pong. Suite: 860.

v0.2.90 — 2026-04-25

service unification — one process per profile

Three legacy daemons (gateway, scheduler, ALP) collapse into a single alpi service per profile. One asyncio loop hosts every enabled subsystem — one PID, one log, one launchd/systemd unit. Memory drops ~2/3. Every profile now starts opt-in (auto-install of scheduler removed, aligning with sandbox / budgets / peers).

v0.2.89 — 2026-04-25

alp.3 — workgroups: pause/resume + member state + management UX

Protocol gains workgroup.pause/resume (idempotent; post returns -32010 workgroup-paused; pull/join/leave keep working — pause must not trap members). Members get their own Subscription state + full management surface. Hub identity is explicit per subscription (probing pinned peers would leak the id and let a malicious peer impersonate by pre-creating a same-id workgroup).

v0.2.88 — 2026-04-25

alp.3 — workgroups (PR 2: leave + rekey + lifetime budget)

Members can leave; hub rotates the group key for remaining members (forward secrecy: old key opens past posts, fails on new ones). Optional lifetime budget (USD or tokens, project-scoped, no daily reset) — posts double-gate on top of profile cap. Profile gate fires upstream of workgroup gate.

v0.2.87 — 2026-04-25

alp.3 — workgroups (PR 1: hub state + 4 core verbs)

Hub side of shared workgroups: profile can create with a chosen roster; pinned remote peers join/post/pull over existing ALP transport (Unix or Noise_XK/TCP). End-to-end encrypted: hub stores ciphertext, group keys sealed per-member. Suite: 789 (was 769).

v0.2.86 — 2026-04-25

setup wizard — section headings + copy pass

alpi setup main menu splits into 5 sections (Agent, Boundaries, Messaging, ALP, Maintenance); model picker into Local/Cloud/Manage. Headings non-selectable, verbatim rendering, auto-spaced. Copy pass across the wizard — Sandbox/Workspace/Budget/TCP-port dim blocks trimmed to 3–6 lines; daemon-service wizards reduced to one line each.

v0.2.85 — 2026-04-25

security — profile .env and config.yaml off-limits to tools

File tools and terminal refuse to read/write the active profile's .env and config.yaml (provider API keys, gateway tokens, sandbox flag, allowlist). A prompt-injected mailbox or page can't coax the agent into leaking or rewriting them; they stay editable by hand or alpi setup. Workspace .env outside ~/.alpi/ deliberately untouched (path-scoped, not basename-scoped).

v0.2.84 — 2026-04-25

budget — daily spending ledger, profile-level cap

Every spend path flows through one ledger + one cap (budget.daily_usd or daily_tokens); per-peer sub-caps dropped — peer trust lives in capabilities + rate limits. Verified live on bob with daily_usd: $0.05; /status reads daily budget $0.0554 / $0.05 · capped.

v0.2.83 — 2026-04-24

alp — inter-machine Noise_XK transport, rate limits, wizard

Inter-machine half of ALP. Peers with address in peers.yaml route over TCP+Noise_XK; ALP.1 Unix socket untouched. New roadmap BG scopes v0.3 budget shape (one ceiling per profile, daily_usd or daily_tokens). Verified on same host and over Tailscale via MagicDNS.

v0.2.82 — 2026-04-24

site/docs — private agent network narrative + tool polish

Public narrative matches product shape: alpi is a profile- based personal AI that grows into a private network across machines. Third pass on AT (prompt + tool descriptions audit against comparable persistent-agent behaviour) — three targeted additions.

v0.2.80 — 2026-04-24

site — header/nav unified, docs index redesigned, SEO at 100%

Second pass on the static site under site/. Single shared nav across landing//docs///docs/*; combined logo + alpaca favicon; burger menu under 760px in <20 lines inline JS. SEO across every page: unique title/description, canonical, Open Graph, Twitter Card with @soyjavi, JSON-LD, sitemap.xml (16 URLs with lastmod) + robots.txt on every build.

v0.2.79 — 2026-04-24

site — static marketing + docs scaffold under site/

First cut of alpi.site as zero-dependency static site: vanilla HTML/CSS/JS + single Node build script reads README.md, QUICKSTART.md, CHANGELOG.md, LICENSE, docs/*.md at HEAD and bakes site/dist/ — landing at /, doc index, one pre-rendered HTML per doc. Versions derived from pyproject.toml; no runtime fetch, CORS, or rate limits.

v0.2.78 — 2026-04-24

skills — auto-validate on every mutation

Every mutating action on a user skill (create/edit/patch/ add_file/remove_file) runs _skill_validate.validate_skill (py_compile, missing imports, OAuth race, port coherence) and surfaces findings inline so the LLM iterates without a separate validate call. Reverted the @alpi/plan experiment — @alpi/* stays reserved + live, but nothing ships by default until concrete patterns justify it.

v0.2.77 — 2026-04-24

skills — bundled infrastructure (BE closed)

Read-only namespace for skills shipped with the alpi package; no content bundled yet, infrastructure only. Bundled skills addressed as @alpi/<name>; @ not legal as on-disk category so collisions impossible. Suite: 692.

v0.2.76 — 2026-04-24

Textual 8.2.3 exposes only @click meta on markdown link spans, no style — links rendered as plain prose. Fix monkey- patches MarkdownBlock._token_to_content at import to add bold+underline on @click spans (idempotent, global). /memory panel replaces the code-block hack with stacked Static headers + per-entry Markdown widgets split on §. Streaming input lag fixed by 12.5Hz timer coalesce vs ~60/s asyncio.create_task per delta.

v0.2.75 — 2026-04-24

wizard / cli — profile lifecycle + polish

New alpi -p <name> setup → Delete profile (non-default profiles only) — one-shot teardown: summary → service warning → typed-name confirmation → uninstall services → rmtree → exit. Collapses what was "uninstall each service manually, then alpi profile remove" into a single guided action. "Did you mean…?" suggestions across profile remove, peers remove/ping, schedule fire via shared _suggest() (difflib).

v0.2.74 — 2026-04-24

schedule — ad-hoc job fire (BA closed)

Closes the tightest feedback loop in schedule lifecycle: add cron, verify it works, without waiting for the cron window.

v0.2.73 — 2026-04-24

skills / memory / docs — stop shipping what we don't use

Deleted the alpi/skills/ package — only blueprint (meta/consolidate-memory/SKILL.md) never reached profiles (skill tool only searches {home}/skills/). Runtime skills system untouched — ~/.alpi/skills/<category>/<name>/ still works.

v0.2.72 — 2026-04-24

memory — v2 rules (AI partial)

Renames PERSONALITY.mdAGENT.md across codebase / prompts / tests / docs (user/agent pair now symmetric). File migration manual per project policy. Char limits: USER.md 1375→3000, MEMORY.md 2200→5000.

v0.2.71 — 2026-04-24

engine / prompts (AT partial — 4 of 5 candidate edits applied)

Per-surface platform hint: _platform_hint() in alpi/engine.py reads ALPI_PLATFORM and injects a matching block (cron/telegram/email/gmail). Cron jobs stop asking phantom users for clarification; Telegram replies arrive Markdown-aware; email replies plain-text-only. New BD for v0.3 (model-aware tool-use guidance — needs agent.log A/B).

v0.2.70 — 2026-04-23

license + foundational docs

Repo re-licensed under Business Source Licence 1.1. Licensor: Satoshi Ltd. Change Date 2030-04-23 → Apache 2.0. Additional Use Grant for personal/research/non-commercial; commercial production requires a licence from info@satoshi-ltd.com. Repo rooted in Satoshi Ltd.'s six operating principles, each doc mapping to its principle.

v0.2.69 — 2026-04-23

models

v0.2.68 — 2026-04-23

ALP.1 ships: Ed25519 identity, signed JSON-RPC envelope with replay cache, fail-closed peer list, Unix-socket server + client. link.ping, link.ask (reject-fast reentrancy), link.cancel (idempotent). Setup wizard health-check no longer blocks menu render on 5–10s of probes — runs on-demand.

v0.2.54 — 2026-04-23

gateway

v0.2.1 – v0.2.53 — 2026-04-21 → 2026-04-23

Two days of rapid iteration after the v0.2.0 split. Patch bumps collapsed into thematic groups; full per-commit detail in git log.

v0.2.0 — 2026-04-21

Foundational v0.2 cut: split CONTEXT → ARCHITECTURE + ROADMAP, positions alf as a lighter private-agent runtime; tiered model docs; profile propagation through tool context; new send_message + schedule

v0.1.0 — 2026-04-19

misc

theme