Skip to content

AfterQuery/polaris

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Polaris

An editable, JSON-backed docs engine. Pages are stored as plain JSON, rendered and edited live in a React (Vite) app, and written back through a small zero-dependency Node API. You vendor the engine into a project and run it against that project's own content — the engine ships the app and the system pages; your pages, backlog, uploads, and progress stay yours.

Quick start

polaris init            # scaffold a fresh instance into ./polaris/
polaris dev              # API server + Vite dev server, together

polaris dev finds the instance from where you're standing — run it from inside polaris/ or from the parent beside it (no cd needed).

init with no argument scaffolds into a new polaris/ folder beside you (pass an explicit path — polaris init my-docs — to choose another). If that folder isn't already inside a git repo, init git-inits it so the engine can be vendored as a submodule there.

init also runs npm install in the vendored engine's web/ for you, so the instance is runnable right away — no separate dependency step (pass --no-install to skip it). Then open the Vite URL dev prints (typically http://localhost:5173/).

polaris dev is instance-aware from your current directory: run it from inside an instance folder — or from the parent beside it, where it finds the one instance init scaffolded — and it starts THAT instance via the instance's own vendored (pinned) engine, even when polaris is a global command living in a different checkout. The same holds for migrate and status. (init is the exception: it targets a chosen dir, not the ambient instance.)

The polaris command is bin/polaris.mjs in this repo. To put it on your PATH:

make install     # symlinks bin/polaris.mjs into ~/.local/bin (tracks this checkout)

make uninstall removes the link; make install PREFIX=/usr/local installs elsewhere. Alternatively npm link this repo, or invoke it directly (node path/to/polaris/bin/polaris.mjs …).

The server itself has no dependencies; only the React app (web/) does, and init installs those. If you ever need to install them by hand (e.g. after --no-install), polaris dev refuses to start without them and tells you to run cd web && npm install.

The CLI

One entrypoint (bin/polaris.mjs) unifies what used to be several manual steps:

Command What it does
polaris init [dir] Scaffold a fresh instance: polaris.config.json, db/ content dirs, a seeded .polaris-version, and a starter home.json; vendor the engine at <dir>/engine; and npm install the app's deps so it's runnable right away. [dir] defaults to ./polaris; if it isn't already inside a git repo, init git-inits it so the engine can be vendored there. --name <name> sets the instance name (default: the dir's basename, or the current folder's when [dir] is omitted). --no-engine scaffolds content only; --no-install skips the dependency install. Refuses to clobber an existing instance.
polaris dev Start the API server and the Vite dev server together, with unified teardown (Ctrl-C or either process exiting tears both down). Resolves the instance from your current directory: run from inside an instance folder — or from its parent, where it finds the one instance beside you — and it starts THAT instance via its own vendored engine, even when invoked as a global polaris. Ambiguous parents (more than one instance) refuse and ask you to cd in. --port <n> sets the API port (default: 5501).
polaris migrate Apply any pending content migrations, then exit. Thin wrapper over server/scripts/migrate.mjs. Also cwd-resolved — hands off to the ambient instance's vendored engine.
polaris status Print a read-only report: instance name, engine vs. data schema version, the compatibility verdict (a behind state blocks the server), and whether a newer engine is available upstream. Also cwd-resolved.

Engine vs. content — the split

Polaris deliberately separates the code you pull from the content you write, so an engine update can never overwrite your docs.

  • Engine root — this repo: the app (web/), the write API and libs (server/), the versioned migrations/, and the engine-owned system pages (db/system/). When vendored as a submodule, this is the submodule prefix. You update it by pulling; you never hand-edit it in an instance.
  • Content root — your db/pages, db/backlog, db/uploads, db/progress, and the .polaris-version stamp. This is your content; an update never touches it.

polaris.config.json binds the two via its contentDir field. It lives at the instance root — an ancestor of the engine in the vendored layout — and the engine finds it by walking up from its own directory (see server/lib/instance-config.mjs). Content lives outside the engine's submodule prefix precisely so git submodule update / subtree pull can replace the engine wholesale without clobbering anything you wrote.

In a flat single-repo checkout (like this one during engine development) the config sits at the repo root and contentDir is ./db, so both roots collapse to the repo root — the same code path, no special case.

Vendoring

Polaris is vendored per instance as a nested submodule. Each instance lives in its own folder (e.g. one per team in a monorepo); the engine is mounted one level down, so the config and content sit inside the instance folder but outside the submodule:

monorepo/
└── team-a/
    └── polaris/                 ← instance folder (findInstanceRoot lands here)
        ├── engine/              ← submodule → the Polaris engine (bin, server, web, migrations, db/system)
        ├── db/                  ← THIS instance's content (committed to the monorepo)
        │   ├── pages/ backlog/ uploads/ progress/  + .polaris-version
        │   └── .polaris-update-cache.json      (gitignore this — regenerated per install)
        └── polaris.config.json  ← { name, contentDir: "./db" }

The submodule boundary at polaris/engine/ is what makes the split work: an engine update (git submodule update --remote) can replace engine/ wholesale without touching db/ or polaris.config.json, and the host monorepo can commit those (git won't track files inside a submodule dir). contentDir stays "./db" because it resolves relative to the config file's own location.

polaris init team-a/polaris scaffolds the instance and runs the submodule add for you:

git submodule add -b main <this-repo-url> team-a/polaris/engine

After the add, init runs npm install in team-a/polaris/engine/web so the instance is immediately runnable (pass --no-install to skip it). Pass --engine-url <url> to override the URL (default: the running engine's origin), or --no-engine to scaffold content only. When the target isn't inside a git repo, init git-inits it first so the submodule has a host repo to record the mapping in. If the add still fails (unknown URL, an add conflict), init writes the content and prints the exact command to run yourself — it never leaves you half-scaffolded.

Later, pull a newer engine and bring content forward:

git submodule update --remote team-a/polaris/engine
(cd team-a/polaris/engine && ../bin/polaris.mjs migrate)   # or via a linked `polaris`

Polaris nudges you when you're behind: a best-effort check compares your running commit against upstream main and, when you're behind, prints a one-line hint at startup and shows a dismissible in-app banner with the exact command to run. It's a soft courtesy — never blocks startup, degrades silently offline or from a non-git copy, and is throttled to one network check a day. Turn it off or customize the command it suggests via the updateCheck / updateCommand config fields below.

Config — polaris.config.json

Six fields (defaults from DEFAULT_CONFIG in server/lib/instance-config.mjs); polaris init writes only the first two and lets the rest default:

Field Default Purpose
name "Polaris" Sidebar wordmark / browser tab title.
contentDir "./db" Where this instance's content lives, relative to the config file.
updateCheck true Master on/off for the "newer engine upstream" nudge. false disables the fetch, the startup log, and the in-app banner entirely.
updateCommand "git submodule update --remote" The exact command the nudge tells you to run.
allowedHosts [] Extra Host headers the Vite dev server accepts (server.allowedHosts). Vite blocks unrecognized hosts (anti-DNS-rebinding); localhost is always allowed. Add names reached via a proxy/tunnel — e.g. ["box"] to hit an instance on a GCP dev box over its SOCKS alias. Keeps the engine unedited per-instance.
webPort 5173 Port for the Vite dev server (web/). Distinct from the API port (polaris dev --port, default 5501). Set it to run two co-located instances without a port collision (e.g. 5179) from config rather than an engine edit.

Layout

  • bin/ — the polaris CLI (polaris.mjs), the single entrypoint.
  • server/ — the zero-dependency Node write API (api-server.mjs) and its lib/ (page store, config seam, versioning, update check, …) plus agent-facing scripts under scripts/ (migrate, backlog, progress).
  • web/ — the React app (Vite, plain JS/JSX, no TypeScript). Its node_modules is the only dependency install in the project.
  • db/system/engine-owned system pages (the component catalog, the changelog, guidelines). They ship with the engine and update when you pull; they are served read-only alongside your pages but never merged into your content.
  • migrations/ — versioned content transforms for db/pages/**/*.json, applied by polaris migrate. See migrations/README.md for the contract migration authors follow.

Content directories (db/pages, db/backlog, db/uploads, db/progress) are per-instance and gitignored in the engine repo — each install generates its own.

Updating & migrations

Pulling a newer engine can bump the schema version the code understands. The version stamp on your content (.polaris-version) must match, or the server refuses to boot — a loud guard rather than silently serving mismatched data (see server/lib/engine-version.mjs):

  • Data behind the engine → pending migrations exist. Run polaris migrate to bring your content forward, then start the server.
  • Data ahead of the engine → you're running an older engine against already-migrated content (e.g. after a downgrade). Update the engine.

polaris status reports exactly where you stand before you start the server.

About

Polaris — a reusable, self-hosted docs engine (React/Vite + Node write-API), vendored per-repo via git subtree.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages