Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
334eb9e
feat(harness): discover agent skills in the sandbox
sanchitrk Oct 14, 2026
f08d05b
test(harness): run one conformance suite on every sandbox driver (#77)
sanchitrk Oct 14, 2026
fce42e0
feat(web): add landing page, site themes and Cmd+K theme palette
sanchitrk Oct 15, 2026
6d6ee64
feat(desktop): pick a project folder in Finder from the start page
sanchitrk Oct 15, 2026
c647bec
feat(desktop): list codework sessions in the start-page sidebar
sanchitrk Oct 15, 2026
6115bf6
feat(web): resize and toggle the start-page sidebar
sanchitrk Oct 15, 2026
32b75e5
fix(desktop): keep the sidebar toggle clear of the window buttons
sanchitrk Oct 15, 2026
eee50cb
feat(desktop): use the 3D brand mark as the app icon
sanchitrk Oct 15, 2026
1bde3ad
feat(web): size the project menu like t3code and add a heading
sanchitrk Oct 15, 2026
6b6ea0d
feat(web): use the system fonts for a native feel
sanchitrk Oct 15, 2026
dbcfa47
feat(web): match t3code's prompt box and project picker
sanchitrk Oct 15, 2026
cb69905
feat(desktop): open a session from the start page in the right workspace
sanchitrk Oct 16, 2026
26487f1
feat(web): bring back rounded, raised frames on the site palettes
sanchitrk Oct 16, 2026
06cff1f
feat: load a session's conversation into its frame
sanchitrk Oct 16, 2026
7f71d65
feat(web): browser-style workspace tabs with back and home
sanchitrk Oct 16, 2026
0f0798f
fix(web): keep each workspace tab on its own focused frame
sanchitrk Oct 16, 2026
9273bea
feat(web): two-line workspace tabs set by the focused widget
sanchitrk Oct 16, 2026
5ddcbc3
feat(web): show the workspace tabs on the start page
sanchitrk Oct 16, 2026
383c599
feat(desktop): allow deleting every workspace
sanchitrk Oct 16, 2026
98924be
fix(web): open a new workspace only once the list has it
sanchitrk Oct 16, 2026
9fbaa8d
fix(web): let the frame that set the tab own it, so tabs don't flicker
sanchitrk Oct 16, 2026
15ce8e3
refactor(desktop): remove the Files widget and its fs.list RPC
sanchitrk Oct 16, 2026
7df0050
refactor(web): remove the placeholder widget
sanchitrk Oct 16, 2026
79289f9
feat(server): add an event log for widgets
sanchitrk Oct 16, 2026
2a895d7
feat(codework): expose session.log over RPC
sanchitrk Oct 16, 2026
1589170
feat(server): add request and reply to the event log
sanchitrk Oct 16, 2026
65f54aa
feat(widget): add the widget SDK with view and backend halves
sanchitrk Oct 16, 2026
d9250b3
feat(web): add the Session widget backend
sanchitrk Oct 16, 2026
d4b395d
feat(web): show the Session widget live, with a composer
sanchitrk Oct 16, 2026
414f2b9
Feature/tui improvements (#71)
prem315 Oct 16, 2026
d146b50
feat(web): stream Session replies live and fold only real work
sanchitrk Oct 16, 2026
0373c49
feat(web): virtualize the Session transcript and page its history
sanchitrk Oct 16, 2026
3694acf
feat(widget): stop following a session once no view watches it
sanchitrk Oct 16, 2026
a4c1124
feat(web): fold frames that do not fit instead of scrolling the desktop
sanchitrk Oct 16, 2026
32374bd
feat: create sessions from the desktop start page and name their proj…
sanchitrk Oct 16, 2026
0114d6d
Merge branch 'feat-desktop-wave-2' into canary
sanchitrk Oct 16, 2026
a6c1c0f
feat(plugin): default the reasoning level to medium
sanchitrk Oct 16, 2026
0f22ae1
feat: list models over RPC and pick model and reasoning on the start …
sanchitrk Oct 16, 2026
d8b65e2
fix: pin effect 4.0.5 and platform-node-shared (#85)
sanchitrk Oct 17, 2026
9945773
feat(tui): populate model and thinking pickers via model.list RPC (#87)
prem315 Oct 17, 2026
89a70d7
feat(desktop): desktop app with tweaks and improvements (#86)
sanchitrk Oct 18, 2026
c623a3e
chore: tweaks
sanchitrk Oct 18, 2026
102e692
chore: name release tags <pkg>@v<version> (#88)
sanchitrk Oct 18, 2026
20b4b21
feat(desktop): installable canary builds, composer notices, Servers s…
sanchitrk Oct 18, 2026
5c48db0
feat(tui): discover server via service.json, verify server.info, and …
prem315 Oct 19, 2026
f2cf72a
feat(tui): support steer/followUp prompts while busy and handle remai…
prem315 Oct 19, 2026
37d4aa6
Add TUI reconnect and durable session log recovery (#95)
prem315 Oct 19, 2026
0d10cb8
Feat/model catalog (#96)
sanchitrk Oct 19, 2026
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
59 changes: 59 additions & 0 deletions .github/workflows/catalog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Model Catalog

# Publishes the model catalog to https://catalog.codework.sh/v1/models.json, the R2 bucket that
# `infra/catalog` deploys. `vp run catalog` builds it from models.dev and OpenRouter, refuses one
# that fails its checks, and reports whether it differs from the published one; only a changed
# catalog is uploaded.
on:
schedule:
- cron: "23 * * * *"
workflow_dispatch:
inputs:
publish:
description: "Upload the catalog to R2 when it changed"
required: true
default: true
type: boolean

permissions:
contents: read

concurrency:
group: catalog
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
# A bucket-scoped R2 API token (Object Read & Write on catalog-bucket-live only), stored as
# CATALOG_R2_ACCESS_KEY_ID / CATALOG_R2_SECRET_ACCESS_KEY, and the account's S3 endpoint
# (https://<account id>.r2.cloudflarestorage.com) as CATALOG_R2_ENDPOINT.
environment: catalog
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@v1.21.1
with:
node-version: 24
run-install: false
cache: false
- run: vp install --frozen-lockfile --filter @codeworksh/aikit
- id: build
run: vp run --filter @codeworksh/aikit catalog "$GITHUB_WORKSPACE/.artifacts/catalog/v1/models.json"
- uses: actions/upload-artifact@v4
with:
name: catalog
path: .artifacts/catalog
retention-days: 14
- if: steps.build.outputs.changed == 'true' && (github.event_name == 'schedule' || inputs.publish)
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CATALOG_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CATALOG_R2_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: auto
R2_ENDPOINT: ${{ secrets.CATALOG_R2_ENDPOINT }}
# One PUT, never multipart: R2's ETag is then the file's MD5, which clients send back to get a 304.
run: >-
aws s3api put-object --bucket catalog-bucket-live --key v1/models.json
--body .artifacts/catalog/v1/models.json
--endpoint-url "$R2_ENDPOINT"
--content-type application/json
--cache-control "public, max-age=300"
94 changes: 79 additions & 15 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ name: Publish
# One workflow publishes every channel, since npm trusted publishing names a single workflow file.
# - canary / dev: every push to that branch
# - latest: run by hand on `main`; publishes each package whose version is not on npm yet
# dev and latest also build the standalone binary and attach it to a GitHub Release: `devel`, one
# prerelease replaced on every dev push, or `cli-v<version>`, marked latest. canary stays npm-only.
# dev and latest also make GitHub Releases (scripts/github.mjs): `devel`, one prerelease with the
# standalone binary replaced on every dev push, or `<pkg>@v<version>` per package released on
# latest, the CLI's with the binary and marked latest. canary makes `nightly`, one prerelease
# with the desktop app replaced on every canary push.
on:
push:
branches: [canary, dev]
Expand Down Expand Up @@ -192,16 +194,78 @@ jobs:
path: release
merge-multiple: true
# codework.sh/install verifies each download against SHA256SUMS.
- run: |
(cd release && sha256sum *.tar.gz > SHA256SUMS)
version="$(node scripts/version.mjs "$CHANNEL" packages/codework)"
if [ "$CHANNEL" = dev ]; then
gh release delete devel --cleanup-tag --yes || true
gh release create devel release/* --prerelease --target "$GITHUB_SHA" \
--title "CLI $version" --notes "Development build $version, from $GITHUB_SHA."
elif gh release view "cli-v$version" > /dev/null 2>&1; then
echo "cli-v$version is already released"
else
gh release create "cli-v$version" release/* --latest --target "$GITHUB_SHA" \
--title "CLI $version" --generate-notes
fi
- run: (cd release && sha256sum *.tar.gz > SHA256SUMS)
- run: node scripts/github.mjs "$CHANNEL" release

desktop:
needs: guard
if: github.ref_name == 'canary'
name: desktop (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: true
matrix:
# Each on its own platform: electron-builder packages for the host, and macOS signs.
include:
- target: mac-arm64
runner: macos-14
args: --mac --arm64
- target: linux-arm64
runner: ubuntu-24.04-arm
args: --linux --arm64
- target: linux-x64
runner: ubuntu-24.04
args: --linux --x64
env:
CODEWORK_RELEASE_ID: ${{ needs.guard.outputs.id }}
steps:
- uses: actions/checkout@v6
# The pacman target packs with bsdtar.
- if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libarchive-tools
- uses: voidzero-dev/setup-vp@v1.21.1
with:
node-version: 24
run-install: false
cache: false
# The app packages the web app and the app server it builds, so those install too.
- run: vp install --frozen-lockfile --filter '@codeworksh/desktop...' --filter '@codeworksh/server...'
- working-directory: apps/desktop
run: vp run package "$CHANNEL" ${{ matrix.args }}
# Installers only; electron-builder's update blockmaps and unpacked app stay behind.
- uses: actions/upload-artifact@v7
with:
name: desktop-${{ matrix.target }}
path: |
apps/desktop/dist/codework-desktop-*.dmg
apps/desktop/dist/codework-desktop-*.zip
apps/desktop/dist/codework-desktop-*.AppImage
apps/desktop/dist/codework-desktop-*.deb
apps/desktop/dist/codework-desktop-*.pacman
if-no-files-found: error
retention-days: 1

# After npm, so `nightly` never names a commit whose packages did not ship.
nightly:
needs: [guard, publish, desktop]
if: github.ref_name == 'canary'
runs-on: ubuntu-latest
permissions:
contents: write
env:
CODEWORK_RELEASE_ID: ${{ needs.guard.outputs.id }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@v1.21.1
with:
node-version: 24
run-install: false
cache: false
- uses: actions/download-artifact@v8
with:
pattern: desktop-*
path: release
merge-multiple: true
- run: (cd release && sha256sum codework-desktop-* > SHA256SUMS)
- run: node scripts/github.mjs canary release
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules
.pnpm-store

out
.electron-runtime
dist
build
.next
Expand Down Expand Up @@ -56,5 +57,14 @@ models.gen.json

.alchemy

.freebuff
opencode.json

# Rust build output (packages/tui binary; the launcher loads the built artifact).
target

# testing
videos

# Catalog CI output (.github/workflows/catalog.yml)
.artifacts
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ This file is the canonical source for unreleased changes and published release n

- Add in-progress work under `## [Unreleased]

## [Unreleased]

### Added

- Added Agent Skills (`codework.prompt.skill`). A skill is a directory with a `SKILL.md` whose frontmatter has a `name` and a `description`; `.codework/skills` may also hold standalone `.md` skills. Skills are found in the session's sandbox, local or remote, and never on the host or in `<home>`: `.codework/skills` in the working directory, then `.agents/skills` in the working directory and each parent up to the git root (or up to the sandbox root outside a repository). `.gitignore`, `.ignore` and `.fdignore` are honoured. The system prompt lists only each skill's name, description and location under `<skills>`; the model reads the full file when a task matches. A skill with `disable-model-invocation: true` is not listed. Invalid fields, unreadable files and name collisions log a warning instead of failing; the first skill found keeps the name. The hint names the `read` tool, or `bash` when `read` is off, and names no tool when the reader is hidden from the prompt. Turn it off with `{ "plugin": "codework.prompt.skill", "enabled": false }` in `plugins`.
- Added `project: { name }` to `session.create`. It names the session's project when the session creates it, ahead of the repository's and the folder's name; a project that already exists keeps its name. The name must be trimmed and not empty.
- Added the `project.rename` RPC (`{ projectId, name }`), which renames a project and fails with `ProjectNotFoundError` for an unknown id. The harness exposes it as `Project.rename`.
- The desktop start page creates a session in the folder you pick, or in a memory sandbox, sends your first prompt and opens the session. A memory session's project is named "In Memory".
- Added the `model.list` RPC (`{ hostDir? }`). It returns the providers the server holds credentials for (an API key in its environment, a stored OAuth login, or a keyless provider from settings), each model's supported thinking levels, and the `default` model and thinking level that settings pick for a session anchored at `hostDir`, with its display names. Without `hostDir` only the user's settings apply. Credentials are checked for presence, not validity. A broken settings file fails with `SettingsError`.
- The desktop start page's composer has a model picker and a Reasoning picker. The model picker lists providers down a rail with their models beside it and searches across all of them. With no model picked, settings decide; a default whose provider has no credentials shows muted and cannot be picked. Reasoning offers only the levels the model supports and marks the settings level as Default. The picks are remembered across restarts.
- Added a model catalog bundled with `@codeworksh/aikit` for OpenAI, Anthropic and OpenRouter (`vp run baseline` in `packages/aikit` regenerates it). It is read when no catalog has been generated yet, so a first run works offline. A generated catalog replaces each provider it lists.
- The model catalog is published to `https://catalog.codework.sh/v1/models.json` (an R2 bucket, `infra/catalog`) by a scheduled GitHub Action, which refuses a catalog that fails its schema check, misses a required model or drops more than a fifth of a provider's models. A refresh now downloads that catalog instead of building one from models.dev on every machine, and asks with the MD5 of its last download so an unchanged catalog costs a 304. A model whose protocol or API method this version does not know is left out. `CODEWORK_CATALOG_URL` points a client at another catalog, a `file:` URL at a local copy. `aikit modelgen` still builds one locally.
- With `OPENROUTER_API_KEY` set, a catalog refresh keeps only the OpenRouter models that key may use, with the key's context limits and prices (`GET /models/user`).
- Added `gpt-6.1-sol` (500k context), `gpt-6-sol` and `gpt-6-astra` to OpenAI Codex.

### Changed

- The default thinking level, for settings that name none, is now `medium` instead of `high`.
- The model catalog generator follows Pi's current rules. OpenAI Codex entries are built from models.dev's OpenAI entries, so their prices and long-context tiers come from there. `gpt-5.4` and `gpt-5.4-mini` are no longer listed for Codex, because the Codex backend rejects them for ChatGPT accounts.
- OpenAI reasoning levels come from models.dev's `reasoning_options`, and OpenRouter models are listed from OpenRouter's own `/models`, which gives the reasoning efforts each one accepts. `:batch` variants are left out.
- Prices take models.dev's long-context tiers for every provider, and OpenAI service-tier multipliers come from models.dev's modes (for example ultrafast 6x on GPT-6.1 Sol). Direct OpenAI requests to the GPT-5.4+ and GPT-6 models default to the 272k short-context window; settings can raise `contextWindow`.
- The generator drops the models.dev alias `gpt-5.6`, which OpenAI's API rejects. Claude Opus 4.7+, Opus 5.x, Sonnet 5.5 and Haiku 5.5 no longer get a `temperature` field, which their API rejects.
- Renamed `OPENCODE_MODELS_URL` and `OPENCODE_MODELS_DEV_FILE` to `CODEWORK_MODELS_DEV_URL` and `CODEWORK_MODELS_DEV_FILE`.
- Upgraded the AI SDK packages to their latest releases, including `@ai-sdk/xai` 5, which drops the Chat Completions API: xAI models run on Responses only, as the catalog already set, and `XaiOptions` takes only Responses options. All providers now share one `@ai-sdk/provider` version.
- A missing model catalog is no longer an error (`model-catalog-missing` is gone); the bundled catalog is read instead.

### Fixed

- Fixed `codework` failing to start after a fresh npm install with `The requested module 'effect/Path' does not provide an export named 'make'`. `@effect/platform-node` pulled in a newer `@effect/platform-node-shared` than the pinned `effect` supports. Every Effect package is now pinned to 4.0.5, and `@effect/platform-node-shared` is pinned with them.

## [@codeworksh/cli@0.3.0] - 2026-10-13

### Added
Expand Down
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@ Conventional Commit style with optional package scopes, e.g `feat(aikit): ...`,

Every package is published by CI from `.github/workflows/publish.yml`, which runs `vp run release <channel>` (`scripts/release.mjs`). It builds the TUI binaries, then publishes the packages in dependency order, derived from their `package.json` workspace dependencies (`scripts/workspace.mjs`), pinning each package to the exact versions uploaded in the same run. `scripts/publish.mjs` builds a single package, rewrites its manifest and publishes it from a temp dir.

- **canary**: every push to `canary`, without `vp check` or typecheck, for quick testing. Versions are `<version>-canary.<run>.<attempt>.g<sha>`.
- **canary**: every push to `canary`, without `vp check` or typecheck, for quick testing. Versions are `<version>-canary.<run>.<attempt>.g<sha>`. It also packages the desktop app (`apps/desktop`, `vp run package <channel>`) as "CodeWork Canary" for macOS arm64 and Linux x64/arm64, and replaces the `nightly` prerelease with it.
- **dev**: every push to `dev`. Versions are `<version>-dev.<YYYYMMDDHHMMSS>` (UTC).
- **latest**: run the workflow by hand on `main`. It publishes each package whose manifest version is not on npm yet and skips the rest.

Versions are bumped locally with `vp run bump <aikit|plugin|harness|tui|cli> [version]`, which runs `bumpp` with the package's `bump.config.ts` and commits and tags `@codeworksh/<pkg>@<version>` without pushing. `vp run bump tui` moves the launcher and its three platform packages together.
GitHub Releases (`scripts/github.mjs`): dev replaces the `devel` prerelease with the CLI binaries; latest makes a `<pkg>@v<version>` release per package not released yet, the CLI's carrying the binaries. canary replaces the `nightly` prerelease with the desktop app.

Versions are bumped locally with `vp run bump <aikit|plugin|harness|tui|cli|desktop> [version]`, which runs `bumpp` with the package's `bump.config.ts` and commits and tags `<pkg>@v<version>` without pushing. `vp run bump tui` moves the launcher and its three platform packages together.

Flow:

Expand Down
20 changes: 20 additions & 0 deletions apps/contract/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@codeworksh/contract",
"version": "0.0.0",
"private": true,
"description": "The desktop app server's RPC contract, shared by the app server and the web app.",
"type": "module",
"exports": {
".": "./src/contract.ts"
},
"scripts": {
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@codeworksh/widget": "workspace:*",
"effect": "4.0.5"
},
"devDependencies": {
"typescript": "catalog:"
}
}
Loading
Loading