Sifpress folds a PHP JSON API, a full React admin app, its styles and the SPA HTML
into one sifpress.php artifact — migrations
included. Drop it into any directory of any PHP host: no
.htaccess, no try_files,
no #/ hash routing, no Node.js on the server.
Migrationsmigrations/*.sql embedded, run on demand
SPA HTMLadmin UI shell + meta injection
JSReact 19 bundle, inlined
CSSTailwind build, inlined
?p=sifpress/api?p=sifpress/admin?p=sifpress/migrationone HTTP request per page load
1production file
0rewrite rules
1 reqper page load, JS+CSS inlined
8.3+PHP required to run
why sifpress
Everything ships inside the artifact
One build assembles the API, the app, the styles, the HTML and the schema into a
single PHP file that behaves identically at any install path.
Single-file artifact
php build.php type-checks, bundles the React app,
inlines every script and stylesheet, embeds the SQL migrations and writes one
artifact: dist/sifpress.php. Idempotent and
repeatable.
Rewrite-free routing
Routes are plain query parameters — ?p=sifpress/admin,
?p=sifpress/api&action=auth.login — that every
web server already understands. URLs stay real, shareable and crawler-friendly.
Just works anywhere
The same file works at /,
/myapp/ or four levels deep, with no rebuild and
no server config. Production never needs Node.js — only PHP.
SQLite + FTS5
WAL-mode database with a pending-migration detector, per-migration
BEGIN IMMEDIATE transactions and full-text search.
The schema lives in migrations/*.sql.
Admin with RBAC
DB-backed sessions with HttpOnly cookies, roles and permissions, page-level
grants, and a Milkdown WYSIWYG markdown editor in a TanStack Router admin UI.
Themes as bundles
Public-facing sifront SPAs are built into two-file .sifront
ZIPs, uploaded from the admin, stored in the DB and served through the artifact’s
own shell.
Self-updating
Point the app at a latest.json manifest and
upgrades become one click: download the release artifact, verify its md5, swap
it in.
CLI & backups
setup, migrate,
backup, config,
cron — WAL-safe VACUUM INTO
snapshots, tarred and pruned on a schedule.
routing model
The ?p= protocol
One query parameter does all of the dispatching. Nothing to configure on the
server, nothing lost to hash routing, back/forward works out of the box.
The protocol
p=sifpress/apiserver-side JSON API (action required)
p=sifpress/adminadmin SPA (React)
anything elsethe active sifront (viewer routes like ?p=/article/x)
No .htaccess, no #/
hash routing, no history-mode server rewrites — the SPA maps browser URLs back to
internal routes with TanStack Router’s rewrite layer and moves with
history.pushState.
/sifpress.php?p=sifpress/api&action=auth.loginJSON API
Because p is a real parameter, every link is
copyable, bookmarkable and indexable — no server ever has to be told how to
serve it.
how it works
One request, one fork
The browser asks for a single PHP file; the artifact decides between JSON and the
inlined SPA on its own.
Browserone request — JS + CSS inlined
↓
sifpress.phpone file in your document root
?p=sifpress/apiaction=…
↓
PHP JSON APIauth · pages · assets · migration
anything else?p=sifpress/admin · ?p=/…
↓
React SPAadmin UI or active sifront
The production server needs only one PHP file — no rewrite rules,
no separate assets, no Node.js.
front system
Meet the sifronts
The public face of a Sifpress site is a sifront — a self-contained React
theme built into a two-file .sifront archive,
stored in the database and served by the artifact itself. Swap it without touching
the PHP.
sifronts/<name>React theme · pnpm package
→
php buildfront.phpdev or release build
→
<name>.sifrontmeta.json + bundle.js
→
upload & activateadmin UI · CLI
→
?p=/…served by the artifact
Inside a .sifront
meta.jsonname, title, version + the theme contract
(require_keys)
bundle.jsthe whole app — styles injected, fonts inlined as data URIs
·exactly two entries — the admin unpacks the ZIP in the browser;
the backend stores bundle/meta/version and never opens a ZIP
sifpress1 — the default theme
·Home, /article/$slug and a 404 route (TanStack Router)
The theme's identity lives in namespaced KV keys — declared with defaults in
meta.json, overridden from Admin → KVs,
guest-readable for visitors.
sifpress1.sidebar.welcome
sifpress1.sidebar.about
sifpress1.sidebar.avatar
sifpress1.sidebar.pinned
sifpress1.sidebar.links
sifpress1.footer.text
sifpress1.background.kind
sifpress1.article.bottom
agent-assisted theming
Restyle it with skills
Deeper changes — layout, motion, a whole new look — are a coding task, and the repo
hands your AI agent the design rules as skills: knowledge files it loads
before touching the theme, so restyles stay faithful to the design system.
Bundled skills — .agents/skills/
apple-designfluid motion, springs, materials, reduced-motion rules
my-glass-webui-designglass-control / apple-panel / ambient-bg — why each rule exists
Pi and opencode both read .agents/skills/
automatically. Ask for the restyle, review the diff, build and upload.
restyle & ship
# restyle with live reload
cd siffronts/sifpress1 && pnpm dev
php buildfront.php # -> dist/sifpress1.sifront
php dist/index.php inject_sifront sifpress1 # dev: push into the DB# ship: admin UI -> Sifronts -> Update, or# php sifpress.php update_sifront dist/sifpress1.sifront --activate
quick start
From download to admin UI in four steps
Grab sifpress.php from the releases page, run two
CLI commands, sign in — the server only needs PHP. Building from source is for
local development (below).
01 Download & place
# grab the newest sifpress.php from the releases page
curl -LO https://github.com/liyu1981/sifpress/releases/latest/download/sifpress.php
mkdir -p /var/www/html
cp sifpress.php /var/www/html/
02 Create the config
# writes sifpress_config.php + creates ./var/sifpress (DB folder)
cd /var/www/html
php sifpress.php setup
# keep the DB elsewhere -- at creation, or adjust later:
php sifpress.php setup --db-dir=/srv/sifpress-db --force
php sifpress.php config --set SIFPRESS_DB_DIR=/srv/sifpress-db
03 Migrate
# applies the embedded migrations, seeds the first admin
cd /var/www/html
php sifpress.php migrate
04 Open the admin UI
# sign in at
https://example.com/sifpress.php?p=sifpress/admin
# first login: admin / admin -- password change is forced
local development
Building from source instead
Hacking on Sifpress itself needs Node.js, pnpm and the PHP CLI. The dev server
rebuilds on save, and a release build produces the same
sifpress.php the releases page ships.
clone · install · serve
git clone https://github.com/liyu1981/sifpress.git
cd sifpress
pnpm install
php build.php # dev artifact -> dist/index.php
./dev.sh # http://localhost:5000, rebuilds on change
php build.php release # release -> dist/sifpress.php