jspod docs

What jspod ships, where things live, and how to customize.

What jspod is

An opinionated thin wrapper around JavaScriptSolidServer (JSS) aimed at first-time users. Single-user personal pods, default me/me credentials, localhost-only, batteries included.

The wrapper handles: default flags, port hopping, browser auto-open, seeding a custom landing page and account dashboard, bundling Pilot as a self-hosted Solid app, and shipping a ~200-byte default data browser. JSS is the substrate — everything that's actually a pod, an IDP, an OIDC provider, comes from JSS.

File layout (pod-data/)

jspod creates pod-data/ in the current working directory on first start (or wherever you pass via --root). Everything the pod is, including identities and signing keys, lives under that single tree.

pod-data/             your pod root
├── index.html        welcome page — jspod overwrites every start
├── index.html.acl    public-read for the landing page (JSS-managed)
├── signin.html       jspod's sign-in app — overwritten every start
├── signin.html.acl   public-read
├── account.html      post-sign-in dashboard — overwritten every start
├── account.html.acl  public-read
├── docs.html         this page — overwritten every start
├── docs.html.acl     public-read
├── profile/
│   └── card.jsonld   your WebID profile (JSS-seeded)
├── public/           public-read container
│   ├── links.jsonld  starter list of Solid apps (jspod-seeded, skip-if-exists)
│   └── apps/pilot/   self-hosted Pilot (jspod-bundled, skip-if-exists)
├── private/          owner-only container
├── inbox/            LDN inbox
├── settings/         prefs + type indexes (JSS-seeded)
├── .acl              root container ACL — owner read/write, no public default
├── .idp/             JSS internal identity storage (see below)
└── .token-secret     JWT signing secret (auto-generated, mode 0600)
Overwrite warning. index.html, signin.html, account.html, and docs.html are owned by jspod and overwritten on every start. Edits won't survive a restart. To customize, fork jspod or run JSS directly instead. The public/links.jsonld and public/apps/pilot/ bundles are skip-if-exists, so user edits there do survive.

Where the IDP data lives

Everything identity-related is under pod-data/.idp/:

.idp/
├── accounts/
│   ├── <uuid>.json             account record — username, WebID, bcrypt(password)
│   ├── _email_index.json
│   ├── _username_index.json
│   └── _webid_index.json
└── keys/
    └── jwks.json                OIDC signing keys for issued tokens

The account record contains a bcrypt hash of the password — not the plaintext. The signing keys are sensitive (anyone with these can mint valid tokens against your pod). JSS manages file modes on these; jspod doesn't touch them.

Customize the landing page

The default landing page (pod-data/index.html) is owned by jspod. Edits to it are overwritten on the next start. To genuinely customize, the options are, in increasing order of effort:

Auth ladder

jspod ships you onto rung 1 (default me/me) and makes climbing visible. The dashboard at /account.html exposes a Change password form (rung 2). Passkey support (rung 3) is on the roadmap. See jspod#6 for the full ladder framing.

To set a custom initial password without going through the UI:

JSS_SINGLE_USER_PASSWORD='your-password' npx jspod

Backup & reset

Your entire pod — content, identity, signing keys — is one directory.

Backup

tar -czf my-pod.tar.gz pod-data/

Restore by extracting the tarball back into a pod-data directory and pointing npx jspod --root /path/to/pod-data at it.

Reset / "delete account"

JSS disables the /idp/account/delete endpoint in single-user mode (the account is the pod). To start completely fresh:

rm -rf pod-data
npx jspod

A new me/me account is seeded on next start.

Bundled Solid apps

jspod bundles Pilot at /public/apps/pilot/. It's served from your own pod, so same-origin sign-in works even on strict browsers (Brave with shields up).

The bundle is copied skip-if-exists, so you can pin a specific Pilot version by editing the files locally and they'll survive jspod upgrades. Delete pod-data/public/apps/pilot/ and restart to re-seed from the current jspod's bundled copy.

Git remote (your pod is a git server)

jspod enables JSS's git HTTP backend by default. Any pod path you have ACL Read on is git-cloneable; any path you have ACL Write on is git-pushable. Fresh paths auto-initialize on first push (JSS 0.0.195+).

Clone a public path

git clone http://localhost:5444/public/apps/pilot ./pilot

Push to a new path (auto-creates the bare repo)

git clone https://github.com/solid-apps/penny.git
cd penny
git remote add pod http://localhost:5444/public/apps/penny
git push pod main

Note: git push against a Solid pod needs the same DPoP-bound auth as any other Solid write. Easiest workaround today is to set an Authorization header via git -c http.extraHeader=... with a token obtained from /signin.html. Cleaner ergonomics are a known gap.

To opt out: npx jspod --no-git.