viburnum
A manager that Keeps All Linked Installs Neatly Synced In Two Universes.
A workbench for your own DeepSeek Harness plugins: create them, mount them, choose which version runs, and keep two machines in sync. It watches the clones your profile is linked to, and one click fetches, pushes, fast-forwards or rebases each one onto the branch it follows — so both machines run the same code without you remembering which one pushed last.
A row in the sidebar carries one dot: green when everything is current, violet when something can be pulled, orange when work is uncommitted, red when it is unpushed or diverged. Installing from a directory, a repository URL or a GitHub organisation follows in 0.2.
viburnum began as one person's two-machine workshop, and it is public now because that problem is not
unique to one person: everyone who develops a harness plugin on more than one machine has the same
"which checkout is current?" question. Named after the shrub that holds its berries through the
winter: in place, visible, current. The command is vib; viburnum works too.
laptop ⇄ origin ⇄ work machine
one click: fetch → ff | rebase → push
Each bundle follows a track — main, or dev while you are trying something — and the track is
per machine, so the laptop can try dev while the work machine stays on main. Switching is the same
button with the other branch. An update is a fetch and a fast-forward in the linked directory, so
there is no pnpm run, no lockfile write, and no profile edit.
viburnum never commits and never force-pushes. When a rebase would rewrite something already published, it stops and shows both sides; when the rebase conflicts, it aborts and hands you the files.
Status: 0.1.0 released (tag v0.1.0), public under the MIT licence.
docs/PLAN.md is the approved plan and carries the gate-3 evidence;
DESIGN.md carries the premise and decisions. main is the stable line (see
Branches).
Public and open
- MIT licence. Use it, fork it, ship it; no warranty.
- Built against the public rulebook. dsh-plugin-development is the skill and process this repository follows — plan gates, bundle shape, standards, templates and lessons. A process nobody can read is a rumour.
- Contributions are welcome. Read CONTRIBUTING.md first: work branches cut from
dev,npm run checkis the gate, and one change per pull request. Security reports go through SECURITY.md, not public issues. - English first. UI copy ships in English; another language is added only when the plugin actually ships one.
- No telemetry, no network daemon, no account. The only outbound traffic is git's own
fetchandpush, in the directories the profile already links.
What 0.1.0 does
- One dot in the sidebar, above Plugins: the worst state across every linked checkout — green current, violet pullable, orange uncommitted, red unpushed or diverged, grey unknown.
- The viburnum page: the mounted checkouts with their track, fresh/behind/ahead counts, directory,
the incoming changelog, and
Refresh/Sync all; per bundleUpdate,Sync,Revertand a track selector. Nothing is modal; a blocked row never stops the next one. - Moves:
Updateis a fetch and a fast-forward.Syncpushes unpublished commits, fast-forwards, or rebases private divergence and pushes it; it refuses to rebase published history and aborts a conflicting rebase before reporting it.Revertrestores the latest update or switch snapshot. - Five model-facing tools:
vib_status,vib_update,vib_sync,vib_switch,vib_revert. Reads are free; every move asks for approval. - A CLI:
vib status | refresh | update | sync | switch | revert, plus--jsonand--dry-run. - State with the profile: tracks, cached rows, receipts and snapshots at
$DSH_HOME/profiles/<profile>/.viburnum/state.json, written atomically and pruned on write.
Not in 0.1.0: install doors (directory, repository URL, organisation), the per-plugin workbench page,
vib new, organisation catalog, timeline and hygiene. Those are scoped in SCOPE.md.
Install
The plugin is installed into a profile by the plugin manager, never by hand:
dsh plugin --profile web add C:\Users\<you>\Documents\deepseek-harness\viburnum
The CLI needs vib on PATH only for terminal use:
cd C:\Users\<you>\Documents\deepseek-harness\viburnum
npm link
Configure
The row is viburnum in cordis.patch.yml; override any field by id:
- id: viburnum
config:
checkIntervalMinutes: 15
fetchTimeoutMs: 30000
| Field | Default | Meaning |
|---|---|---|
checkIntervalMinutes |
5 |
Background check interval; 0 disables checks on start and on a timer (on-demand only). |
fetchTimeoutMs |
20000 |
Bound on one git process, including a fetch. |
catalogOwners |
['dsh-works'] |
GitHub owners the 0.2 organisation door will read. |
pluginsDir |
'' |
Shelf directory for 0.2 installs; empty means $DSH_HOME/viburnum/plugins. |
Invalid configuration fails the plugin load with the field and range named.
The state file
$DSH_HOME/profiles/<profile>/.viburnum/state.json is owned by the plugin: version: 2, bundle
records (track, last check, cached row), a 50-entry action history, and 20 update/switch snapshots
kept for 30 days. The page, the tools and the CLI share it through the one core; writes are
temp-file + rename.
The page's data does not travel through a generated Remote endpoint — an out-of-tree bundle cannot add
one. It uses two same-origin JSON routes registered on the Host web server,
/viburnum/status and /viburnum/action, which require the x-viburnum: 1 header so a cross-site
form cannot act. The browser half polls the status route every 30 seconds and after every action.
Verification (2026-11-06)
Verified live in the web profile:
npm run check— 78 tests, 0 failures.- Installed with the plugin manager:
application: applied, no warnings. vib_statusandvib statusboth report the three mounted bundles (dsh-plugin-alerts,dsh-plugin-pixelart,dsh-plugin-viburnum), each current, dot green.GET /viburnum/statusreturns200with the rows and config; the browser client had fetched it (transport.clientSeenAtwith a Chrome user agent), so the page transport works end to end.- Client slot inspection:
sidebar.panellistoccupantviburnumatorder: -10beforeplugins(order: 0), andmainoccupantviburnumactive. - One live fetch hit the 20 s bound and was reported as a timeout without leaving a git process
behind;
vib statusstill answered from cache.
Not run, and therefore not claimed: visual checks in light and dark, an approval prompt end to end (the answerer is disabled in this session), a real move on a user checkout, and the second machine.
Limits
- viburnum never commits and never force-pushes.
- 0.1.0 is accepted against offline fixture repositories. No second machine is available, so cross-machine sync is not verified in this release.
- The page transport is a localhost-only JSON route pair; it stores no credentials and reads no secrets. Git inherits whatever the machine already uses.
- Only
link:andfile:dependencies are watched. Registry bundles are the plugin manager's job.
Branches
main is the stable line; dev is the integration line where work happens. Features use
feature/<slug> branches cut from dev and merged back into it; a hotfix/<slug> cuts from
main, merges into main, then merges back into dev. A release merges dev into main after
the full check, tags v<version>, and syncs main back into dev. The detailed rule lives in
the dsh-plugin-development skill.
Licence
MIT — see LICENSE. The candidate butterfly marks in icons/ came from the
design notebook and are part of the repository; the eventual shipped mark will be chosen there.
House rules: npm run check is the gate, node:* before a dependency, no telemetry, and the only
writes are the profile state file and the checkouts the user asked a move to touch.
No comments yet. Be the first to write one.