Establishes a hard auth gate before any app is packaged: OIDC is
preferred, LDAP is acceptable (flagged risk), auth-proxy for user-less
utility apps, and local-only-auth apps are blocked from packaging
until they gain SSO.
- AGENTS.md: new "Authentication Policy" section with the verdict table
and Cloudron OIDC/LDAP/proxy-auth wiring notes.
- STATUS.md: new "Auth Status" matrix assessing all 7 completed
packages + the next candidates (draw.io proxy-eligible, Windmill
OIDC, NetBox OIDC but Redis-blocked, Gophish blocked-on-auth).
Flags tech debt: Webhook/WireViz need httpAuth proxy added; Puter
auth needs revisit.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
8.3 KiB
Agent Guidelines — TSYS Cloudron Packaging
Top-level files: README.md (project overview + app inventory),
STATUS.md (living status, agent-maintained),
JOURNAL.md (append-only ADR/pattern journal),
GitUrlList.txt (upstream repo list — source of truth for
the app set). Read STATUS.md first every session.
Active agent: Crush running GLM-5.2 (zai) for large tasks, Gemini for small. Permission mode:
yolo.
Repository Layout
README.md Project overview + full app inventory table
AGENTS.md THIS FILE — agent operating manual
STATUS.md Living status (agent-maintained, human read-only)
JOURNAL.md Append-only journal: per-package write-ups, patterns, ADRs
GitUrlList.txt Master list of upstream repos (source of truth, ~57 apps)
clone-repos.sh Automated upstream-repo cloning
Package-Templates/ Reusable Cloudron packaging templates
├── python-app/ (Dockerfile + CloudronManifest + start.sh templates)
├── django-app/ (Dockerfile + start.sh templates)
└── official-wrapper/ (Dockerfile template)
Package-Workspace/ One dir per app: <Category>/<app>/ (+ gitignored repo/)
├── API-Gateway/ webhook, apisix
├── Development/ puter, reviewboard
├── Documentation-Tools/ wireviz-web
├── Low-Code/ corteza
└── Monitoring/ healthchecks
Package-Workspace/**/repo/is gitignored — upstream source is cloned locally for reference but never committed. Only the package files (Dockerfile,CloudronManifest.json,start.sh,README.md, etc.) are tracked.- Each package =
Dockerfile+CloudronManifest.json+start.sh(if needed) +README.md+CHANGELOG.md+logo.png+.env.example(if config knobs exist). - No host build tooling required — packaging is
docker build(Cloudron base images handle runtimes). Keep the host clean.
Git Policy
- ALWAYS commit + push. Never wait. After each logical unit of work
(one package, one doc sync, one fix), immediately stage, commit
(conventional format), and push to
origin/main. Do not pause for review. This overrides any default "never commit unless asked" behavior. - Atomic commits. One coherent change per commit (e.g. a single package, or a single doc-correction pass — not both mixed).
- Conventional format:
feat: add <app> Cloudron package (<Category>),fix(scope): desc,docs: desc,refactor(scope): desc. Include a body for anything non-obvious. - Shell scripts are committed executable. Run
chmod +x start.shon the host before committing — Cloudron builds hit permission errors onRUN chmod, so make scripts executable at authoring time, not build time.
Automatic Gardening Protocol
Docs and code drift apart. After any work session, an agent MUST:
- Update
STATUS.md— reflect newly completed packages, changed counts, new issues, shifted priorities. This file is human read-only; agents own it. Update the "Last updated" header (date + agent). - Keep counts consistent across all docs. When a package completes, the
same total must appear in
STATUS.md,README.md("Current Progress"), andJOURNAL.md("Current Status"). A count in one place but not the others is a protocol violation. - Update the app inventory in
README.md— add the ✅ Packaged marker on the right row, and the app to the "Completed Packages" table. - Append to
JOURNAL.md— one section per package (pattern used, build process, challenges, files created, commit hash). Never delete or reorder existing entries. - Grep for stale paths after any rename/restructure —
grep -rn 'old/path' --include='*.md'and fix references in the same commit. - Self-audit before commit. For a new package, verify the package dir
appears in:
STATUS.md(Completed Packages table),README.md(inventory- completed table),
JOURNAL.md(new section).
- completed table),
- Treat
GitUrlList.txtas the source of truth for the app set. If the README inventory table disagrees, reconcile the README to the list, not the other way around.
Key Scripts
| Script | Purpose |
|---|---|
clone-repos.sh |
Clone all upstream repos into Package-Workspace/<Category>/<app>/repo/ |
Key Docs
| Doc | Purpose |
|---|---|
STATUS.md |
Current state, completed packages, known issues, next priorities |
JOURNAL.md |
Per-package write-ups, the 5 packaging patterns, challenges & solutions |
README.md |
Project overview + full app inventory + category breakdown |
GitUrlList.txt |
Master upstream repo list (source of truth) |
Package-Templates/ |
Reusable templates per packaging pattern |
Authentication Policy (MANDATORY)
Every app must have an auth story before packaging. Research it up front and record it in the Auth Status matrix.
| Auth type | Verdict | Action |
|---|---|---|
| OIDC client (native or plugin) | ✅ PREFERRED | Package; wire Cloudron OIDC provider env vars. |
| LDAP (native or plugin) | ⚠️ ACCEPTABLE w/ RISK | Package, but FLAG as "auth-risk: LDAP" in STATUS + README — must be fixed/validated before production. |
| Local-only (built-in user DB, no SSO) | ❌ UNACCEPTABLE | Do NOT package. Record in STATUS as blocked-on-auth. |
| No user concept (stateless/utility app) | ✅ via AUTH PROXY | Package with httpAuth: {"type":"proxy"} so Cloudron gates access at the proxy. Admin restricts who can reach it. |
OIDC env vars Cloudron exposes (when the app consumes the platform OIDC
provider): CLOUDRON_OIDC_ISSUER, CLOUDRON_OIDC_CLIENT_ID,
CLOUDRON_OIDC_CLIENT_SECRET, CLOUDRON_OIDC_TOKEN_SIGNATURE_ALGORITHM
(manifestVersion 2 / platform OIDC). LDAP addon env vars:
CLOUDRON_LDAP_*. See CloudronManifest.json addons (no extra addon needed
for proxy auth; use the httpAuth field).
Before writing a Dockerfile, determine which row applies and write the finding into STATUS.md's Auth Status table. Never silently ship a local-only- auth app.
Cloudron Packaging — Quick Reference
Pick a pattern (see JOURNAL.md for full templates and worked examples):
| Pattern | When | Examples |
|---|---|---|
| Official-image wrapper | App ships a usable Docker image | APISIX, Healthchecks, Review Board |
| Multi-stage build | App needs compiling | Webhook (Go), Puter (Node.js) |
| Python build | Python app with deps | WireViz Web |
| Django + PostgreSQL | Django web app | Healthchecks, Review Board |
| Pre-compiled binaries | Upstream ships release binaries | Corteza |
Standard package steps:
mkdir -p Package-Workspace/<Category>/<app>/and clone upstream intorepo/.- Write
Dockerfile+CloudronManifest.json(+start.shif runtime setup needed). docker buildto validate locally.- Write
README.md+CHANGELOG.md+logo.png(+.env.example). - Commit as
feat: add <app> Cloudron package (<Category>), push. - Run the gardening protocol above (update STATUS / README / JOURNAL).
Recurring gotchas (from JOURNAL.md):
chmodinRUNfails on Cloudron base → make scripts executable on the host.- Don't
apk/apt-getin base images that lack the package manager; use the image's built-in tooling or pick the right base. - Wait for DB/etcd addons in
start.shbefore running migrations. - Prefer
npm installovernpm ciwhen lockfiles don't match the build env. - Define every TCP port explicitly in
CloudronManifest.json.
Addons — Environment Variables
PostgreSQL: CLOUDRON_POSTGRESQL_{HOST,PORT,DATABASE,USERNAME,PASSWORD}.
etcd: CLOUDRON_ETCD_{HOST,PORT}. Localstorage mounts at /app/data.
Project Context
Packaging ~57 upstream FLOSS apps for Cloudron — TSYS Group's PaaS of choice.
This repo is the Cloudron half of the support stack; the
Docker-Compose local dev stack
is a sibling project. Solo operator, conventional-commit discipline, build
locally then push to origin/main on git.knownelement.com.