Install in 5 minutes
One command runs the whole stack with Docker, then 60 seconds to load the extension.
You need Docker (Desktop on macOS and Windows, Engine with the compose plugin on Linux) and Chrome, or another Chromium browser of version 142 or newer (Edge, Brave, Arc). Firefox is not supported yet.
1. Run one command
curl -fsSL https://raw.githubusercontent.com/FindMalek/skiffr/main/install.sh | shThe script makes a skiffr/ folder, downloads the compose file of the latest release (checked against that release's SHA256SUMS), generates every secret into skiffr/.env (permissions 600), pulls the images, starts everything, waits until it is healthy and prints (all later commands run inside that folder, so cd skiffr first):
dashboard http://localhost:3002
api http://localhost:3001 (the url to paste in the extension)
site http://localhost:3000
docs http://localhost:3003
sign in admin@skiffr.local
password <20 random characters> (shown once, it is also in skiffr/.env)The admin is created and reset to the .env values on every api start, so a password you change in the dashboard is reverted by the next restart or update. Change it in .env.
The download of the compose file is checked against the SHA256SUMS of the same release. That catches a truncated or corrupted download, not a compromised repository or release: the sums and the files come from the same place, and install.sh itself comes from the main branch. If that matters to you, read the script first (it is one file), and pin a release you have looked at with --version v0.1.0. Signed attestations of the release files are planned.
It asks nothing. Run it again at any time: .env and the data are never overwritten, only missing keys are added.
No curl, or you want the source? Clone and run the same thing:
git clone https://github.com/FindMalek/skiffr
cd skiffr
./scripts/setup.sh # pulls the released images
./scripts/setup.sh --build # builds them from this checkout instead (several minutes)A build from source has no extension zip at /downloads: build the extension yourself with pnpm install && pnpm --filter extension build and load apps/extension/.output/chrome-mv3.
Options
Pass them after sh -s -- when piping: curl ... | sh -s -- --port 4000.
| Option | What it does |
|---|---|
--port 4000 | site on 4000, api 4001, dashboard 4002, docs 4003 (default 3000 to 3003) |
--domain skiffr.example.com | serve on your own domain with automatic https, see below |
--version v0.1.0 | pin a release (default latest, which ./skiffr update follows) |
--email you@example.com | login of the first admin (default admin@skiffr.local) |
--autoupdate | also run the daily image updater, see deploy |
--no-start | write the files and stop |
--dir path | install folder (default ./skiffr) |
On localhost, why it works without a domain
Every app is published on 127.0.0.1 on its own port, and the dashboard proxies the sign-in to the api, so the session cookie is first-party on localhost. The extension calls the api directly at http://localhost:3001 with its token. Nothing is exposed to your network: the ports are bound to the loopback address, and the database has no published port at all. To reach it from another device use --domain, or set SKIFFR_BIND=0.0.0.0 and the public urls in .env yourself.
Your own domain
Point four DNS records at the server (skiffr.example.com, dashboard., api. and docs. under it), open ports 80 and 443, then:
curl -fsSL https://raw.githubusercontent.com/FindMalek/skiffr/main/install.sh | sh -s -- --domain skiffr.example.comA bundled Caddy gets the certificates from Let's Encrypt and proxies each name to its app. The extension then uses https://api.skiffr.example.com.
2. Load the extension (60 seconds)
Chrome does not install an extension from a file on its own, so this step is by hand. Your own server serves the extension that matches its version.
- Download
http://localhost:3001/downloads/skiffr-extension.zipand unzip it into a folder you will keep. Chrome does not install zips, it loads an unzipped folder. - Open
chrome://extensions(Edgeedge://extensions, Bravebrave://extensions, Arcarc://extensions) and turn on Developer mode at the top right. - Click Load unpacked and pick the unzipped folder.
- Pin the skiffr icon from the puzzle menu in the toolbar.
Do not delete the folder: Chrome reads the extension from it.
3. Connect it and apply
- Open the dashboard, sign in with the printed email and password and fill in your profile. A fill without a profile stops with a message.
- Open Extension in the dashboard and create a token. Copy it.
- Right-click the skiffr icon and choose Options (or
chrome://extensions, Details, Extension options). Set the api url to the one the installer printed, paste the token and press Test connection. - Open a job application form. A toast asks "Autofill this application?", press Yes.
Ctrl+Shift+F(Cmd+Shift+Fon macOS) fills the current page without the toast.
Review what was filled: fields the model is unsure about are outlined in amber. Skiffr never submits a form, never clicks submit, next or apply buttons and never touches password or hidden inputs, you press the button yourself. What it does on a page is in the extension.
First run checklist:
- the dashboard loads and you are signed in
- your profile is saved
- a token is created and Test connection says connected
- one real application form is filled and submitted by you
AI keys are optional. Without them the profile, saved answers, the queue and saved-answer fills all work. To let the model map fields your saved answers do not cover, put GROQ_API_KEY in skiffr/.env (get one) and run docker compose up -d again. OPENAI_API_KEY adds similar-question suggestions. See environment and privacy for what is sent.
Troubleshooting
| Problem | Fix |
|---|---|
Cannot connect to the Docker daemon | start Docker Desktop (Linux: sudo systemctl start docker), run the command again |
permission denied on the docker socket (Linux) | add yourself to the docker group (sudo usermod -aG docker $USER) and log in again. Do not run the installer with sudo: it would make the folder and .env root owned |
port 3000 is already in use | run again with --port 4000 |
pull access denied, or no release published yet | the images are on ghcr.io/findmalek/skiffr-<app>. Use the clone path with --build, or ask the maintainer to make the packages public |
the api log says password authentication failed for user "skiffr" | a data volume from an earlier install with another .env is still there (the database password is fixed when the volume is created). If that data is disposable: docker compose down -v, then start again |
| the installer stops with "did not become healthy" | read the log it prints, then docker compose logs. A wrong value in .env makes the api refuse to start and says which one |
| the extension cannot connect | the api url must be exactly the printed one, no trailing path. Open it plus /health in a browser, it must answer "ok":true. Run docker compose ps in the skiffr/ folder |
| the extension says the token is invalid or expired | create a new token in the dashboard, Extension, paste it again |
| cannot sign in | the password is ADMIN_PASSWORD in skiffr/.env. The admin is reset to the .env values on every api start, so change the password there |
| the extension is older than the server | download the zip again, replace the files in your folder and press reload on the skiffr card at chrome://extensions |
| you want to use it from another device on your network | the extension only accepts https api urls, or plain http for localhost, so a bare LAN address will not work for it. Use --domain (or your own tls proxy) and an https url. The dashboard alone also needs WEB_URL, DASHBOARD_URL and API_PUBLIC_URL in .env to be the address you type in the browser |
Update, back up, remove
Run these inside the skiffr/ folder, cd skiffr first (from a clone: ./scripts/skiffr).
| Command | What it does |
|---|---|
./skiffr update | backs up the database to ./backups first (stops if that fails, --no-backup skips it), then fetches the latest release's compose file (checksum checked) and images and restarts. The api migrates the database on start |
./skiffr update --version v0.1.0 | the same for one release: how to roll back |
./skiffr status | what runs, the running version, whether a newer release exists |
./skiffr logs api | follow the logs of a service |
./skiffr backup | database dump to ./backups/skiffr-<time>.sql.gz. Keep .env with it |
./skiffr version | the running version |
docker compose down | stop, data stays |
docker compose down -v | stop and delete all data, a full reset |
To remove skiffr completely: docker compose down -v, then delete the folder. Restoring a backup, automatic updates and the rules for rollbacks are in deploy. Releases, versions and the extension zip come from releasing. A Chrome Web Store listing, which would update the extension by itself, is tracked in issue 26 and is not available yet.