Twenty minutes from
git cloneto a running PMA with one service live and reachable in your browser. The minimum dev install — enough to feel what PMA is, before you commit to running the whole stack.
Level: 1 · Reading time: 20 min
docker compose version works).asd CLI installed: curl -fsSL https://asd.host/install.sh | bash. See /asd for what asd is and why PMA uses it.just installed: apt install just / brew install just / equivalent.bun installed: curl -fsSL https://bun.sh/install | bash.Already done this before? Skip to Level 2 — add a service where you'll write a manifest and watch the framework activate a new service.
We're going to clone the PMA repo, run one command, and end up with a working Redmine instance reachable at https://redmine-<your-id>.<tunnel-host>. No nginx config, no certbot, no per-service SSO setup, no manual database creation. The bootstrap script reads each package's manifest and does the work.
The trade-off: this is the minimal profile — only Redmine runs. To get the full enterprise stack (Mattermost, n8n, ERPNext, Wiki.js, Superset, Authentik, Grafana, …) you'll switch profiles in Level 3. Start small to feel the pattern first.
1. Clone the repo:
git clone https://github.com/asd-engineering/asd-pma.git
cd asd-pma
2. Bootstrap the minimal profile:
just bootstrap-local minimal
This takes 15-20 minutes the first time (Docker images get pulled, containers start in dependency order, Authentik initialises its database, Redmine runs its migrations, SSO is wired up, Caddy routes are generated, tunnels come up). You'll see phase-by-phase progress.
3. Get the URLs:
just tunnel-status
# Shows the live URLs for every running service
Or check .env:
grep -E '^(REDMINE_URL|AUTHENTIK_URL)=' .env
4. Log in:
Open REDMINE_URL in a browser. You should see Redmine. Click "Login" → you're redirected to Authentik → use the admin credentials from .env:
grep AUTHENTIK_ADMIN .env
# AUTHENTIK_ADMIN_USER=akadmin
# AUTHENTIK_ADMIN_PASSWORD=<generated>
After login you land back in Redmine, authenticated.
$ just status
[asd-dev-authentik] ✓ healthy
[asd-dev-authentik-postgres] ✓ healthy
[asd-dev-redmine] ✓ healthy
[asd-dev-redmine-postgres] ✓ healthy
[asd-dev-caddy] ✓ running
$ curl -sI ${REDMINE_URL} | head -2
HTTP/2 200
content-type: text/html;charset=utf-8
You have a working PMA. Two services running (Authentik + Redmine), one shared SSO, one public URL, automatic HTTPS.
To stop everything:
just down
To bring it back up later:
just up
Three things the bootstrap did under the hood:
Read every packages/<svc>/manifest.yaml. Found Redmine + Authentik in the minimal profile (defined in services.yaml). For each: read container config, DB type, SSO type, health endpoint, backup strategy. No framework code knows the word "redmine" — it's all manifest-driven.
Wired SSO automatically. Redmine's manifest declares sso.type: oauth. During bootstrap, the framework discovered this, called the generic OAuth-with-Authentik flow (scripts/sso/), registered the Redmine OAuth app in Authentik, configured Redmine's auth strategy. No manual provider-setup ceremony.
Generated Caddy routes + tunnels. Each service's packages/<svc>/net.manifest.yaml was read by asd net apply. The routes appeared in Caddy; the tunnels came up. The URLs got written back to .env for any service / script that needs them.
For the deeper "how the framework does this" view, see /pma/internals/bootstrap (planned) and /pma/internals/package-system (planned).
recovery/playbooks/*.yaml. Match the symptom to a playbook entry. Or run asd doctor for a system-wide health probe.