Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d961f7d
Chats can be archived, not just deleted
join3r Oct 13, 2026
6183d09
Show generated pictures as soon as each call ends
join3r Oct 13, 2026
137259f
Browser control on Linux
join3r Oct 13, 2026
ae0788a
Browser control on Linux: start only browsers Stem knows
join3r Oct 13, 2026
e140619
Test Linux from a Mac, and browser control end to end
join3r Oct 13, 2026
491fe89
Merge branch '0.7.0--add-archive-to-chats-not-just-delete' into 0.7.0
join3r Oct 15, 2026
a3c7ab9
Merge branch '0.7.0--i-wonder.-witch-features-are-available-o' into 0…
join3r Oct 15, 2026
3712c10
Discuss window bugs
join3r Oct 15, 2026
e280696
Mail-driven status queries for Chaptarr
join3r Oct 15, 2026
54709e1
In the ios app, remove the green connected icon a…
join3r Oct 15, 2026
b9f0164
Secretary vs. Normal Persona
join3r Oct 15, 2026
3a34b2a
Check AlphaRatio audiobook torrent mail
join3r Oct 15, 2026
7f18055
Deploy to VPS and build DMG
join3r Oct 15, 2026
c4c7c4a
Check the mail Missing Crypt Mage Artwork
join3r Oct 15, 2026
f39be8c
remote mails
join3r Oct 15, 2026
d527d95
Deploy to VPS and build DMG
join3r Oct 15, 2026
68dad30
Nejasný stav práce modelu
join3r Oct 15, 2026
ed0dd24
Generate missing crypt art
join3r Oct 15, 2026
8f4d9af
Move global relay to relay.stem
join3r Oct 16, 2026
bcbf799
Company relay isolation via DNS
join3r Oct 16, 2026
84ebc90
Inject MCP Server Context Upfront
join3r Oct 17, 2026
6f80962
Stale chat preview in mail
join3r Oct 18, 2026
a4d8048
Slow chat loading on iOS
join3r Oct 18, 2026
0264fe6
Clickable map addresses in iOS
join3r Oct 18, 2026
ca5423d
Pele vs Mermaid for STEM diagrams
join3r Oct 18, 2026
64a1858
Chyba zobrazenia textu v dlhých chatoch
join3r Oct 18, 2026
ada8587
iOS Stem chat folders missing
join3r Oct 18, 2026
65eb98e
Multiple profiles for Stem
join3r Oct 18, 2026
6ed6066
Linux feature parity feasibility
join3r Oct 18, 2026
fff6928
HEIC attachment conversion
join3r Oct 18, 2026
c4705ef
Review previous chat session
join3r Oct 18, 2026
fe53ac0
Feature parity gaps across platforms
join3r Oct 19, 2026
265d6d8
Discussing menu in STEM
join3r Oct 19, 2026
a7fa029
Výber domény pre STEM
join3r Oct 19, 2026
9514914
Awantech billing details review
join3r Oct 19, 2026
1ee9bb7
Zarovnanie výberov menu v Linuxe
join3r Oct 19, 2026
4dbba21
Pridanie zdieľania odpovedí a threadov
join3r Oct 19, 2026
1ffd953
Aktualizácia nastavení zdieľania
join3r Oct 19, 2026
1539334
Prezretie posledného chatu
join3r Oct 19, 2026
ea997c7
Asi je čas rozbehať overovacie emaily na heystem.…
join3r Oct 19, 2026
2a57902
Linux AppImage browser support
join3r Oct 19, 2026
0ac6755
Release 0.7.0 windows exe packaging
join3r Oct 19, 2026
1e68f19
Release 0.7.0
join3r Oct 19, 2026
4ff6fdd
Docs for 0.7.0: mail with other Stems, share links, Windows and Linux
join3r Oct 19, 2026
df3f265
Release: retry stapling the notarized DMG
join3r Oct 19, 2026
6ae6a5a
E2E: browser-live spawns Chrome with a mock keychain on macOS
join3r Oct 19, 2026
eacb497
Release: retry the mac build when stapling loses Apple's connection
join3r Oct 19, 2026
fab5d51
Release + E2E: ride out Apple's dropped stapler connections and a slo…
join3r Oct 19, 2026
080751c
Release: a DMG ticket Apple accepted but CloudKit won't hand over is …
join3r Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ docs/screenshots
# that survives every `docker save` and every registry push.
stem_key
*.tar

# The relay is a separate Go program with its own image (relay/Dockerfile).
relay
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ jobs:
- name: Headless server boots under plain node
run: npm run test:server

# tests/e2e/browser-live.spec.ts drives a real Chromium with the Stem
# extension through the native host — the one check of the per-platform
# browser-control glue. It skips itself when no browser is installed.
- name: Install Chromium for the browser-control E2E
run: npx playwright install ${{ runner.os == 'Linux' && '--with-deps' || '' }} chromium

- name: E2E tests (Playwright + Electron)
run: ${{ runner.os == 'Linux' && 'xvfb-run --auto-servernum --' || '' }} npm run test:e2e

Expand Down Expand Up @@ -94,3 +100,17 @@ jobs:

- name: Unit tests (Vitest, Windows-relevant subset)
run: npm run test:win

relay:
runs-on: ubuntu-latest
defaults:
run:
working-directory: relay
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: relay/go.mod
cache-dependency-path: relay/go.sum
- run: go vet ./...
- run: go test ./...
60 changes: 57 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ name: Release
on:
push:
tags: ['v*']
# Run by hand (Actions → Release → Run workflow, or `gh workflow run release.yml
# --ref <branch>`) to build every installer from a branch before tagging; the
# installers land as workflow artifacts and nothing is published.
workflow_dispatch:

permissions:
contents: write
Expand Down Expand Up @@ -121,13 +125,30 @@ jobs:
env:
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
# Sign while electron-builder's temporary signing keychain is available.
- run: npm run dist:mac -- --arm64 --config.forceCodeSigning=true --config.dmg.sign=true
# Stapling fetches the ticket from Apple's CloudKit, and the connection
# from GitHub's macOS runners drops now and then (Error 68, "The network
# connection was lost") after Apple has already accepted the app. Build
# again rather than fail the release on it.
- name: Build, sign and notarize
run: |
for attempt in 1 2 3; do
if npm run dist:mac -- --arm64 --config.forceCodeSigning=true --config.dmg.sign=true; then exit 0; fi
echo "::warning::dist:mac failed (attempt $attempt)"
rm -rf release
sleep 30
done
exit 1
- name: Verify signed and notarized app
run: |
app=release/mac-arm64/Stem.app
test "$(lipo -archs "$app/Contents/MacOS/Stem")" = arm64
codesign --verify --deep --strict --verbose=2 "$app"
xcrun stapler validate "$app"
# validate asks Apple's CloudKit too; see the build step above.
for attempt in 1 2 3 4 5 6; do
if xcrun stapler validate "$app"; then break; fi
if [ "$attempt" = 6 ]; then exit 1; fi
sleep 20
done
spctl --assess --type execute --verbose=4 "$app"
- name: Notarize and verify final DMG
run: bash scripts/notarize-mac-dmg.sh release/*-arm64.dmg
Expand All @@ -152,8 +173,41 @@ jobs:
if: always()
run: rm -f "$RUNNER_TEMP/AuthKey.p8"

windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
cache: npm
- run: npm ci
# Unsigned: no Windows code-signing certificate yet (see the `win` block
# in electron-builder.yml).
- run: npm run dist:win
- name: Packaged app is sound
shell: bash
run: |
app=release/win-unpacked/resources/app
node "$app/node_modules/@earendil-works/pi-coding-agent/dist/cli.js" --version
for stray in src tests ios docs scripts Dockerfile; do
if [ -e "$app/$stray" ]; then echo "::error::$stray/ leaked into the packaged app"; exit 1; fi
done
ls "$app/node_modules/onnxruntime-node/bin/napi-v6"
# latest.yml + the installer's blockmap are what an installed Stem
# updates from (src/desktop/updates.ts).
- uses: actions/upload-artifact@v4
with:
name: windows
if-no-files-found: error
path: |
release/Stem-Setup-*.exe
release/Stem-Setup-*.exe.blockmap
release/latest.yml

publish:
needs: [linux-x64, mac]
needs: [linux-x64, linux-arm64, mac, windows]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
node_modules/
node_modules
dist/
out/
# electron-builder artifacts (see electron-builder.yml directories.output)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<p align="center">
<a href="https://github.com/join3r/stem/releases/latest"><b>Download</b></a>
· macOS (Apple Silicon) · Linux (AppImage, deb) ·
· macOS (Apple Silicon) · Linux (AppImage, deb) · Windows ·
<a href="docs/README.md">User guide</a>
</p>

Expand Down Expand Up @@ -114,7 +114,7 @@ A global shortcut opens Quick Chat over whatever app you're in. Ask, hit Enter,
- **Coding agents.** A persona hands work to Claude Code or any other ACP agent, on the server or on one of your computers. The agent's permission requests arrive as cards in the chat.
- **Computer control (alpha).** A persona pinned to your Mac can work in its apps, including windows on another Space or behind other windows. macOS 14 or newer.
- **Skill recorder (alpha).** Record yourself doing a task on the Mac. Stem writes it up as a draft skill, and a practice run tries it before you save it.
- **Browser control.** The Stem extension for Chrome, Arc, Dia, Brave, Edge and Chromium lets Stem use your own signed-in browser in background tabs.
- **Browser control.** The Stem extension for Chrome, Arc, Dia, Brave, Edge and Chromium lets Stem use your own signed-in browser in background tabs, on a Mac or Linux.
- **Scheduled tasks.** Ask for "every weekday at 8, check…" and you get a cron job. Each run starts in a fresh thread.
- **Shell commands.** A safety check runs what you asked for and turns the rest back. You decide only after repeated refusals, and you can always allow commands by name or pattern.
- **MCP servers and skills.** Add MCP servers by command or URL, OAuth included. Stem writes skills from work that went well and rewrites the ones that failed.
Expand Down
71 changes: 71 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,77 @@ Maintainer notes:
date, tag.
-->

## 0.7.0 — 2026-10-19

### Added

- **Mail with other people's Stems.** Add your email address under Settings → Features → **Your
email address** and confirm the code Stem emails you. People who use Stem can then mail you there,
and you can mail them. Mail is encrypted from one Stem to the other and is text only for now. Mail
from someone new waits under **Requests** until you accept them. Your personas see an incoming
mail only after you let them, and a reply a persona drafts goes out only after you approve it.
**Only people I've written to can reach me** keeps everyone else from finding out that you use
Stem. Compare keys in person to mark a contact as checked. Requests and drafts are on the desktop
only.
- **Share links.** Hover an answer and click the share icon to publish the whole chat, the question
and answer, or the answer alone as a link anyone can open. The content is encrypted in your Stem,
and the key is part of the link, so the server that hosts it can't read it. Links show a preview
card in chat apps, stay out of search engines, and expire after 30 days. Settings lists your links
so you can take one down. Sharing needs a verified email address, and a company that limits mail
with other Stems turns it off. It works from the iPhone too.
- **Ask about this window.** A second Quick Chat shortcut opens Quick Chat next to the window you're
in, with a picture and the text of that window attached. Ask "What does Jana need from me?" in
Slack and the answer appears beside it. If one of your MCP servers covers that app, Stem uses it
to read what the window doesn't show. With computer control allowed, Stem can also click and type
in that window. Set the shortcut under Settings → Quick Chat. Works on the Mac, Windows and Linux
(GNOME).
- **Computer control on Windows and Linux (Alpha).** "Let Stem control this computer" now works on
Windows 10 and 11, and on Linux under GNOME on Wayland. On Linux, Stem installs a small GNOME
extension from Settings → Features → Computer control. You log out and back in once after the
first install, and later updates arrive without a login. Moving your own mouse or pressing a key
stops a run.
- **Browser control on Windows and Linux (Beta).** The Stem extension now works in Chrome, Edge,
Brave and Chromium on Windows and Linux, and in Chromium-based AppImages such as Helium. Browsers
installed as Snap or Flatpak can't run it.
- **Several browser profiles.** If you keep separate browser profiles for work and home, each one
connects on its own. Name them under Settings → Features → Browser control, pick the one tasks
start in, and limit a persona or chat to the profiles it may use. Asked for your open tabs, Stem
lists them by profile.
- **Dictation on Windows and Linux (Beta).** The microphone button now works there too, with Whisper
running on your computer. Its model downloads the first time you use it, and the audio never
leaves your computer.
- **Secretary brings in help on its own.** A Secretary mail now adds whichever personas the job
needs, including ones that control your computer, and sees the errand through. Use **Normal** if
you want to add personas yourself.

### Changed

- **The iPhone opens faster.** The chat list and mail show the last list at once and load less over
the network, so a slow connection no longer means a long wait.
- **Connected folders skip ignored files.** A mirrored folder leaves out what its `.gitignore`
leaves out.

### Fixed

- **Several pictures made at once all show.** When Stem made a few pictures in one go, all but the
last read "no longer available" until you reopened the chat.
- **A long chat on the iPhone no longer goes blank** after you send a message.
- **Every HEIC photo from the iPhone arrives.** Some HEIC and HEIF variants were sent without being
converted to JPEG and couldn't be read.
- **A scheduled task survives a server restart.** A run the server died under is now recorded and
run once more, instead of being lost.
- **Long sign-ins finish.** Signing in during onboarding no longer gets stuck when it takes more
than five minutes.
- **Answered approvals leave the Inbox.** Answering an approval in mail moves that conversation out
of the Inbox, and archiving a chat clears its Return-to-chat row.
- **Named chats stay read.** A chat Stem named after its first turn no longer turned bold again.
- **The working dots stay** under a reply that's still being written, so you can tell it isn't
finished.
- **Big servers start.** On a server with many chats, the chat list scan at startup could run out of
memory.
- **The first launch on Windows works.** Windows scans every file on the first launch after an
install or update, which made Stem time out before it could answer.

## 0.6.1 — 2026-10-13

### Fixed
Expand Down
13 changes: 9 additions & 4 deletions deploy/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ TZ=Europe/Bratislava

# ---- Push notifications to the iOS app (optional; off unless all four are set) ----
#
# Without these, Stem sends no notifications and does no work towards them — the
# server is exactly what it was. With them, an approval card, a long turn ending
# or a task alert also taps the phone on the shoulder; the notification carries
# ids and a short label and never a message (src/server/push/).
# You don't need these. Without them, Stem wakes the phone through the global
# relay's push gateway, which shows fixed wording only ("Approval needed") and
# sees the device token and ids, never a message. STEM_PUSH_GATEWAY=off turns
# that off; STEM_PUSH_GATEWAY_URL points it at another relay.
#
# With them, this server talks to Apple itself: an approval card, a long turn
# ending or a task alert taps the phone on the shoulder with ids and a short
# label and never a message (src/server/push/). Only the holder of the app's
# APNs key can do this.
#
# The key is the .p8 Apple hands you once, for a key with the APNs service
# enabled. It has to be INSIDE the container, so mount it in docker-compose.yml
Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Pick the feature you see in Stem.
| [Chats](user/chats.md) | Ask, attach files, organize conversations |
| [Quick Chat](user/quick-chat.md) | Ask from any app |
| [Mail](user/mail.md) | Send requests to personas and get replies in your Inbox |
| [Mail with other Stems](user/other-stems.md) | Write to people who use Stem, with your personas drafting the replies |
| [Share links](user/share-links.md) | Publish an answer or a chat as a link anyone can open |
| [Memory](user/memory/README.md) | Learn useful context and recall earlier chats |
| └ [Facts](user/memory/facts.md) | Durable details: preferences, people, projects |
| └ [Past chats](user/memory/recall.md) | Recall: find relevant parts of past conversations |
Expand Down
2 changes: 1 addition & 1 deletion docs/assistant/assistant-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

Stem is NOT running on the computer the user is typing on. Stem itself runs on a server they own (Linux, macOS or Windows); the app in front of them is a client talking to it over the network, and their phone may be another. Your `run_command` shell, the files you read and write, and every MCP server that is not pinned to one of their computers run ON THAT SERVER.

So: the server has what a server has installed, not what their own computer has, and it cannot reach an address on their home network. When something fails there because a program is missing, say plainly which machine is missing it instead of asking them to check their own. Do not tell them your shell "does not run on your computer" as though you had no shell — you have the server's, which is the right one for anything belonging to Stem. If a job genuinely has to happen on their own computer, you may have two ways in: `run_command` with its `device` parameter runs a shell command on one of their own computers (only one that has switched on "accepts commands" — your per-turn context names them), and an MCP server pinned to that computer covers everything else; read the `assistant-mcp` and `mcp-servers` guide pages. The `device` shell is for shell work — files, git, scripts, `open -a`. Driving that computer's screen (System Settings, clicking, typing, AppleScript at System Events or at an app) is the job of the `computer` tool: a persona pinned to that computer in the persona editor has it, and so does a chat with no persona when the user allowed computer control in chats (Settings → Features). A persona chat without a pin never has it, whatever that switch says. When a persona is pinned to the computer, a GUI-scripting command from a conversation that may not drive it is refused with the persona's name. Hand the task to that persona (send_mail it in a mail conversation the user added it to) or tell the user to ask it, rather than scripting around it. Coding agents follow the same rule: a persona's coding setup, or Settings → Features → Coding agents for chats with no persona. So does the user's browser: the `browser` tool (the Stem extension in their own Arc or Chrome) comes from a persona's browser pin or Settings → Features → Browser control; web pages go through it, not through `computer` or a browser opened over `run_command`.
So: the server has what a server has installed, not what their own computer has, and it cannot reach an address on their home network. When something fails there because a program is missing, say plainly which machine is missing it instead of asking them to check their own. Do not tell them your shell "does not run on your computer" as though you had no shell — you have the server's, which is the right one for anything belonging to Stem. If a job genuinely has to happen on their own computer, you may have two ways in: `run_command` with its `device` parameter runs a shell command on one of their own computers (only one that has switched on "accepts commands" — your per-turn context names them), and an MCP server pinned to that computer covers everything else; read the `assistant-mcp` and `mcp-servers` guide pages. The `device` shell is for shell work — files, git, scripts, `open -a`. Driving that computer's screen (System Settings, clicking, typing, AppleScript at System Events or at an app) is the job of the `computer` tool, on a Mac, on Windows 10 and 11, and on Linux under GNOME on Wayland: a persona pinned to that computer in the persona editor has it, and so does a chat with no persona when the user allowed computer control in chats (Settings → Features). A persona chat without a pin never has it, whatever that switch says. When a persona is pinned to the computer, a GUI-scripting command from a conversation that may not drive it is refused with the persona's name. Hand the task to that persona (send_mail it in a mail conversation the user added it to) or tell the user to ask it, rather than scripting around it. Coding agents follow the same rule: a persona's coding setup, or Settings → Features → Coding agents for chats with no persona. So does the user's browser: the `browser` tool (the Stem extension in their own Chrome-family browser: Arc, Chrome, Edge, Brave and the like) comes from a persona's browser pin or Settings → Features → Browser control; web pages go through it, not through `computer` or a browser opened over `run_command`.

A program the server lacks is often still one command away, so try these before declaring it missing: anything published on PyPI runs as `uvx <tool>` (`uvx yt-dlp <url>`) and anything on npm as `npx -y <package>`, with no install step — the download is kept, so it is only slow the first time. A tool you will reach for again can go on the PATH with `uv tool install <tool>`; those land in a folder that survives server upgrades. `apt-get install` also works (the run pauses for the user's approval) and is the way to a system-level program like `ffmpeg` — but an upgrade replaces the container and an apt install goes with it, so when you resort to apt, say so and tell the user that a few lines in a `Dockerfile.local` beside the server's docker-compose.yml make it permanent (the "Running on a server" doc in the Stem repository shows exactly the lines).
Loading
Loading