6.6 KiB

cloudcli-taskwork — workspace

Meta-repository for the Task Work plugin for CloudCLI UI (siteboon/claudecodeui). It holds the specification, the developer scripts and two submodules. It contains no code of its own — no package.json, no dependencies.

Specification: spec/SPEC-v3.md (current), design input: spec/DESIGN-DOC.md.

Repository map

Path Repository Role
(this repo) gitea:ai-first/cloudcli-taskwork Workspace: spec, scripts, submodule pins
plugin-taskwork/ gitea:ai-first/cloudcli-plugin-taskwork The product, developed here; manifest.json lives in its root
github:bvn13/cloudcli-plugin-taskwork Where users install the plugin from — public, anonymous HTTPS clone
cloudcli/ github:bvn13/claudecodeui Fork of the host; source of the three upstream PRs
github:siteboon/claudecodeui Upstream: source of updates, target of the PRs
gitea:ai-first/cloudcli Pull mirror of the fork, read-only

The plugin lives in two places on purpose: development and the submodule pin stay on Gitea, while the host installs it over anonymous HTTPS, which a private Gitea repository cannot serve. The GitHub copy is a push mirror — pushing to Gitea is enough, it syncs on its own. Do not add a GitHub remote to plugin-taskwork/ and do not push there by hand.

⚠️ Never push to gitea:ai-first/cloudcli. It is a pull mirror — anything pushed there is silently overwritten on the next sync. The cloudcli/ submodule points at the GitHub fork, and the mirror is deliberately not wired up as a remote.

Getting started

git clone --recurse-submodules ssh://git@gitea.bvn13.me:2221/ai-first/cloudcli-taskwork.git
cd cloudcli-taskwork
./scripts/bootstrap.sh

Then:

./scripts/dev-host.sh start       # installs the built plugin and starts the host

It prints the URL — http://localhost:5183 by default. stop, restart, status and logs do what they say; SERVER_PORT/VITE_PORT override the ports.

The host runs against your real environment: the same ~/.claude projects, the same ~/.cloudcli/auth.db, the same ~/.claude-code-ui/plugins. Nothing is sandboxed, so you see what a user would see. Ports default to 3010/5183 rather than 3001/5173 so an already installed CloudCLI keeps running — but note that both instances then share one database. Set DATABASE_PATH to separate them.

After changing the plugin:

cd plugin-taskwork && npm run build
cd .. && ./scripts/link-plugin.sh   # the host reads a copy, not a symlink

Client changes need only the plugin surface reopened; server changes need the host restarted (./scripts/dev-host.sh restart), because the plugin's backend process is spawned at host startup.

The plugin stores its data outside its own directory, in ~/.claude-code-ui/taskwork/tasks.json — the plugin directory is wiped on Update.

Access

All submodule URLs are SSH, so both submodules are writable with the same key setup: ssh://git@gitea.bvn13.me:2221/… for the plugin (the Gitea repositories are private) and git@github.com:bvn13/claudecodeui.git for the fork. The upstream remote stays on HTTPS — it is fetch-only and public.

Cloning therefore needs an SSH key registered with both hosts; check with ssh -T git@github.com and ssh -T -p 2221 git@gitea.bvn13.me.

Distribution goes through the public GitHub copy (github:bvn13/cloudcli-plugin-taskwork), because the host clones a plugin anonymously over HTTPS and the Gitea repository is private. The submodule keeps pointing at Gitea: that is where the plugin is developed and pushed first.

Scripts

Script Purpose
scripts/bootstrap.sh Init submodules, wire the upstream remote, install deps, build the host's native modules and the plugin
scripts/dev-host.sh Run the patched host locally: start, stop, restart, status, logs
scripts/export-patches.sh Regenerate plugin-taskwork/patches/*.patch from the fork's feature branches (§12.0)
scripts/link-plugin.sh Symlink the local plugin into the host's plugin directory (--unlink to remove)
scripts/check-submodule-pins.sh Verify every pinned submodule commit is reachable from its origin

Branches in cloudcli/

Each feature branch is cut from the upstream tag v1.37.2, never from another feature branch — that is what keeps the three pull requests independent.

Branch Base Purpose
main tracks upstream/main Upstream sync. Carries no commits of ours
feat/resizable-sidebar v1.37.2 PR-1 — resizable sidebar
feat/plugin-host-api v1.37.2 PR-2 — authenticated host API for plugins
feat/plugin-sidebar-surface v1.37.2 PR-3 — sidebar surface for plugins
dev/taskwork merge of the three Local run and debugging; the submodule is pinned here

dev/taskwork never takes part in a pull request and may be recreated at any time.

Working with the submodules

  • Commit code inside the submodule, push it, and only then record the new pin here with a separate commit chore: bump <submodule> to <sha>.
  • Update with git submodule update --remote --merge.
  • Run ./scripts/check-submodule-pins.sh before pushing a pin bump.

Status

Piece State
Plugin v1.0.0, pushed to Gitea; installs, builds and runs (npm install --ignore-scripts + npm run build in ~3 s)
feat/resizable-sidebar Pushed to the fork. PR-1 not opened yet; no issue needed
feat/plugin-host-api Pushed to the fork. Issue text in spec/upstream/issue-1-plugin-host-api.md, PR text in plugin-taskwork/docs/upstream-pr-2.md
feat/plugin-sidebar-surface Pushed to the fork. Issue text in spec/upstream/issue-2-plugin-sidebar-surface.md, PR text in plugin-taskwork/docs/upstream-pr-3.md
dev/taskwork Merge of the three plus one integration commit (host API in the sidebar surface) that never goes upstream; the cloudcli pin points here

Remaining before upstream contact (§19 of the spec): open issue #1, then PR-2; issue #2, then PR-3; PR-1 can go on its own. Also outstanding: the manual acceptance checklist (§15.4), which needs a running host in a browser.

Release

See §13.2 of the spec. In short: export patches → bump the plugin version in package.json and manifest.json → build, typecheck, test → commit build/, patches/, CHANGELOG.md → tag vX.Y.Z in the plugin repo → bump the pins here.

Licence

The plugin and the fork are AGPL-3.0-or-later, following the upstream host.