A phased skill set that takes a non-developer from "I have an idea" to a live, self-hosted web app — built on free and open-source parts, deployed to their own server, and maintained afterwards without breaking it.
Written for the DeepSeek Harness skill format. Each phase is a separate skill file, so a session loads only the instructions it needs.
An AI agent can scaffold an app. What it usually cannot do is:
- finish — get from a scaffolded repo to a running production site with SSL, backups and alerts;
- stay free — every popular starter quietly defaults something to a paid vendor (Vercel, a managed database, an auth service), and the bill appears after the work is done;
- survive a context reset — weeks later, in a brand-new session with no memory of the conversation, it re-does finished work or contradicts decisions already made.
This pipeline is an attempt to fix all three, with the third treated as the hard one.
Phases are split by what they need loaded, not by ceremony:
| Phase | Needs | Doesn't need |
|---|---|---|
| 1 — requirements | GitHub data, user back-and-forth | SSH, Coolify, deployment |
| 2 — scaffolding | the boilerplate's file tree, phase 1's answers | deployment details |
| 2.5 — redesign (optional) | the scaffolded code, a design engine, vision | deployment details |
| 3 — deploy | SSH, Coolify, domain | which boilerplate, what it looks like |
| 4 — maintain | the status file only — often a fresh session | the original conversation |
5 — kaviar |
the session log and the lesson files | the project |
| Skill | What it does |
|---|---|
saas-pipeline (entry point) |
Routes only. Reads the status file and hands off to the right phase. |
foundation-research |
Pins requirements down and picks a starting point. Defaults to one deeply-supported boilerplate (nextjs/saas-starter) extended with a business-case pattern, rather than running a comparison every time. Branches only when the idea genuinely calls for it. |
scaffold-lego |
Clones the boilerplate, checks the dev environment is real, maps required features against the actual codebase, strips unused modules, and swaps any paid-by-default piece for a free one. |
redesign-visual (optional) |
Restyles the UI when it still looks like boilerplate. Runs a named design engine, then a deterministic gate, then a bounded screenshot + vision review. |
deploy-vps |
Puts it live on the user's own VPS with Coolify: domain, SSL, hardening, backups, uptime alerting. |
maintain-evolve |
Post-launch changes, from a fresh session with zero prior context — everything comes from the status file and the repo. |
kaviar |
The self-improvement loop. Reads the session's own log for failures, retries and pushback, and turns at most three of them into lasting lessons. Proposes edits to the pipeline; never silently applies them. |
install-harness-skill |
Installs a skill from a folder, archive, git URL, or another harness's plugin layout. Shipped because the pipeline's own tooling calls it. |
Every phase reads and writes PIPELINE_STATUS.md at the project root. It is the only thing that survives a context reset, a compaction, or a new session weeks later. Its schema and rules are in shared/references/status-file-schema.md, and it is machine-validated:
node skills/shared/scripts/note_lint.cjs --status PIPELINE_STATUS.mdThis is the design decision the rest of the pipeline is built around. An agent that trusts its memory will re-dispatch finished work — which is expensive and confusing — so the status file, a task ledger and git log are treated as authoritative over recollection.
The skills live under skills/, which is the skills root every phase's internal paths are
written against (shared/references/..., 00-orchestrator/SKILL.md). The repo root holds only
documentation and licence — deliberately, because a flat .md file sitting in a skills root is
rejected by the harness as a malformed skill.
Either clone straight into a skills root:
git clone https://github.com/takimdigital/saas-pipeline.git /tmp/saas-pipeline
cp -r /tmp/saas-pipeline/skills/. ~/.dsh/skills/…or let the bundled installer diff and sync it, which is the intended shape — each project keeps
its own copy under <project>/.dsh/skills, so a project cannot silently drift onto an old version:
node /tmp/saas-pipeline/skills/shared/scripts/install_pipeline.cjs --target /path/to/your/project # report only
node /tmp/saas-pipeline/skills/shared/scripts/install_pipeline.cjs --target /path/to/your/project --apply # syncinstall_pipeline.cjs diffs before it copies, backs up anything it overwrites, and never deletes.
It leaves other skills in the target root alone.
Verify the skills registered — this must report RESULT: OK:
node /tmp/saas-pipeline/skills/install-harness-skill/scripts/install-skill.cjs --check-only /tmp/saas-pipeline/skillsExpected: registered: 8 -> saas-pipeline, foundation-research, scaffold-lego, redesign-visual, deploy-vps, maintain-evolve, kaviar, install-harness-skill
- Node 22+ — every script is Node, no build step, no dependencies to install.
bashfor the three.shscripts (check_environment.sh,install_environment.sh,skills/02b-redesign/scripts/check_redesign_scope.sh).- Python 3 for one optional freshness check.
- Git, and Docker if you want the local-database path.
Deterministic scripts are preferred over letting the model re-derive the same answer every session. That is an explicit cost and focus decision, not an accident.
| Script | Purpose |
|---|---|
skills/shared/scripts/setup_harness.cjs --check |
Reports whether vision, screenshot paths and the scope hook are actually wired. Run before promising any visual verification. |
skills/shared/scripts/note_lint.cjs |
Validates note-form files and the status file. --tree <root> lints the whole package. |
skills/shared/scripts/cache_audit.cjs "<sessions dir>" |
Prints a workspace's real cache hit rate and bill from the harness's own logs. No API calls. |
skills/shared/scripts/install_pipeline.cjs |
Syncs this package into a project (see above). |
skills/shared/scripts/install_scope_hook.cjs |
Installs the PreToolUse hook that enforces redesign scope. |
skills/05-kaviar/scripts/session_retro.cjs |
Extracts failures, retries and pushback from a session log. |
skills/05-kaviar/scripts/lessons.cjs |
add / list / check / prune / promote / apply the lesson store. |
skills/02b-redesign/scripts/design_context.cjs |
Collects design tokens, routes and component inventory for a review. |
skills/02b-redesign/scripts/design_gate.cjs |
The deterministic design gate. |
skills/01-foundation-research/scripts/check_github_freshness.py |
Checks whether a boilerplate has moved on since it was last assessed. |
These are the rules that shaped the rest, all stated in skills/00-orchestrator/SKILL.md:
- Free only, except the VPS and the domain. No Vercel, no managed Postgres, no paid auth vendor, no paid email beyond a free tier — unless the user explicitly opts in. Surfacing and fixing a starter's paid defaults is part of phase 1/2, not a footnote.
- Assume the user is not a developer. Plain language before any technical ask; point at a setup guide for anything they have to go get themselves.
- The user provides access and purchases; the agent does the rest.
- Real git history, not a dump commit.
- Minimal footprint — wire up what was asked for and strip the rest.
- Features get verified, not assumed. "The app boots" is not the bar; every must-have feature is confirmed against a written blueprint.
- Nothing is claimed that was not measured. Prices, savings, "this is enforced" — each is either verified with a command or marked unknown. Several reference files have been wrong before and were corrected.
- The implementer never reviews its own work. Anything that matters gets a separate reviewer with fresh context.
- Post-launch changes go through a branch and a CI gate, never a direct push to
main— with Coolify, a direct commit is an immediate ungated production deploy. - Rulings, not stalls. A running plan does not stop for questions it can answer. Stop only for something irreversible, security-sensitive, or outside the repo.
skills/shared/LESSONS.md holds what this pipeline learned while being used — one line per lesson, each with a symptom, a fix, and a pointer to the session it came from. Repeats reinforce a hit count rather than duplicating the entry.
Promotion into a SKILL.md requires the user's explicit approval:
# capture a lesson (--key is optional; defaults to a slug of the symptom)
node skills/05-kaviar/scripts/lessons.cjs add --phase 2.5 --symptom "..." --fix "..." --evidence session-abc123
node skills/05-kaviar/scripts/lessons.cjs list
node skills/05-kaviar/scripts/lessons.cjs check
# promote one INTO a SKILL.md — the only write path, and it refuses without --approved
node skills/05-kaviar/scripts/lessons.cjs apply K-003 --skill 02b-redesign/SKILL.md --approvedLessons captured this way are the reason several of the non-negotiables exist — including the one about never writing a */ sequence inside a block comment, and the one about matching on normalised paths rather than raw OS paths.
Stated rather than hidden:
- No version number. There is no
versionfield, no tag and no changelog. The git history is the record. - The
.shscripts were not executed on Windows during packaging — there is nobashon the machine used to assemble this repo. They are syntax-plausible but not verified here. The Node scripts were all syntax-checked and the read-only ones were run. install_pipeline.cjs --presetexpects anagent-presets/saas-pipeline-onlydirectory sitting next to the skills root. It is not shipped here; without it the flag reportsnot found next to the packageand copies nothing. Everything else works.note_lint.cjs --treeexits 1 on this package by design: the reference files are prose-heavy relative to the house note style, and they point at paths (docs/design/…,docs/pipeline/…) that are generated inside a consumer project, not here. Warnings, not breakage.- It is built against a specific harness. The skill frontmatter, hook format and
~/.dshlayout are DeepSeek Harness conventions. Porting is possible —skills/install-harness-skill/references/porting-non-dsh-skills.mdcovers it — but this repo is not harness-neutral. - The lessons reference opaque session ids (
session-85ac7dfc) as evidence. They identify nothing private, but they will be meaningless outside the machine that produced them.
README.md LICENSE .gitattributes .gitignore docs + licence only
skills/ the skills root — everything below ships
00-orchestrator/ entry point, named `saas-pipeline` — routes only
01-foundation-research/ requirements + boilerplate choice
02-scaffold-lego/ build features on the clone
02b-redesign/ optional visual pass (+ scope hook, design gate)
03-deploy-vps/ Coolify, TLS, hardening, backups, alerting
04-maintain-evolve/ post-launch changes
05-kaviar/ retrospective, lesson store, promotion
install-harness-skill/ skill installer (called by the tooling above)
shared/ reference files + scripts used by every phase
references/ boilerplates, free-stack swaps, cost, git hygiene, …
scripts/ install, lint, audit, harness checks
LESSONS.md accumulated lessons
assets/ vision smoke-test fixture
Docs sit at the repo root rather than inside skills/ on purpose: a flat .md in a skills root
is a hard failure in the harness's own validator, so README.md there would break the install it
documents.
MIT. Use it, fork it, strip it for parts.