A visual config editor for OpenCode.
Edit your OpenCode JSON configuration without ever opening ~/.config/opencode/opencode.json by hand.
Loom is a small desktop app that turns OpenCode's JSON config into a structured, validated UI. It tracks dirty state, shows you a diff before saving, validates against the upstream schema, and keeps a .bak backup so you never lose a working config.
Note
Loom runs on macOS and Linux today. A Windows build is on the Roadmap.
brew tap kespineira/homebrew-tap
brew install kespineira/homebrew-tap/loom-occurl -fsSL https://raw.githubusercontent.com/kespineira/loom-oc/main/install.sh | bashGrab the latest .dmg from the Releases page.
The installer script also works on Linux — it drops an AppImage into ~/.local/bin/loom-oc and registers a .desktop entry:
curl -fsSL https://raw.githubusercontent.com/kespineira/loom-oc/main/install.sh | bashMake sure ~/.local/bin is on your PATH.
Releases also include a Debian package and an RPM if you prefer system packaging:
# Debian / Ubuntu
sudo apt install ./Loom_<version>_amd64.deb
# Fedora / RHEL
sudo dnf install ./Loom-<version>-1.x86_64.rpm
# AppImage
chmod +x Loom_<version>_amd64.AppImage
./Loom_<version>_amd64.AppImageLinux builds depend on webkit2gtk-4.1 and gtk-3 at runtime. The .deb declares them; for the AppImage on minimal distros you may need to install them manually.
- Global and project scopes with backend-resolved paths.
- Visual editors for settings, agents, providers, MCP servers, permissions, commands, and plugins.
- Diff review before every save — you see exactly what changes hit disk.
- Schema validation against the cached upstream OpenCode JSON Schema before writing.
- Conflict detection via file revisions, so external edits aren't overwritten silently.
- Automatic
.bakbackup before overwriting an existing config. - Undo / redo and dirty-state tracking across the whole app.
- Light and dark themes, collapsible sidebar, and a
Cmd+Kcommand palette. - Auto-updates through Tauri Updater (checks GitHub Releases on launch).
| Shortcut | Action |
|---|---|
Cmd+K / Ctrl+K |
Open the command palette |
Cmd+S / Ctrl+S |
Validate and review save changes |
Cmd+Z / Ctrl+Z |
Undo config change when focus is outside a text field |
Cmd+Shift+Z / Ctrl+Shift+Z |
Redo config change when focus is outside a text field |
Cmd+\ / Ctrl+\ |
Toggle the sidebar |
Cmd+1 through Cmd+7 |
Jump between editor sections |
Esc |
Close dialogs |
- SvelteKit 2 + Svelte 5 in SPA mode via
adapter-static. - Tauri 2 as the desktop shell.
- TypeScript on the frontend.
- Rust backend commands for path resolution, JSON read/write, backups, and conflict checks.
json-schema-to-typescriptto compile the upstream OpenCode JSON Schema intoOpenCodeConfigdefinitions.- Ajv 2020 for runtime schema validation.
src/
routes/ SvelteKit app shell
lib/
components/editors/ Visual OpenCode config editors
components/ui/ Reusable UI primitives
schema/ Cached schema, generated types, validation helpers
stores/ Svelte stores
tauri/commands.ts Typed wrappers around invoke()
src-tauri/
src/
lib.rs #[tauri::command] entry points
paths.rs XDG-aware config path resolution
config.rs JSON read/write, revisions, backups, conflict checks
scripts/
fetch-schema.ts Downloads opencode.ai/config.json and codegen
- Node.js (version pinned in
.nvmrc— currently 22, required by pnpm 11) andpnpm. - Rust stable toolchain via
rustup. - Tauri 2 system dependencies.
pnpm installSchema generation runs before dev/build through pnpm schema:fetch. It downloads https://opencode.ai/config.json, caches it at src/lib/schema/opencode.schema.json, and emits typed bindings to src/lib/schema/opencode.ts. If the host is unreachable and there is no cached schema, the script falls back to a permissive type OpenCodeConfig = Record<string, unknown> stub so local development can continue.
pnpm tauri:dev # full Tauri shell
pnpm dev # frontend only, no Tauri shellpnpm tauri:build # full installer
pnpm build # SvelteKit static bundle onlypnpm check
pnpm test
pnpm build
cd src-tauri && cargo test --libIf your Rust toolchain has formatting and lint components installed, also run:
cd src-tauri && cargo fmt --all -- --check
cd src-tauri && cargo clippy --all-targets -- -D warnings| Script | Description |
|---|---|
pnpm dev |
SvelteKit dev server |
pnpm build |
SvelteKit static build |
pnpm check |
svelte-kit sync plus svelte-check |
pnpm test |
Vitest unit tests |
pnpm schema:fetch |
Fetch and regenerate OpenCodeConfig types |
pnpm version:check |
Verify version is aligned across the three sources of truth |
pnpm version:bump |
Bump version in package.json, Cargo.toml, tauri.conf.json |
pnpm tauri:dev |
Tauri dev app |
pnpm tauri:build |
Tauri release build |
Releases are cut by pushing a v* tag, which triggers .github/workflows/release.yml to build a universal macOS bundle and Linux artifacts (.deb, .rpm, AppImage), publish them to the same GitHub Release, and bump the Homebrew tap.
pnpm version:bump 0.3.0
git commit -am "chore: bump v0.3.0"
git tag v0.3.0
git push origin main v0.3.0CI runs pnpm version:check to fail fast if package.json, src-tauri/Cargo.toml, and src-tauri/tauri.conf.json drift apart.
- Linux build (AppImage /
.deb/.rpm) - Windows build (
.msi) - In-app schema doc viewer
- Diff-aware merge when external edits are detected
Open to suggestions — see CONTRIBUTING.md.
Issues and pull requests are welcome. Please read CONTRIBUTING.md first — it covers dev setup, commit conventions, and the PR flow.
For security issues, do not open a public issue. See SECURITY.md.
MIT © Kevin Espiñeira
