agentleFS
educlopezeduclopez/mallard/skills/gitlab-project-bootstrap/SKILL.md

gitlab-project-bootstrap

Skill4 starsChanged 13 days agoMITView on GitHub

Set up or audit GitLab project metadata hygiene (avatar, description, topics, badges, README) for Cinetic Digital's private client repos on gitlab.com. Use this whenever the user is starting a brand-new client project, asks to "configure" or "bootstrap" a GitLab project, wants project descriptions/tags/topics/badges set, mentions a project's README is missing/stock/hidden/needs improving, or asks what's missing / what should be set up on a GitLab repo. Also trigger when the user mentions a specific client project by name (e.g. a PrestaShop or Laravel repo) and asks about its GitLab page, its description, or wants it to "look proper." Works both for brand-new projects (apply everything from minute 1) and for auditing/fixing an existing one.

  • Reads credentials
  • Commits and pushes

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 3 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If you don't have the exact namespace/project path, search for it:

    line 28
  2. Very specific:

    If there are multiple near-matches (e.g.

    line 38
  3. Very specific:

    Has CI: add a real pipeline badge using GitLab's placeholder URL syntax (it resolves %{project_path}/%{default_branch} server-side, so it …

    line 95
  4. Distinctive:

    If found, git mv .README.md README.md and layer a short overview section on top — don't duplicate the existing content, it's usually solid …

    line 114
  5. Distinctive:

    If the reachable instance is down/in maintenance, say so in the README rather than silently omitting the screenshot — that's more honest …

    line 164
  6. Very specific:

    If the project has a real staging/production URL, use *that* in the README — never a *.lndo.site or localhost link.

    line 168
  7. Distinctive:

    Branch protection can be hollow: Check the default branch's protection AND the member list together:

    line 195

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GitLab project bootstrap (Cinetic Digital client repos)

Checklist + concrete commands for making a private client repo on gitlab.com (group nevengroup, formerly cineticd) look and behave properly from day one — description, topics, badges, README, and a couple of org-hygiene checks worth flagging. Built from real work across PrestaShop projects (ps9-gaudibarcelonashop, vives-8, milagros-colombia-b2b-v9.1) and a Laravel one (apply-animalmax).

Everything here is done via glab (GitLab CLI) — either glab api for project-metadata-only changes (no repo files, no PR needed), or a normal clone → branch → MR → merge flow when a repo file (README) needs to change.

Before you start: find the project and its SSH remote alias

If you don't have the exact namespace/project path, search for it:

glab api "projects?membership=true&per_page=100&search=<name>" | python3 -c "
import json,sys
for p in json.load(sys.stdin):
    print(p['path_with_namespace'], '|', p.get('description'))
"

If there are multiple near-matches (e.g. vives-8, vives-17-nuevo, ps17-vivescortadaimport), confirm the right one with the user rather than guessing — don't touch the wrong client's repo.

Check ~/.ssh/config for the SSH host alias used to reach gitlab.com — this org uses a Host gl-cinetic alias (not git@gitlab.com: directly) with its own IdentityFile. Cloning with the wrong host will fail with "Permission denied (publickey)" even though your GitLab account has access. Always clone as git@gl-cinetic:<path>.git, and run glab mr create/glab mr merge from inside the cloned repo (not with --repo <path> from elsewhere) — glab otherwise tries to add its own remote using the default host and fails the same way.

1. Avatar

GitLab defaults to a colored initial-letter avatar if none is set — looks unfinished on a client project page. This one's manual: Settings → General → avatar upload, a square logo image (≥128×128px). No API shortcut worth using here; just point the user at the setting if they haven't done it.

2. Description

One line, via API, no repo file touched:

enc=$(python3 -c "import urllib.parse; print(urllib.parse.quote('<namespace>/<project>', safe=''))")
glab api -X PUT "projects/$enc" --field "description=<one-liner>"

Name the stack, and for PrestaShop projects, the parent theme too (this is the detail that makes descriptions actually useful, not just decorative):

  • Gaudí & Barcelona Shop — PrestaShop 9.1.1 storefront (ElementFlow / stsitebuilder page builder)
  • Milagros Colombia — B2B PrestaShop 9.1 storefront, Panda child theme
  • Vives — PrestaShop 8 storefront, Panda child theme (viveschild)
  • Animalmax — job application portal (Laravel + Inertia + React)

How to find the real active theme — don't guess from folder names. A PS install usually ships several theme folders (classic/, panda/, hummingbird/, plus the client's custom one) but only one is active. Read the client's own theme's config/theme.yml for its parent: field to know what it's built on, then confirm it's the one actually in use — cross-check against CLAUDE.md if the repo has one, but don't trust it blindly: it can be stale. A quick sanity check that worked well: whichever theme directory has the most recent commit/mtime is almost always the one being actively developed, i.e. the active one.

cat themes/<client-theme>/config/theme.yml | grep parent
git log -1 --format=%ci -- themes/<theme-dir>   # per theme dir, compare dates

3. Topics (tags)

Also via API, same no-file-touched pattern:

glab api -X PUT "projects/$enc" --field "topics=prestashop,php,ecommerce"

Pick 3-5 real stack keywords, not generic filler. Examples that worked:

  • PrestaShop storefront: prestashop,php,ecommerce (+ b2b if it's a B2B store)
  • Laravel + Inertia + React app: laravel,php,react,typescript,inertia

4. Badges

Also API-only (POST projects/<id>/badges with name, link_url, image_url fields) — no PR needed.

First, check if the repo actually has CI (ls .gitlab-ci.yml in a clone, or glab api "projects/$enc/repository/files/.gitlab-ci.yml/raw?ref=<default_branch>"). This decides what kind of badge is honest to add:

  • No CI: static shields.io badges only — stack version, PHP version, theme. Nothing else to report, so don't add pipeline/coverage badges (they'd have nothing behind them).
    glab api -X POST "projects/$enc/badges" \
      --field "name=PrestaShop" \
      --field "link_url=https://www.prestashop-project.org/" \
      --field "image_url=https://img.shields.io/badge/PrestaShop-9.1.1-df0067?style=flat-square"
  • Has CI: add a real pipeline badge using GitLab's placeholder URL syntax (it resolves %{project_path}/%{default_branch} server-side, so it keeps working across renames/branch changes):
    glab api -X POST "projects/$enc/badges" \
      --field "name=Pipeline" \
      --field "link_url=https://gitlab.com/%{project_path}/-/commits/%{default_branch}" \
      --field "image_url=https://gitlab.com/%{project_path}/badges/%{default_branch}/pipeline.svg"
    Only add a Coverage badge if the CI config actually produces a coverage report. Read the .gitlab-ci.yml jobs first — a security-scan-only pipeline (e.g. just a Trivy dependency scan) has no coverage number, so a coverage badge would sit at "unknown" forever, which reads as broken/misleading rather than honest. When in doubt, skip it and say why.

5. README

The hidden-README gotcha

GitLab only renders a project's overview from a non-dotfile named README/README.md/etc. A repo can have perfectly good docs sitting in a dot-prefixed file like .README.md that silently never displays on the project page. Always check for this before writing a new README from scratch:

ls -la  # look for .README.md, .readme, etc. alongside (or instead of) README.md

If found, git mv .README.md README.md and layer a short overview section on top — don't duplicate the existing content, it's usually solid dev documentation, just invisible.

Structure that's worked well

Project Name
============

[![Stack](badge)](link)
[![Stack2](badge)](link)

One-line description of what this project is.

<p align="center">
  <img src="docs/screenshot-home.webp" alt="..." width="900"/>
</p>

Stack
-----

- **Bullet list**, bold the key technology names
- Anything architecturally notable (fork-tracking strategy, override system, custom modules, page-builder module, etc.)

Environments
------------

- **Production/Pre:** <real URL> (note explicitly if it's down/in maintenance rather than silently skipping)

Local setup / Theme build
--------------------------

Only include this section if there's a real local dev flow worth documenting (e.g. Lando + a CSS build pipeline). Don't invent one.

Conventions
-----------

Pointer to CLAUDE.md if the repo has one — don't duplicate its content here.

See references/readme-template.md for a copy-pasteable skeleton.

Screenshot rule

If there's a reachable instance (local dev, staging, or production — in that order of preference for a NEW project; for an EXISTING project with a real deployed URL, use that URL, not a local one, see below), take a homepage screenshot and compress it before committing — a raw PNG from a browser screenshot tool is typically 1-1.5MB, which is heavy for a repo. Convert to WebP:

cwebp -q 82 screenshot.png -o docs/screenshot-home.webp   # ~125KB from a 1.5MB PNG, negligible quality loss
rm screenshot.png

If the reachable instance is down/in maintenance, say so in the README rather than silently omitting the screenshot — that's more honest than pretending there's nothing to show.

Never link local dev URLs in a README that has a real environment

If the project has a real staging/production URL, use that in the README — never a *.lndo.site or localhost link. Local dev links are only appropriate when the project genuinely has no deployed environment yet (e.g. it hasn't shipped anywhere).

Respect existing ownership

If a specific team member actively relies on and edits a project's README (ask if unsure — "does anyone use this doc day to day?"), don't touch the file even if it looks improvable. In that case, still do steps 2-4 (description/topics/badges) since those are GitLab metadata, not the README file, and don't step on anyone's workflow.

6. Applying a README change (existing project, no local clone yet)

git clone git@gl-cinetic:<namespace>/<project>.git /path/to/scratch
cd /path/to/scratch
git checkout -b docs/readme-<whatever>
# edit README.md
git add README.md [docs/screenshot-home.webp]
git commit -m "docs: <conventional-commit-message-in-english>"   # no Co-Authored-By line
git push -u origin docs/readme-<whatever>
glab mr create --source-branch docs/readme-<whatever> --target-branch <default_branch> --title "..." --description "..."

Then decide on merge timing:

  • No CI, or the repo owner has said "no CI, merge directly": glab mr merge <id> --yes right away.
  • Has real CI: it's still fine to merge a docs-only change immediately (nothing it touches affects the pipeline), but ask first if unsure — don't assume every repo works like the no-CI ones.

7. Org-hygiene things worth flagging (don't auto-fix)

These involve people/access, not just files — check and report, then ask before changing anything:

  • Branch protection can be hollow. Check the default branch's protection AND the member list together:
    glab api "projects/$enc/protected_branches"
    glab api "projects/$enc/members/all" | python3 -c "
    import json,sys
    for m in json.load(sys.stdin): print(m['username'], m['access_level'])
    "
    Access levels: 10=Guest, 20=Reporter, 30=Developer, 40=Maintainer, 50=Owner. If a branch is "protected to Maintainers" but most/all members are ALSO Maintainer, the protection does nothing — anyone can push straight to the default branch or self-approve. Recommend most members sit at Developer, with only 1-2 people at Maintainer/Owner.
  • Required MR approval rules — often unset by default (anyone can merge their own MR with zero review).
  • CODEOWNERS for sensitive paths (payment modules, config/credentials-adjacent files, overrides).
  • Secret push protection — GitLab has a built-in toggle that blocks commits containing likely secrets before they land.

Report findings plainly (e.g. "14/14 members are Maintainer, branch protection is effectively decorative") and let the user decide the fix — this is their team's access model, not a call to make unilaterally.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.