- Svelte 54.1%
- JavaScript 44.5%
- CSS 0.6%
- Nix 0.3%
- Dockerfile 0.3%
- Other 0.2%
- image job needs a host runner with node for actions/checkout@v4;
`runs-on: docker` + container: docker:27-cli fails because the cli
image has no node. Switch to runs-on: docker-builder (same label
edufeed-app uses on this Forgejo instance).
- Dockerfile no longer needs .npmrc (deleted in
|
||
|---|---|---|
| .forgejo/workflows | ||
| docs/superpowers/plans | ||
| src | ||
| .dockerignore | ||
| .envrc | ||
| .gitignore | ||
| .mcp.json | ||
| Caddyfile | ||
| CLAUDE.md | ||
| create-page.png | ||
| Dockerfile | ||
| explore.png | ||
| flake.lock | ||
| flake.nix | ||
| footer-check.png | ||
| homepage.png | ||
| import-page.png | ||
| package-lock.json | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
| settings-page.png | ||
| signin-modal.png | ||
| svelte.config.js | ||
| tree-3-levels.png | ||
| tree-verification.png | ||
| vite.config.js | ||
NOCABS
Vocabs but on Nostr — a Svelte 5 app for authoring, browsing, and sharing controlled vocabularies as Nostr events, using the NIP-VOCAB six-kind split (ConceptSchemes, Concepts, Collections — published and draft variants).
NOCABS is a pure client-side SPA: all Nostr work happens in the browser (applesauce signers, localStorage-backed drafts, direct relay subscriptions). There is no backend, no server-side data, no cookies.
Develop
Requirements: Node 22+, pnpm (via corepack enable).
pnpm install
pnpm dev # http://localhost:5173
pnpm test
The two libs (nostr-vocab-core, nostr-vocab-skos-import) are pinned to
public tarball URLs on the Forgejo npm registry directly in package.json.
No .npmrc, no SSH keys, no registry routing needed — pnpm install fetches
them by URL and locks the integrity hash in pnpm-lock.yaml.
Local development against sibling repos
If you're iterating on the libs at the same time, you can override the registry
versions with a file path without touching the committed package.json:
pnpm link ../nostr-vocab-core
pnpm link ../nostr-vocab-skos-import
Undo with pnpm unlink or pnpm install to restore registry versions.
Build
pnpm build
Output is a fully static site in build/. Serve it with any static host — Caddy,
nginx, GitHub Pages, Netlify, Cloudflare Pages, npx serve build, etc.
Dynamic routes like /vocab/[pubkey]/[d] depend on client-side routing. Your static
host must fall back unknown paths to index.html (the bundled Caddyfile does
this out of the box).
Run anywhere (Docker)
A production image is published to the Forgejo container registry on every push to
main:
docker run --rm -p 8080:80 git.edufeed.org/edufeed/nocabs:latest
# open http://localhost:8080
The image is caddy:2-alpine serving the built static assets on port 80. No env
vars are needed. For TLS, put it behind any reverse proxy (Traefik, Caddy, nginx,
Cloudflare) terminating HTTPS upstream.
Deploy behind your own reverse proxy
Example Caddy block on the host:
nocabs.example.com {
reverse_proxy nocabs:80
}
Example nginx server block:
server {
server_name nocabs.example.com;
listen 443 ssl http2;
# ... tls config ...
location / {
proxy_pass http://nocabs:80;
}
}
Homelab deploy (edufeed)
The homelab Ansible repo ships a role and playbook mirroring the edufeed-app
pattern (docker-compose + Traefik labels on the proxy network):
ansible-playbook playbooks/deploy_nocabs.yml
Default domain: nocabs.edufeed.org. Change via nocabs_domain in
roles/nocabs/defaults/main.yml or the playbook vars.
CI / Release
.forgejo/workflows/build.ymlruns tests on every push/PR and builds+pushes the image onmainand onv*tags.- Required repo secret:
REGISTRY_TOKEN— a token withwrite:packageonedufeed/nocabscontainer registry.
To cut a release: bump package.json version, commit, tag v0.2.0 (or whatever),
push the tag. The image will be published with :latest, :0.2.0, and the commit
SHA.
Bumping lib versions
When a new nostr-vocab-core or nostr-vocab-skos-import is published to
the Forgejo npm registry, update the tarball URLs in package.json (the
version appears twice per URL), then pnpm install to refresh the lockfile
and commit both files.
One-time preflight (first bring-up)
- In the Forgejo UI for the
edufeedorg: generate an API token withwrite:packagescope. Add it as secretFORGEJO_NPM_TOKENon both lib repos (nostr-vocab-core,nostr-vocab-skos-import). - In
nostr-vocab-core: commit the publish workflow, tagv0.2.3, push the tag. The Forgejo Action publishesnostr-vocab-core@0.2.3. Mark the package public in the Forgejo packages UI. - In
nostr-vocab-skos-import: same — tagv0.2.4, push, mark public. - In
nocabs: runpnpm installlocally to regeneratepnpm-lock.yamlagainst the public tarball URLs, commit the updated lockfile, push. From this commit onwardpnpm install --frozen-lockfileworks in CI and on any clean machine — no credentials needed for install. - Create the
REGISTRY_TOKENsecret onnocabs(package:write on the container registry) and push tomain— the first image will build.
Tech
- SvelteKit +
@sveltejs/adapter-static - Tailwind CSS + daisyUI
- applesauce — Nostr client libraries
- Forgejo for source, CI (Forgejo Actions), npm + container registries