## File: README.md

---

## ✨ Why HolaOS is different

Most agent products hand you a finished product and hope it fits your work. HolaOS hands you the parts. Apps, chat tools, skills, integrations, models, agents, memory — you assemble the workspace around how your work actually runs, and change it whenever the work changes. Because everything runs locally, customizing it never means handing your work to someone else's cloud.


### 🪟 HolaApps — apps and agent, side by side

Install apps from the in-workspace marketplace and they open as **real, interactive surfaces right beside your agent.** Watch it work inside the app, step in whenever you want, and the result lands in place — not a wall of chat text, but the actual app, driven by the agent, next to the agent.

- **Real surfaces, not chat** — every app is a live UI (Notion, a browser, your own app), not a transcript.
- **Side-by-side by design** — app and agent share the screen, so you always see what's happening and can take over.
- **One click to install** — browse the in-workspace marketplace and open any app instantly.
- **Bring your own** — point a HolaApp at any URL and MCP server; it lives on your machine, yours to open and drive.
- Context stays in sync both ways — drive the app by hand and the agent keeps up. Whatever you click, type, or open in the UI becomes context the agent already has, so you never stop to re-explain what you just did.



### 💬 IM — plug in the chat tools your team already lives in

Most work context never makes it into a document. It's in a Slack thread, a Feishu group, a DingTalk message. Connect the chat tools your team already uses and your agent works from the real conversation — not from your summary of it.

- **Where the context really is** — decisions, requirements, and changes get made in chat and stay there. The agent reads them directly, so you stop re-explaining what was already said.

- **The tools your team is already in** — Slack, Feishu, DingTalk, WeChat. Connect the ones you use, skip the ones you don't.

- **You decide what it can see** — access is granted per tool and per scope, and the agent reads nothing until you approve it.

### 🧩 Skills, integrations, and MCP — add any capability without building one

- **Integrations** — connect Gmail, Notion, Slack, GitHub, Linear and 50+ more with one-click OAuth. Agents read and act across your tools, no glue code — and every agent inherits the same connections.
- **MCP** — plug in any Model Context Protocol server to give your agents new tools. Bring your own, or install community MCP servers in one click.
- **Skills** — package a workflow once; any agent runs it on demand.
- **Combos** — bundle skills and integrations into a single one-click install.



### 💸 Models your way — pick the right one per task, or bring your own

One account, every model — no keys, no setup, no switching between providers. The latest frontier models are **built in**: cost-efficient **Kimi K3** and **GLM 5.2** for everyday volume, plus top-tier **GPT 5.6**, **Claude Opus 5**, and **Fable 5** for the hard problems. Prefer your own provider? **Bring your own keys** for OpenAI, Anthropic, or any OpenAI- or Anthropic-compatible endpoint — those run on _your_ account, not your holaOS plan.

- **Zero-setup default** — one account, every SOTA model, no API keys to manage.
- **BYOK when you want it** — your keys, your providers, your rates.
- **Right model per task** — pick per job, per agent.


### 🔀 Agents — run the agent you prefer, not the one we picked

Claude Code, Codex, and the built-in holaOS agent — side by side, no switching. Whichever you run, it shares the same memory, tools, skills, and apps. Use the best agent for the job without rebuilding your setup every time.

- **No lock-in** — run Claude Code, Codex, or holaOS's own agent in the same workspace, over the same tools, files, and memory.
- **Shared everything** — one context, one set of tools, one workspace.
- **Consistent results** — the same skills and integrations, whatever's driving.

### 🧠 One memory, every agent

Context, preferences, and project history live in a single shared memory — stored **locally, as plain files you can read and edit.** Switch agents, close the app, come back next week: it already knows where you left off.

- **Never start from zero** — durable memory across sessions _and_ agents.
- **Local-first & yours** — on your machine, visible and editable, not locked in someone else's cloud.
- **Actually recallable** — structured and embedded, so the right context returns when it's needed.




### 🛠️ Your entire workstation, agent-operable

- **🌐 A real browser, driven by agents** — signed-in browsers your agents drive to browse, click, and extract — under your control.
- **🎨 Frontier generation built in** — the latest image, video, and audio models inside every agent. Storyboard a video, design a poster, voice a script — one prompt.
- **📄 Real deliverables** — reports, spreadsheets, and slides saved as real `.xlsx`, `.pptx`, and `.docx` files you can send, not text stuck in a chat.
- **⏰ Automation** — run on a schedule or a trigger. Digests, monitors, and reports finish and file themselves.

### 🔒 Your work stays on your side

 An agent that can reach your tools, your chats, and your whole machine only makes sense if you stay in control of it. That control is built into how HolaOS works, not bolted on as a setting.

 - **Local-first, not cloud-first** — workspace files, memory, embeddings, and session history all live on your own disk. There is no copy of your work on our servers.

 - **We can't see your data** — not your files, not your memory, not your conversations. It isn't a policy we promise; it's a place your data never goes.

 - **Every action is approved by you** — connecting a tool, reading a thread, editing a file. The agent asks first, and you decide what it can reach and what stays off limits.

 - **Visible and reversible** — open what the agent remembers, edit it, delete it. Memory is a folder you can read, not a black box.

 - **Your own keys, your own contracts** — route inference through your own model provider if that's what your policy requires.

### 🌐 HolaHub — the recipe platform for agents, inside HolaOS


 The fastest way to set up your workspace is to start from someone else's working setup. On HolaHub, creators publish agent recipes that already run — model, prompt, skills, MCP, integrations — and anyone installs one in a click and gets the same result. Share what you built, run what other people built.

 - **One click to share** — package any run in HolaOS and post it to the Hub, process and result together. No export, no rewrite, no second account.

 - **One click to reproduce** — every skill, MCP, image, or video on the Hub runs in your own workspace instantly. Discovery and installation are the same gesture.

 - **Recipes, not just outputs** — each post opens up into how it was made: the session behind a skill, the prompt behind an image or video. You see the ingredients of a result, not only the result.



### 🚀 Run it your way

|                     |                                                                                                                                                                          |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **🖥️ Desktop app**  | Download and go. Nothing to set up — frontier models built in, free to start.                                                                                           |
| **🔓 Open source**  | Self-host it. Modified Apache 2.0, bring your own keys, run it entirely on your machine.                                                                                |
| **🏢 Enterprise**   | SSO with per-role permissions for every agent, skill, and app. Connect internal systems without exposing them. Audit logs on every action. On-prem or your own cloud.   |

---

## Table of Contents

- [Quick Start](#quick-start)
- [Manual Install](#manual-install)
- [OSS Release Notes](#oss-release-notes)

## Quick Start

### One-Line Install

For a fresh-machine bootstrap on macOS, Linux, or WSL, use the repository installer:

```bash
curl -fsSL https://raw.githubusercontent.com/holaboss-ai/holaOS/refs/heads/main/scripts/install.sh | bash -s -- --launch
```

You can also follow the manual path if you want to control each setup step.

## Star the Repository





## Manual Install

You likely will not need this section because One-Line Install runs the same setup. Use Manual Install when you want to inspect or control each step. If you use the manual path, verify the usual prerequisites first:

```bash
git --version
node --version
npm --version
```

The repo pins its Node version in a root [`.nvmrc`](.nvmrc). If you already use [nvm](https://github.com/nvm-sh/nvm), running `nvm use` in the repo root will pick it up automatically — nvm is optional and not required to set up holaOS.

### One-Line Agent Setup

If you use Codex, Claude Code, Cursor, Windsurf, or another coding agent, you can hand it the setup instructions in one sentence:

```text
Run the holaOS install script from https://raw.githubusercontent.com/holaboss-ai/holaOS/refs/heads/main/scripts/install.sh. It should install git and Node.js 24.14.1/npm if they are missing, clone or update the repo into ~/holaboss-ai unless I specify another --dir, run desktop:install, create apps/desktop/.env from apps/desktop/.env.example if needed, run desktop:prepare-runtime:local and desktop:typecheck, and only run desktop:dev if I ask for --launch. If Electron cannot open, stop after verification and tell me the next manual step.
```

That handoff keeps the installation flow self-contained while leaving the detailed bootstrap steps in the repo-local [INSTALL.md](INSTALL.md) runbook.

This is the baseline installation flow for local desktop development.

1. Install the desktop dependencies from the repository root:

```bash
npm run desktop:install
```

2. Create your local environment file:

```bash
cp apps/desktop/.env.example apps/desktop/.env
```

If you are following the repo exactly, keep the file close to the template and only change the values that your provider or machine needs.
The canonical path is `apps/desktop/.env`. Existing legacy `desktop/.env` files are still accepted for now, but new setups should use `apps/desktop/.env`.

3. Prepare the local runtime bundle:

```bash
npm run desktop:prepare-runtime:local
```

4. If you want a quick validation pass before launching Electron, run:

```bash
npm run desktop:typecheck
```

5. Start the desktop app in development mode:

```bash
npm run desktop:dev
```

The `predev` hook will validate the environment, rebuild native modules, and make sure a staged runtime bundle exists.

If you want to stage the runtime before opening the desktop app, there are two common paths:

Build from local runtime:

```bash
npm run desktop:prepare-runtime:local
```

Fetch the latest published runtime:

```bash
npm run desktop:prepare-runtime
```

Use the local path when you are actively changing runtime code. Use the published bundle when you want to verify the desktop against a known release artifact.

Use `One-Line Install` when you want the fastest path to a working local desktop environment. Use `Manual Install` when you need to inspect or control each setup step yourself.


## OSS Release Notes

- License: modified Apache 2.0 with additional commercial-distribution and branding conditions. See [LICENSE](LICENSE).
- Security issues: report privately to `admin@holaboss.ai`. See [SECURITY.md](SECURITY.md).

## Star History

<a href="https://www.star-history.com/?repos=holaOS%2FholaOS%2Cholaboss-ai%2FholaOS&type=date&legend=top-left">
 
   
   
   
 
</a>

---

## File: apps/desktop/README.md

# Holaboss Local - Neon AI Workspace Prototype

Desktop prototype inspired by a futuristic dark neon-green AI operating workspace with three docked panes:

1. File Explorer (left)
2. In-app Browser panel (center)
3. AI Chat assistant (right)

Built with Electron + React + TypeScript + Vite + Tailwind CSS.

## Features

- Electron main/preload/renderer separation with secure preload bridge
- Full-window dark neon-green visual system
- Global top tab bar with workspace controls
- Three-pane layout with draggable split handles
- Pane widths persist in local storage
- Real local file explorer (reads your filesystem via secure IPC)
- Real embedded Chromium browser (`<webview>`) with URL/home/back/forward/refresh
- AI chat panel with suggestion pills, composer, user/assistant bubbles, and local rule-based responses

## Tech Stack

- Electron
- React 19
- TypeScript
- Vite
- Tailwind CSS
- Lucide React icons

## Run

```bash
npm install
cp .env.example .env
npm run dev
```

This launches:
- Vite dev server for the renderer (`http://localhost:5173`)
- TS build watcher for Electron main/preload (`out/dist-electron/*.cjs`)
- Electron desktop window with live restarts on main/preload changes

The repo ships no remote endpoint URLs — backend/auth access is configured entirely through environment variables (see `.env.example`).

Before running `npm run dev`, create `apps/desktop/.env` from `apps/desktop/.env.example` and fill in the required remote values:

```bash
cp .env.example .env
```

`npm run dev` stages a runtime bundle before Electron starts. In this repo it prefers a locally built runtime when the runtime packager scripts are available.
Each staged runtime bundle is self-contained and carries the runtime API, bundled Node/npm, and bundled Python.

## Build

```bash
npm run build
```

This creates:
- Renderer production bundle in `out/dist/`
- Electron main/preload bundles in `out/dist-electron/`

## Runtime Bundle

Packaged desktop builds expect a staged runtime bundle at `out/runtime-/`:

```bash
npm run prepare:runtime
```

That stages the bundle for the current host platform from an explicit runtime source. If you need to target a specific platform explicitly:

```bash
npm run prepare:runtime:macos
npm run prepare:runtime:linux
npm run prepare:runtime:windows
```

For local development against unreleased `holaOS` runtime changes:

```bash
# optional when your OSS repo is not ../holaOS
export HOLABOSS_OSS_ROOT=/absolute/path/to/holaOS

# builds the runtime bundle for the current host platform and stages it into out/runtime-
npm run prepare:runtime:local
```

After `npm run prepare:runtime:local`, a normal `npm run dev` uses that staged local runtime bundle. Set `HOLABOSS_RUNTIME_PLATFORM=macos|linux|windows` if you need to override platform detection.

Or package directly with local runtime in one step:

```bash
npm run dist:mac
npm run dist:mac:dmg
npm run dist:win
```

The staging script accepts one of:
- `HOLABOSS_RUNTIME_DIR=/absolute/path/to/runtime-`
- `HOLABOSS_RUNTIME_TARBALL=/absolute/path/to/holaboss-runtime--<sha>.tar.gz`
- `HOLABOSS_RUNTIME_BUNDLE_URL=https://.../holaboss-runtime--<sha>.tar.gz`
- `HOLABOSS_RUNTIME_PLATFORM=macos|linux|windows` to override the auto-detected target platform when needed

Runtime packagers can also override the bundled Python source when needed:
- `HOLABOSS_RUNTIME_PYTHON_DIR=/absolute/path/to/extracted/python`
- `HOLABOSS_RUNTIME_PYTHON_TARBALL=/absolute/path/to/cpython-...tar.gz`
- `HOLABOSS_RUNTIME_PYTHON_URL=https://.../cpython-...tar.gz`
- `HOLABOSS_RUNTIME_PYTHON_VERSION`, `HOLABOSS_RUNTIME_PYTHON_RELEASE`, `HOLABOSS_RUNTIME_PYTHON_VARIANT`, and `HOLABOSS_RUNTIME_PYTHON_TARGET_TRIPLE`

If none are set, it falls back to the host temp directory, for example `${TMPDIR:-/tmp}/holaboss-runtime--full`, or you can run `npm run prepare:runtime:local` first.

To build a mac app bundle with the runtime embedded in Electron resources:

```bash
npm run dist:mac
```

Use `dist:mac` for the default local-runtime packaging flow. Use `prepare:runtime` with explicit runtime source env vars when you need to package against a prebuilt runtime bundle instead.

This produces an unsigned local mac app bundle with `runtime-macos` embedded in `Contents/Resources/`.

For Windows packaging:

```bash
npm run dist:win
```

Use `dist:win` on a Windows host to build and stage a native local runtime bundle first, then produce a Windows NSIS installer.

The Windows packaging command also writes `out/holaboss-config.json` from your configured desktop environment before building the installer.

This produces a Windows NSIS installer `.exe` in `out/release/`.

Output:
- [holaOS.app](/Users/you/Desktop/holaOS/desktop/out/release/mac-arm64/holaOS.app)

Remote configuration for packaged runs (set via environment variables):
- `HOLABOSS_AUTH_BASE_URL` for Better Auth session endpoint
- `HOLABOSS_AUTH_SIGN_IN_URL` for the hosted sign-in page
- `HOLABOSS_BACKEND_BASE_URL` for the Holaboss backend base URL used by the desktop
- `HOLABOSS_PACKAGED_APP_BIN` for an explicit packaged binary path

Start by copying the template:

```bash
cp .env.example .env
```

To build a mac installer image:

```bash
npm run dist:mac:dmg
```

This produces a local-use `.dmg` installer in `out/release/`.

Notes:
- `dist:mac` builds an unpacked `.app`
- `dist:mac:dmg` builds a `.dmg` installer
- both local mac packaging commands force ad-hoc signing for local smoke testing via `--config.mac.identity=-`
- production signing and notarization are handled in GitHub Actions once the Apple secrets are configured

### Signed Product Release

Desktop validation and desktop release packaging now share the single `.github/workflows/ci.yml` workflow, whose display name is `CI`.

On pull requests and pushes to `main`, `CI` runs the normal validation jobs only. On manual dispatch, that same workflow:
- calls `.github/workflows/publish-linux-runtime.yml` to build the backend-consumed Linux runtime bundle and stage it for the final release publish
- checks out the requested `ref`
- creates the requested GitHub release in `holaboss-ai/holaOS-releases`
- attaches the Linux runtime bundle, manifest, and checksum to that same `holaboss-ai/holaOS-releases` tag
- builds the signed and notarized Apple Silicon macOS app, then uploads the DMG, ZIP, blockmaps, and `latest-mac.yml`
- calls `.github/workflows/publish-macos-intel-desktop.yml` to stage the notarized Intel macOS (`x64`) DMG, ZIP, blockmap, and mac updater manifest for the same release
- merges the Apple Silicon and Intel macOS updater manifests before publishing the final shared `latest-mac.yml` / `beta-mac.yml` assets
- builds the signed Windows NSIS installer, then uploads the installer, blockmap, and channel manifest

The `.github/workflows/publish-macos-intel-desktop.yml` workflow remains separately dispatchable for Intel-only reruns. It now rebuilds the notarized Intel macOS DMG, ZIP, blockmap, and updater metadata, then merges the Intel updater entries into the existing shared `latest-mac.yml` / `beta-mac.yml` assets on `holaboss-ai/holaOS-releases`. That standalone rerun path assumes the Apple Silicon macOS release assets for the tag already exist in the shared release repo.

Release channel policy:
- the Linux runtime bundle is published separately for remote sandbox runtime consumers
- desktop releases still do not attach standalone runtime tarballs to `holaboss-ai/holaOS-releases`
- desktop-shippable releases publish to `holaboss-ai/holaOS-releases`
- the in-app desktop updater is still intended to track desktop releases, not arbitrary runtime assets

Desktop release versioning:
- use stable semver in `YYYY.MDD.R` format
- `YYYY` = year, `MDD` = month without a leading zero plus a two-digit day, `R` = release number for that date
- examples: `2026.410.1`, `2026.410.2`, `2026.1113.1`
- do not zero-pad the month in the middle segment; `2026.0410.1` is not valid semver
- desktop GitHub release tags must be `holaOS-YYYY.MDD.R`
- the desktop packager derives the app update version from the trailing `X.Y.Z` suffix in `release_tag`, so tags should end with the same `YYYY.MDD.R` value
- to print a version for today, run `npm --prefix desktop run release:version`
- to print the full desktop release tag for today, run `npm --prefix desktop run release:tag`
- to print the second release for a specific day, run `npm --prefix desktop run release:version -- 2 --date 2026-04-10`
- to print the second release tag for a specific day, run `npm --prefix desktop run release:tag -- 2 --date 2026-04-10`

The manual `CI` release path requires these repository secrets and fails fast when any of them are missing:

- `MAC_CERTIFICATE`: base64-encoded `Developer ID Application` `.p12`
- `MAC_CERTIFICATE_PASSWORD`: password for the `.p12`
- `APPLE_ID`: Apple Developer account email
- `APPLE_APP_SPECIFIC_PASSWORD`: app-specific password from Apple ID settings
- `APPLE_TEAM_ID`: Apple Developer Team ID
- `AZURE_TENANT_ID`: Microsoft Entra tenant ID for the Windows signing service principal
- `AZURE_CLIENT_ID`: client ID for the Windows signing service principal
- `AZURE_CLIENT_SECRET`: client secret value for the Windows signing service principal; use the secret `Value`, not the secret ID
- `HOLABOSS_RELEASES_REPO_TOKEN`: token with read access to the private source repo and write access to `holaboss-ai/holaOS-releases`

The manual `CI` release path also requires these repository variables for Azure Trusted Signing:

- `WINDOWS_SIGNING_ENDPOINT`: Azure Trusted Signing endpoint for the account region
- `WINDOWS_SIGNING_ACCOUNT_NAME`: Trusted Signing account name
- `WINDOWS_SIGNING_CERTIFICATE_PROFILE_NAME`: certificate profile name
- `WINDOWS_SIGNING_PUBLISHER_NAME`: publisher name exactly as it appears in the certificate profile

The Windows signing service principal must have the `Artifact Signing Certificate Profile Signer` role on the Trusted Signing account or certificate profile.
The Windows CI release job validates this before the build by requesting a Trusted Signing token and signing a small probe executable, so role-assignment or propagation failures fail before the expensive installer build.

When manually triggering `CI`, provide:

- `ref`: the branch, tag, or commit you want to ship
- `release_tag`: the GitHub release tag to create or update, in `holaOS-YYYY.MDD.R` format
- `release_title`: optional display title for the GitHub release
- `prerelease`: whether the GitHub release should be marked as a prerelease when first created

The workflow stages the runtime bundle needed for each desktop build inside the runner, maps the Apple signing secrets and Azure Trusted Signing settings to `electron-builder`, and uploads the desktop release assets to the chosen GitHub release. The desktop build config uses `hardenedRuntime` plus an explicit mac entitlements plist at `resources/entitlements.mac.plist`.

Docs publishing remains separate in `.github/workflows/deploy-docs.yml` and automatically runs only for docs changes.

After a signed build, validate the produced app locally with:

```bash
codesign --verify --deep --strict --verbose=2 /path/to/holaOS.app
spctl -a -vv -t exec /path/to/holaOS.app
xcrun stapler validate /path/to/holaOS.app
```

## Project Structure

```text
electron/
  main.ts
  preload.ts
src/
  components/
    layout/
      AppShell.tsx
      TopTabsBar.tsx
      SplitPaneLayout.tsx
    panes/
      FileExplorerPane.tsx
      BrowserPane.tsx
      ChatPane.tsx
    ui/
      PaneCard.tsx
      IconButton.tsx
  data/
    mockFiles.ts
    mockBrowser.ts
  utils/
    mockAssistant.ts
  types/
    electron.d.ts
    webview.d.ts
  App.tsx
  main.tsx
  index.css
```

## Browser Notes

The center pane uses a real Electron `webview`:
- Source is set in `src/components/panes/BrowserPane.tsx`
- Navigation controls call real webview methods (`goBack`, `goForward`, `reload`, `loadURL`)
- Main process enables and guards webview attachment in `electron/main.ts`

If you later want a multi-tab browser architecture, keep the current `BrowserPane` control surface and swap to a tab manager that creates one webview per tab.

## File Explorer Notes

The left pane reads real directories from your machine:
- IPC handler lives in `electron/main.ts` (`fs:listDirectory`)
- Renderer call lives in preload bridge (`window.electronAPI.fs.listDirectory`)
- UI and navigation are in `src/components/panes/FileExplorerPane.tsx`

The explorer currently supports:
- folder open (double-click or “Open Selected Folder”)
- back/forward/up/home navigation
- search/filter in current directory
- grouped rendering by modified date (Today / This Week / This Year / Earlier)

### AI assistant

Current chat replies are local rule-based mocks (no backend/LLM):
- Rules and canned responses live in `src/utils/mockAssistant.ts`
- `ChatPane.tsx` handles message rendering and send flow

Replace point for real AI backend:
- Hook send flow in `src/components/panes/ChatPane.tsx` where `generateMockReply` is called
- Replace timeout mock with API call and stream/append tokens as needed

## Security

Renderer runs with:
- `contextIsolation: true`
- `nodeIntegration: false`
- `webviewTag: true` (enabled intentionally for embedded browser pane)

Preload bridge exposes runtime info and a constrained filesystem API via `window.electronAPI`.

## Stretch Goals Ready

Codebase is structured to support later additions such as:
- draggable top tabs
- command palette
- collapsible icon rail
- tokenized theme switching

---

## File: docs/plans/2026-05-18-discord-module-connect-flow-fix/README.md

# Discord module connect-flow fix — 2026-05-18

When a user asked the desktop agent to build a brand-new Discord
module, three independent bugs surfaced in sequence:

1. **No Connect button rendered** in the chat after the agent reported
   the app was ready.
2. **First `/api/composio/connect` call always failed** with a 502;
   retrying always worked.
3. **After the user finally authorized**, the Discord app already
   running in the sandbox kept behaving as if no integration was
   bound, until a manual restart.

The three bugs are independent — fixing only one of them leaves the
flow broken at the next step — so the work is split into three stages
that need to land together for the end-to-end Discord build to work.
Each stage is locally verifiable on its own (see each stage doc's
"Verification" section).

| Stage | Bug | Layer | Deploys via |
|---|---|---|---|
| [1](stage-1-broaden-pending-integrations-emit.md) | Connect button | holaOS runtime | rebuild + `npm run desktop:prepare-runtime:local` |
| [2](stage-2-restart-app-after-bind.md) | Stale grant after bind | holaOS desktop (electron main + preload + renderer) | `npm run desktop:dev` |
| [3](stage-3-hono-remove-toolkit-mapping-and-upsert.md) | First-time 502 + non-extensible toolkit map | Hono (frontend/apps/server) | `bun run deploy:staging` |
| [4](stage-4-account-display.md) | Account labels show as hex hash for any toolkit not in `PROVIDER_WHOAMI` | UI fallback (Tier 1) + per-yaml whoami passthrough across runtime/desktop/Hono (Tier 2) | desktop rebuild + `bun run deploy:staging` |
| [5](stage-5-toolkit-slug-fix.md) | `not_connected` / 401 on send-message after a clean OAuth (identity probe works) | `provider.ts` + yaml use the **actual Composio toolkit slug** (`discordbot`, not `discord`); skill rewritten to enforce one-value-everywhere; `composioToolkit` deprecated | edit-in-workspace + `bun run desktop:prepare-runtime:local` (skill ships in runtime bundle) |
| [6](stage-6-app-surface-bind-button.md) | App Surface "Connect" button only rendered for ~12 hardcoded toolkits; new agent-built apps had no in-app bind UI | `/api/v1/apps` returns yaml-declared `integrations[]` per app; `AppSurfacePane` resolves provider from yaml (not from a hardcoded map); `handleConnectAccount` runs full OAuth+bind+restart inline | desktop rebuild |
| [7](stage-7-deduplicate-bind-state-and-drop-app-catalog.md) | Two parallel bind-state machines (chat card + App Surface) drifted; `APP_CATALOG` hardcoded display labels for 7 apps — agent-built apps got `labelFromAppId` fallbacks | Shared `useIntegrationBinding` hook; both consumers refactored; yaml `name:` surfaced on `/api/v1/apps`; `APP_CATALOG` / `summary` / `accentClassName` deleted | desktop rebuild + `npm run desktop:prepare-runtime:local` |
| [8](stage-8-cancel-stuck-connect.md) | Rejecting / closing the OAuth window left the Connect button spinning for the full 5-min poll timeout | Hook exposes `cancel()` + per-call AbortController; consumers swap Connect → Cancel button while `busy === "connecting"`; unmount aborts in-flight controller | desktop rebuild |

The legacy module-app source is **not** touched — the desktop agent now
generates app modules dynamically, the legacy marketplace path is no
longer the source of truth for these bugs.

## End-to-end verification (after all three stages ship)

```text
1. Open desktop → start a new workspace → tell the agent "build a
   Discord bot module for me".
2. Once the agent reports the app is ready, a "Connect Discord" card
   MUST render inline in the assistant turn (Stage 1).
3. Click Connect Discord → OAuth window opens → user grants access in
   their browser (Stage 3, no 502 on the first attempt).
4. Card transitions to "Bound to discordbot-module …" within seconds
   of the user clicking through OAuth (Stage 2 has restarted the app
   in the background so HOLABOSS_APP_GRANT is freshly injected).
5. Ask the agent "list my Discord guilds" — it must succeed on the
   first call without any restart hint or manual intervention.
```

## Why the bugs presented together

All three bugs sit on the same chain — the agent's "I just built a new
toolkit-backed app" path. Existing apps (gmail, github, etc.) had at
least one of:

- a marketplace catalog entry hardcoding `provider_id`, working around
  Stage 1's narrow emit set;
- an entry in `PROVIDER_TO_TOOLKIT`, working around Stage 3's missing
  mapping;
- a user who had connected the toolkit before any app was running,
  side-stepping Stage 2's boot-time env capture.

A truly fresh Discord install bypassed all three workarounds at once,
which is why this is the first toolkit to expose the whole chain.

---

## File: docs/plans/2026-05-18-discord-module-connect-flow-fix/stage-1-broaden-pending-integrations-emit.md

# Stage 1 — Broaden `pending_integrations` emit (Bug 1)

> Symptom: desktop agent creates a new Discord module, but no Connect button
> appears in the conversation. User has to open the Integrations pane manually
> to authorize the toolkit.

## Root cause

`pending_integrations` is the payload the runtime emits in a tool result so
the chat UI can render an inline Connect card next to the assistant message.

Two layers were both involved:

1. `pendingIntegrationsFromAppManifests` (runtime-agent-tools.ts) reads each
   app's `app.runtime.yaml`, parses `integrations[]` (and the legacy
   `integration` singular via `integration-types.ts:88` fallback), and emits
   one entry per `required: true` integration. **This part already works
   correctly for Discord** — `integration: { destination: "discordbot" }`
   resolves to `provider: "discordbot"`.
2. `claimed-input-executor.ts:3266` `PENDING_INTEGRATION_EMITTING_TOOLS` only
   scanned the output of four tools:
   - `workspace_apps_install`
   - `workspace_apps_ensure_running`
   - `workspace_apps_restart`
   - `workspace_apps_restart_and_wait_ready`

If the desktop agent ended its build flow on any other tool —
`workspace_apps_scaffold`, `_register`, `_build`, `_wait_until_ready`, or
`_get_status` — the chat UI never saw `pending_integrations` and the Connect
card was never rendered. The SKILL.md instructs the agent to end on
`ensure_running`, but in practice the LLM does not always follow that path.

## Fix

Two changes, both in `holaOS/runtime/api-server/src/`:

1. **`claimed-input-executor.ts:3266`** — extend the emitting set with five
   completion-type tools:
   ```ts
   "workspace_apps_scaffold",
   "workspace_apps_register",
   "workspace_apps_build",
   "workspace_apps_wait_until_ready",
   "workspace_apps_get_status",
   ```

2. **`runtime-agent-tools.ts`** — introduce a private helper
   `pendingIntegrationsForApps(workspaceId, appIds)` and call it at the tail
   of every completion-type tool method so the JSON result carries
   `pending_integrations: [...]` whenever a registered app has at least one
   `required: true` integration:
   - `scaffoldWorkspaceApp`
   - `registerWorkspaceApp`
   - `buildWorkspaceApp` (both `skipped` and normal paths)
   - `getWorkspaceAppStatus` (single-app + all-apps variants)
   - `restartWorkspaceApp`
   - `waitUntilWorkspaceAppReady` (both ready and timed-out paths)

The card UI already de-dupes by `(provider_id, app_id)`, so emitting the same
entry from multiple successive tools is harmless — only the most recent
assistant turn renders the card.

## Files changed

- `runtime/api-server/src/claimed-input-executor.ts`
- `runtime/api-server/src/runtime-agent-tools.ts`

## Verification

1. Rebuild runtime + redeploy bundled `.pyc` into desktop:
   ```bash
   cd holaOS
   npm run desktop:prepare-runtime:local
   ```
2. Restart the desktop app.
3. Ask the agent to create a Discord module from scratch.
4. After the agent reports the app is ready, a Connect Discord card MUST
   appear inline in the chat. This should hold regardless of which tool the
   agent invoked last.

## Out of scope (handled in later stages)

- The Hono `/api/composio/connect` first-time failure (Stage 3 — Bug 2).
- Running Discord app not picking up the new grant after authorization
  (Stage 2 — Bug 3).

---

## File: docs/plans/2026-05-18-discord-module-connect-flow-fix/stage-2-restart-app-after-bind.md

# Stage 2 — Restart the workspace app after a binding change (Bug 3)

> Symptom: user clicks Connect Discord, OAuth succeeds, the Composio
> connection is finalized and the workspace-app binding is upserted — but
> the running Discord app still answers as if no integration is configured.
> The agent has to be told to restart the app, or the user has to do it
> manually.

## Root cause

The runtime bridge transport
(`experiments/app-builder-sdk/src/bridge-transports/runtime-broker.ts` and
the equivalent in `@holaboss/bridge`) reads `HOLABOSS_APP_GRANT` from
`process.env` once at module import. The grant carries `(workspace, app)`
identity, which the integration-broker uses on every provider call to look
up the bound connection.

When a new binding is created **after** the app has started:

1. The runtime writes the new binding to `runtime.db` correctly.
2. The integration-broker can resolve the binding on subsequent calls.
3. **But** the bridge in the running app process still carries either a
   stale grant or no grant — env is captured at boot, not refreshed.

The desktop already calls `composioFinalize` (writes the connection) and
`upsertIntegrationBinding` (writes the workspace-app binding) in
`IntegrationConnectCard.handleConnect` / `handleBind`. What was missing
was a process-level restart of the app so `integration-runtime.ts` can
re-inject `HOLABOSS_APP_GRANT` at the next boot.

The runtime already exposes the right endpoint
(`POST /api/v1/capabilities/runtime-tools/workspace-apps/:appId/restart` —
backed by `RuntimeAgentToolsService.restartWorkspaceApp`), but no desktop
IPC surfaced it to the renderer.

## Fix

End-to-end wiring of a new `restartApp` IPC, then call it from the bind
flow.

### 1. Runtime → main process

**`electron/main.ts`** — new `restartWorkspaceApp(workspaceId, appId)` thin
wrapper around `requestWorkspaceRuntimeJson` posting to the
`workspace-apps/:appId/restart` capability endpoint.

### 2. IPC registration

**`electron/main.ts`** — `handleTrustedIpc("workspace:restartApp", ...)`
next to the other binding handlers.

### 3. Preload bridge

**`electron/preload.ts`** — expose
`window.electronAPI.workspace.restartApp(workspaceId, appId)`.

### 4. Renderer type definition

**`src/types/electron.d.ts`** — add the method signature to the
`workspace` IPC surface.

### 5. Renderer consumer

**`src/components/panes/ChatPane/AssistantTurn/IntegrationConnectCard.tsx`**
— extract a `rebootAppAfterBindChange` helper; call it in both
`handleConnect` (after a fresh OAuth-driven bind) and `handleBind` (after
the user switches/binds an existing connection).

The restart is fire-and-forget: a thrown error is swallowed because the
bind itself succeeded, and a manual restart later will recover the same
end state. The next agent call against the app will surface the actual
error if anything broker-side is still wrong.

## Files changed

- `desktop/electron/main.ts` (new helper + IPC handler)
- `desktop/electron/preload.ts` (bridge entry)
- `desktop/src/types/electron.d.ts` (type)
- `desktop/src/components/panes/ChatPane/AssistantTurn/IntegrationConnectCard.tsx`
  (consumer)

## Verification

1. Rebuild desktop:
   ```bash
   cd holaOS
   npm run desktop:install
   npm run desktop:dev
   ```
2. Create a fresh Discord module (Stage 1 must already be deployed —
   otherwise the Connect card may not appear at all).
3. Click Connect Discord, complete the OAuth flow in the popped browser.
4. After the card transitions to the "Bound to discordbot-module" state,
   immediately ask the agent to call a Discord tool (e.g. list guilds).
5. The tool MUST work on the first call — no manual restart, no
   "integration not bound" error.
6. Repeat with switching accounts (drop-down "Switch to account 2") to
   confirm `handleBind` also triggers the restart.

## Out of scope (handled separately)

- Bug 1 (Stage 1): Connect button not appearing — Stage 2 only matters if
  the card renders in the first place.
- Bug 2 (Stage 3): Hono `/api/composio/connect` first-time failures — the
  user has to be able to complete OAuth for Stage 2 to ever exercise.
- Future optimization: drop the restart in favor of an in-process env
  refresh hook on the bridge transport, so Discord doesn't lose a few
  seconds of uptime per bind. Not worth the complexity until restart
  proves user-visible.