Skip to content
Merged

0.8.2 #104

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jobs:
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
VERSION: ${{ steps.pkg.outputs.version }}
run: |
set -euo pipefail
Expand Down Expand Up @@ -202,6 +203,7 @@ jobs:
- name: Attach GitHub release artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
VERSION: ${{ needs.preflight.outputs.version }}
run: |
set -euo pipefail
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.8.2] - 2026-07-07

### Added

- 🌿 **Fork chats from any response.** Start a fresh copy of a conversation from the current response or with `/fork`, so you can try a different direction without changing the original chat.
- ✨ **Easier skill access.** Type `/` to find skills alongside chat commands, and admins can control skill behavior from a new Skills page.

### Changed

- 🧠 **Smarter skill upkeep.** Computer can help keep managed skills up to date after real chats, while admins can turn skill features on or off.
- ⚙️ **Tidier settings.** About, sharing, update, license, and PWA reset controls now live in General, with Skills under Admin.

### Fixed

- 💬 **Clearer chat controls.** Message actions now show helpful tooltips, and commands that need an existing chat stay hidden until they can be used.
- 📦 **More dependable release downloads.** Release runs now attach download files to the right repository more reliably.

## [0.8.1] - 2026-07-06

### Added
Expand Down
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

<sub>See more at [cptr.sh](https://cptr.sh/)</sub>

Open WebUI Computer (`cptr`) runs on your machine and serves your whole computer (files, terminal, editor, git) to any browser. It literally is your computer.
Open WebUI Computer (`cptr`) runs on your machine and serves your whole computer to any browser: files, terminal, editor, git, running sessions, AI agents, and tools. It literally is your computer.

Use it from your phone, tablet, laptop, another computer, or the machine it's running on. Designed to feel native on every screen. Connect your own AI via API key, or plug in a coding agent you already subscribe to and skip the key entirely. Terminal multiplexer, parallel AI agents, full workstation, one tool, your computer, any device.
Use it from your phone, tablet, laptop, another computer, or the machine it's running on. Designed to feel native on every screen. Connect your own AI via API key, plug in a coding agent you already subscribe to, or work directly in the terminal. One tool, full workstation, any device.

## Install

Expand Down Expand Up @@ -55,23 +55,27 @@ Most tunnels forward to `localhost`, so the default `cptr run` works. If your tu

Or skip networking entirely and connect a [messaging bot](#messaging-bots) instead.

## What you get
## The Whole Machine

Open WebUI Computer is the real workstation surface: files, shell, git state, workspaces, chats, tools, and sessions stay together wherever you open it.

| | |
|---|---|
| 📁 **File browser** | Navigate, create, rename, upload, drag and drop. Icons by type, sizes at a glance. |
| ⌨️ **Terminal** | Full shell in the browser. Run your tools, your scripts, or your favourite coding agent. |
| 🔀 **Git** | Stage, commit, diff, branch, push. Visual changes view. No command line required. |
| 📁 **Real files** | Navigate, create, rename, upload, drag and drop. Icons by type, sizes at a glance. |
| ✏️ **Editor** | Syntax-highlighted editing with tabs. Open multiple files side by side. |
| 🔀 **Git** | Stage, commit, diff, branch, push. Visual changes view. No command line required. |
| ⌨️ **Terminal** | Full shell in the browser. Run your tools, your scripts, or your favourite coding agent. |
| 🔄 **Sessions persist** | Terminal keeps running when you close the tab. Come back on any device. |
| 🗂️ **Tabs** | Open terminals, files, chats, and tools in separate tabs. Rearrange or split your layout. |
| 📂 **Workspaces** | Multiple projects, one instance. Switch without losing your place. |
| 🔍 **Search** | Find files by name, search across file contents and chat history. ⌘K to find anything. |
| 📱 **Mobile-first** | Not a desktop UI made smaller. Built for the screen in your pocket. |
| 🔄 **Sessions persist** | Terminal keeps running when you close the tab. Come back on any device. |

## AI agent

Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint), or connect a coding agent you already subscribe to.
AI that works where your work actually lives.

Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endpoint), or connect a coding agent you already subscribe to. It can read the workspace, edit files, run commands, browse the web, use tools, automate recurring work, and spin up parallel sub-agents on the same machine.

| | |
|---|---|
Expand All @@ -95,7 +99,7 @@ Bring your own API key (OpenAI, Anthropic, Ollama, or any OpenAI-compatible endp

## Coding agents

Connect a coding agent as a native backend and use the subscription you already pay for. No separate API key needed.
Use the subscriptions you already pay for as native backends on your own machine. No separate API key needed.

**Codex** · **Claude Code** · **Cursor** · **Grok** · **OpenCode** · **Cline**

Expand All @@ -105,15 +109,15 @@ Prefer to run agents yourself? Any terminal agent (Gemini CLI, Kilo Code, Pi, an

## Messaging bots

Connect the AI to your chat apps. Full tool access, streaming responses, conversations synced back to the web UI.
Message your computer from wherever you are. Connect the AI to your chat apps with full tool access, streaming responses, and conversations synced back to the web UI.

**Telegram** · **Discord** · **Slack** · **WhatsApp** · **Signal**

Message your computer from wherever you are. Ask it to check a build, push a fix, or explain a file. Switch workspaces with `/workspace`, start fresh with `/new`.
Ask it to check a build, push a fix, or explain a file. Switch workspaces with `/workspace`, start fresh with `/new`.

## Gateway API

Open WebUI Computer exposes an OpenAI-compatible API (`/v1/chat/completions`). Any client that speaks OpenAI, including [Open WebUI](https://github.com/open-webui/open-webui), can use each Open WebUI Computer workspace as a model with full agent capabilities: file access, terminal, web search, tools.
Turn each workspace into an OpenAI-compatible agent model with real machine access. Open WebUI Computer exposes `/v1/chat/completions`, so any client that speaks OpenAI, including [Open WebUI](https://github.com/open-webui/open-webui), can use a workspace with full agent capabilities: file access, terminal, web search, tools.

## More

Expand All @@ -127,7 +131,7 @@ Open WebUI Computer exposes an OpenAI-compatible API (`/v1/chat/completions`). A
| 📋 **Audit logging** | Structured audit trail of all API mutations with automatic redaction of sensitive data. |
| 🪵 **Diagnostic logging** | Configurable structured logs (text or JSON) with optional upstream request capture. |
| ⌨️ **Keyboard shortcuts** | Customisable keybindings with a settings panel. |
| 🌍 **10 languages** | EN, DE, ES, FR, JA, KO, PT-BR, RU, ZH-CN, ZH-TW. |
| 🌍 **10 languages** | English, Deutsch, Español, Français, Português (Brasil), Русский, 日本語, 한국어, 简体中文, 繁體中文. |
| 🔐 **Auth** | Username/password with JWT sessions. Signup toggle for admins. |

## Design principles
Expand Down
6 changes: 6 additions & 0 deletions cptr/frontend/src/lib/apis/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ export const getChat = (chatId: string, modelId?: string) => {
export const deleteChat = (chatId: string) =>
fetchJSON<{ ok: boolean }>(`/api/chats/${chatId}`, { method: 'DELETE' });

export const forkChat = (chatId: string, messageId?: string | null) =>
fetchJSON<{ ok: boolean; chat_id: string }>(
`/api/chats/${chatId}/fork`,
jsonBody({ message_id: messageId ?? null })
);

// ── Mutations ───────────────────────────────────────────────

export const sendMessage = (
Expand Down
8 changes: 8 additions & 0 deletions cptr/frontend/src/lib/apis/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ export interface SkillInfo {
license?: string;
compatibility?: string;
managed?: boolean;
created_by?: string | null;
created_from?: string | null;
view_count?: number;
use_count?: number;
update_count?: number;
last_viewed_at?: string | null;
last_used_at?: string | null;
last_updated_at?: string | null;
}

export const getSkills = (workspace: string) =>
Expand Down
122 changes: 122 additions & 0 deletions cptr/frontend/src/lib/components/Admin/Skills.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<script lang="ts">
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
import { getAdminConfig, updateConfig } from '$lib/apis/admin';
import ToggleSwitch from '$lib/components/common/ToggleSwitch.svelte';
import Spinner from '$lib/components/common/Spinner.svelte';

let loading = $state(true);
let saving = $state(false);
let enabled = $state(true);
let toolEnabled = $state(true);
let backgroundReview = $state(true);
let reviewInterval = $state(10);

onMount(async () => {
try {
const config = await getAdminConfig();
enabled = config['skills.enabled'] !== false && config['skills.enabled'] !== 'false';
toolEnabled =
config['skills.tool_enabled'] !== false && config['skills.tool_enabled'] !== 'false';
backgroundReview =
config['skills.background_review_enabled'] !== false &&
config['skills.background_review_enabled'] !== 'false';
reviewInterval = Number(config['skills.review_interval_turns']) || 10;
} catch {
toast.error('Failed to load config');
}
loading = false;
});

async function save() {
saving = true;
try {
await updateConfig({
'skills.enabled': enabled,
'skills.tool_enabled': toolEnabled,
'skills.background_review_enabled': backgroundReview,
'skills.review_interval_turns': Math.max(1, Number(reviewInterval) || 10)
});
toast.success('Saved');
} catch {
toast.error('Failed to save');
} finally {
saving = false;
}
}
</script>

<div class="flex flex-col h-full">
{#if loading}
<div class="flex justify-center py-8"><Spinner size={16} /></div>
{:else}
<div class="flex-1 min-h-0 overflow-y-auto scrollbar-hover pr-1.5 -mr-1.5">
<h2 class="text-sm font-medium text-gray-900 dark:text-white mb-4">Skills</h2>

<h3 class="text-xs text-gray-400 dark:text-gray-600 mb-2">Behavior</h3>
<div class="flex flex-col gap-2.5">
<label class="flex items-center justify-between cursor-pointer">
<span class="text-xs text-gray-600 dark:text-gray-400">Enable skills</span>
<ToggleSwitch
value={enabled}
onchange={(v) => {
enabled = v;
}}
/>
</label>

{#if enabled}
<label class="flex items-center justify-between cursor-pointer">
<span class="text-xs text-gray-600 dark:text-gray-400"
>Assistant can manage skills</span
>
<ToggleSwitch
value={toolEnabled}
onchange={(v) => {
toolEnabled = v;
}}
/>
</label>

<label class="flex items-center justify-between cursor-pointer">
<span class="text-xs text-gray-600 dark:text-gray-400">Background review</span>
<ToggleSwitch
value={backgroundReview}
onchange={(v) => {
backgroundReview = v;
}}
/>
</label>
{/if}
</div>

{#if enabled}
<h3 class="text-xs text-gray-400 dark:text-gray-600 mb-2 mt-5">Limits</h3>
<div class="flex flex-col gap-2.5">
<div>
<label class="text-xs text-gray-600 dark:text-gray-400" for="skills-review-interval">
Review every
</label>
<input
id="skills-review-interval"
type="number"
bind:value={reviewInterval}
min="1"
class="w-full mt-1 h-7 px-2 rounded-lg text-xs bg-gray-100 dark:bg-white/6 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-white/8 outline-none transition-colors"
/>
</div>
</div>
{/if}
</div>

<div class="shrink-0 pt-3 flex justify-end">
<button
class="text-[0.8125rem] text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors duration-100 disabled:opacity-50"
disabled={saving}
onclick={save}
>
{saving ? 'Saving...' : 'Save'}
</button>
</div>
{/if}
</div>
6 changes: 6 additions & 0 deletions cptr/frontend/src/lib/components/FileBrowser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,11 @@
closeMenu();
}

function copyPath(entry: TreeEntry) {
navigator.clipboard.writeText(entry.path);
closeMenu();
}

async function confirmRename(entryPath: string) {
const oldName = entryPath.split('/').pop() ?? '';
if (!renameValue.trim() || renameValue === oldName) {
Expand Down Expand Up @@ -1347,6 +1352,7 @@
{ label: '', divider: true, onclick: () => {} }
]
: []),
{ label: $t('files.copyPath'), icon: 'copy', onclick: () => copyPath(contextMenu!.entry) },
{ label: $t('files.rename'), icon: 'pencil', onclick: () => startRename(contextMenu!.entry) },
...(contextMenu.entry.type !== 'directory'
? [
Expand Down
6 changes: 6 additions & 0 deletions cptr/frontend/src/lib/components/Icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
/>
<path d="M6 16V3" />
<path d="M8 18H9C12.5 18 18 15.9 18 9.5V8" />
{:else if name === 'chat-fork'}
<path d="M4 12H9" />
<path d="M9 12C12.5 12 12.5 7 16 7H20" />
<path d="M17 4L20 7L17 10" />
<path d="M9 12C12.5 12 12.5 17 16 17H20" />
<path d="M17 14L20 17L17 20" />
{:else if name === 'chat-bubble'}
<path
d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 13.8214 2.48697 15.5291 3.33782 17L2.5 21.5L7 20.6622C8.47087 21.513 10.1786 22 12 22Z"
Expand Down
Loading
Loading