skills/pegasus-projects/SKILL.md
Use when the user asks to create, view, or modify a SaaS Pegasus project via the `pegasus` CLI — e.g. "create a new Pegasus project for X", "add subscriptions to my Pegasus project", "show me my project settings", "switch the front-end framework to React", "what features can I use on my license tier". This skill covers the `pegasus projects create / update / show / fields` commands and the underlying API shape.
npx skillsauth add saaspegasus/pegasus-skills pegasus-projectsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are managing a SaaS Pegasus project on behalf of the user. Pegasus is a Django boilerplate; a "project" is a configuration of features (frontend framework, auth providers, billing, AI, etc.) that the Pegasus build pipeline later renders into a real Django codebase. Your job is to translate the user's intent into the right CLI calls.
Authentication uses an API key from saaspegasus.com.
pegasus auth is already configured: a key lives at
~/.pegasus/credentials, or in $PEGASUS_API_KEY.pegasus auth themselves. Don't try to guess
or generate a key — they must paste their own.pegasus projects list # list all projects
pegasus projects fields --json # schema for a new project
pegasus projects fields --for <id> --json # schema for an existing project
pegasus projects show <id> --json # full config of one project
pegasus projects create --json [--set k=v ...] [--config-file path]
pegasus projects update <id> --json [--set k=v ...] [--config-file path]
pegasus projects push <id> # push to GitHub (separate flow)
ALWAYS pass --json when you (an agent) are inspecting output. The
default is a Rich table for humans that may truncate or scroll past your
visible viewport — a 60+ field schema looks like fields are missing when
they aren't. JSON output is always complete and parseable. Treat tables as
human-only.
For any non-trivial create or update, work in this order:
Get the schema. The endpoint is project-aware — call the variant that matches your task:
pegasus projects fields --jsonpegasus projects fields --for <id> --jsonThe schema omits fields the project's release/state can't configure. For
a new project on a modern release, expect fields like bundler,
css_framework, database, and python_package_manager to be absent
— there's only one valid choice and the server applies it. For an
existing legacy project (e.g. one still on bundler=webpack), those
fields reappear with both choices so you can see and change them.
Trust what the schema shows. If bundler isn't in the response,
don't try to set it.
Response shape:
{
"user_tier": "free" | "basic" | "pro" | "unlimited",
"fields": {
"project_name": { "type": "string", "max_length": 100 },
"use_celery": { "type": "boolean", "min_tier": "free" },
"use_subscriptions": { "type": "boolean", "min_tier": "pro" },
"ai_chat_mode": { "type": "choice", "choices": ["llm", "none"], "min_tier": "pro" },
...
}
}
min_tier only appears on fields gated by a license tier. Compute
"can I use this?" client-side: field.min_tier <= user_tier per the
ordering free < basic < pro < unlimited. No feature requires
unlimited today — treat unlimited as ≥ pro for the math.min_tier (project_name, project_slug, etc.) are
tier-agnostic.If the user asked for a tier-gated feature they can't use, surface that before attempting the call. Say something like: "Subscriptions requires a Pro license; you're on free tier. Want to skip it, or upgrade?"
Construct the payload. Two ways to provide settings, combinable:
--set key=value (repeatable) for individual fields. Booleans accept
true/false/yes/no/y/n. null/none/empty parse to None
on the client side, but most string fields reject null server-side
(you'll get field: This field may not be null.). Use null only on
fields explicitly documented as nullable — pegasus_version and
license are the main ones.--config-file path to load a YAML or JSON file. If the file has a
default_context: top-level key (real pegasus-config.yaml shape),
it's unwrapped automatically. --set values override file values.Call create or update. The response is the full project in
pegasus-config.yaml shape (see "The config shape" below).
On a 400, read the response body. Two shapes are possible:
{ "project_slug": ["Sorry, your project ID must be a valid Python module name..."] }
The CLI renders each as field: message.help_url (business / license errors, e.g.
a license tier that doesn't support a requested feature):
{
"error": "Subscriptions is not available on your current license...",
"help_url": "https://www.saaspegasus.com/billing/"
}
When help_url is present, always relay it to the user — it's
where they go to fix the underlying issue (upgrade their license,
set up a GitHub repo, etc.). The CLI prints it as a second line
prefixed More info: <url>.Either way, adjust and retry, or report to the user.
The API speaks the same key shape as a project's local pegasus-config.yaml,
with a few specifics:
"y"/"n" strings —
so an agent can paste yaml back without translating.project_name and project_slug. Everything
else uses model defaults. author_name, email, and license auto-populate
from the user's profile if omitted.project_slug must be a valid Python identifier, lowercase, no leading
or trailing underscore, and not a reserved name (apps, templates,
pegasus, stdlib module names, etc.). Server normalizes/validates.project_name ↔ model nameuse_auto_reload ↔ model use_browser_reloadpegasus_version is the pinned version (e.g. "2026.5" or
"2026.5.0.2") or null to track latest. The value must match an
actual released version — the server validates against its release
list and rejects guessed strings like "2026.5.0" with
Unknown Pegasus version. If the user just wants the latest, use
null; don't try to construct a version string. Output also includes
_pegasus_version (read-only, the resolved version that would be
used at build time).css_theme is a read-only output field derived from css_framework.license is a UUID string. Pass null for free tier. Must belong to
the requesting user.id_pegasus_version (resolved version)github_username (computed from the linked GitHub repo or user profile)css_theme (computed from css_framework)You can safely PATCH the entire GET response back — read-only keys are silently dropped.
The schema decides which choice fields you can touch. Don't try to be clever
about deprecated alternatives — if bundler isn't in the schema, the
question "vite or webpack?" doesn't exist for this context. Similarly,
don't ask the user "should we use tailwind or bootstrap?" when the schema
only lists tailwind.
For feature booleans the user hasn't mentioned, omit them from the
payload — the server applies the model default. Don't enumerate them when
proposing the call; it bloats the conversation. The booleans that default
on because they're recommended for typical SaaS apps: use_sentry,
use_health_checks, use_impersonation, use_async, use_celery,
use_translations, use_browser_reload, use_dark_mode, use_api_keys,
post_process (ruff). Only flip these to false if the user explicitly
asks.
For AI coding-tool rules (use_ai_rules_*), all default off. If the
user asks for "AI rules" / "agents" generically without naming a tool,
prefer use_ai_rules_claude=true (its UI label is "Claude Code
(Recommended)"). Only set use_ai_rules_agents, use_ai_rules_cursor, or
use_ai_rules_junie when the user names that specific tool.
The server enforces several couplings. Knowing them keeps you from proposing conflicting settings:
bundler=vite forces include_static_files=false.css_framework != tailwind forces use_flowbite=false and use_shadcn=false.use_subscriptions=false clears subscription_billing_model and
subscription_pricing_ui.use_teams=false clears use_teams_example.use_async=false clears use_async_example.docker_mode=full requires database=postgres (rejected otherwise).deploy_platform=kamal requires database=postgres.License tiers (low to high): free, basic, pro, unlimited.
The server validates feature compatibility at create/update time and again at build time. If a project has features its license can't support, the API rejects with a 400 keyed per offending feature.
You should pre-check via the schema's min_tier rather than discovering
through 400s. If the user wants something their tier can't do:
If the user has no license at all and the free tier flag is active for them,
their tier is free. Otherwise no license means they can't build at all
(the API will create projects but pegasus push will refuse).
"Create a project for me with X, Y, Z":
pegasus projects create --json --set project_name="..." --set project_slug=... [--set k=v ...]"Show me my project / what's in it":
pegasus projects show <id> --json and present relevant subset to user."Add feature X" / "switch to React" / etc:
pegasus projects show <id> --json to see current state.pegasus projects fields --for <id> --json to confirm the field is
configurable for this project's release/tier.pegasus projects update <id> --json --set key=value."Apply these settings from this yaml file":
pegasus projects update <id> --json --config-file path/to/pegasus-config.yaml.--set to override specific values."What can I configure?" / "What features are available?":
pegasus projects fields --json.pegasus projects fields --for <id> --json —
the response will reflect that project's release and current values.pegasus projects fields without --json is a Rich table that can be
truncated by terminal height. If you think the schema is "missing" a
field, you're almost certainly reading truncated output — re-run with
--json.my_app. You can't have two on one account.--set ai_chat_mode=none)."2026.5.0") or null. If
the user wants the latest, use null — don't try to discover the latest
version string yourself.pegasus projects push (creates a
GitHub PR with the rendered project). Build-time validation is stricter
than create-time validation; if it passes the API it might still fail at
build with a license/feature/release combo issue.Pegasus CLI commands print Rich tables by default. When you're acting as an agent for a human:
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
A CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.