Loading...
Loading...
This skill should be used when the user asks to "create a post", "edit a post", "update post content", "list posts", "convert markdown to Lexical", "write article to Payload", or mentions Payload CMS content management. Handles both production and local Payload sites via REST API with authentication.
npx skill4agent add b-open-io/prompts payload# Production site (ask user or check project config)
curl -s "https://your-site.com/api/posts?limit=1" | head -c 100
# Local development
curl -s "http://localhost:3000/api/posts?limit=1" 2>/dev/null | head -c 100
curl -s "http://localhost:3010/api/posts?limit=1" 2>/dev/null | head -c 100# Login to get auth token
curl -X POST "https://your-site.com/api/users/login" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "..."}' \
-c cookies.txt
# Use the cookie file for authenticated requests
curl -X POST "https://your-site.com/api/posts" \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{"title": "...", "content": {...}}'/adminpayload-token# Create a post
curl -X POST "https://your-site.com/api/posts" \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{
"title": "Post Title",
"slug": "post-slug",
"content": { "root": { ... } },
"_status": "published"
}'
# Update a post
curl -X PATCH "https://your-site.com/api/posts/POST_ID" \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{"content": { "root": { ... } }}'# Check the post was created
curl -s "https://your-site.com/api/posts?where[slug][equals]=post-slug" | jq '.docs[0]'{
"root": {
"type": "root",
"format": "",
"indent": 0,
"version": 1,
"direction": "ltr",
"children": [
{
"type": "paragraph",
"format": "",
"indent": 0,
"version": 1,
"direction": "ltr",
"children": [
{"type": "text", "text": "Content here", "mode": "normal", "format": 0, "detail": 0, "version": 1, "style": ""}
]
}
]
}
}| Markdown | Lexical Node |
|---|---|
| Paragraphs | |
| |
| text with format: 1 |
| text with format: 2 |
| text with format: 16 |
| Code blocks | |
| Lists | |
| |
| Value | Format |
|---|---|
| 0 | Normal |
| 1 | Bold |
| 2 | Italic |
| 3 | Bold + Italic |
| 16 | Code |
python3 ${SKILL_DIR}/scripts/md_to_lexical.py article.md > /tmp/content.json| Collection | Slug | Purpose |
|---|---|---|
| Posts | | Blog posts |
| Pages | | Static pages |
| Media | | Uploaded files |
| Users | | User accounts |
// scripts/create-post.ts
import { getPayload } from 'payload'
import config from '../src/payload.config'
const payload = await getPayload({ config })
await payload.create({
collection: 'posts',
data: { title: '...', content: {...}, _status: 'published' }
})
process.exit(0)source .env.local && bunx tsx scripts/create-post.ts# Check migration status
bun run payload migrate:status
# Run pending migrations
bun run payload migrate
# Create a new migration
bun run payload migrate:create migration-name
# Rollback last migration
bun run payload migrate:down
# Rollback and re-run all migrations
bun run payload migrate:refresh
# Reset all migrations (rollback everything)
bun run payload migrate:reset
# Fresh start - drop all tables and re-run migrations
bun run payload migrate:fresh# Generate TypeScript types from collections
bun run payload generate:types
# Generate import map
bun run payload generate:importmap
# Generate Drizzle database schema
bun run payload generate:db-schema# Show Payload project info
bun run payload info
# Run a custom script with Payload initialized
bun run payload run scripts/my-script.ts# Run queued jobs
bun run payload jobs:run
# Run jobs with options
bun run payload jobs:run --limit 10 --queue default
# Handle scheduled jobs
bun run payload jobs:handle-schedulesFORCE ROW LEVEL SECURITY// src/migrations/YYYYMMDDHHMMSS_enable_rls.ts
import { type MigrateUpArgs, type MigrateDownArgs, sql } from "@payloadcms/db-postgres";
export async function up({ db }: MigrateUpArgs): Promise<void> {
// Helper function to check admin status
await db.execute(sql`
CREATE OR REPLACE FUNCTION is_admin()
RETURNS BOOLEAN
LANGUAGE SQL
STABLE
SECURITY DEFINER
AS $$
SELECT COALESCE(
CURRENT_SETTING('app.current_user_role', TRUE) = 'admin',
FALSE
);
$$;
`);
// Enable RLS on sensitive tables
await db.execute(sql`
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE users FORCE ROW LEVEL SECURITY;
-- Users can only access their own data
CREATE POLICY users_select_policy ON users
FOR SELECT USING (id = (SELECT get_current_user_id()) OR (SELECT is_admin()));
CREATE POLICY users_update_policy ON users
FOR UPDATE USING (id = (SELECT get_current_user_id()) OR (SELECT is_admin()));
`);
}
export async function down({ db }: MigrateDownArgs): Promise<void> {
await db.execute(sql`DROP FUNCTION IF EXISTS is_admin();`);
await db.execute(sql`ALTER TABLE users DISABLE ROW LEVEL SECURITY;`);
}usersapi_keysdepositsusage_logsuser_id(SELECT function())SECURITY DEFINERpush: truebun run payload migrate:create feature-name# In CI/CD pipeline
bun run payload migrate && bun run build# Mark existing migrations as already run
psql "$DATABASE_URL" -c "
INSERT INTO payload_migrations (name, batch, created_at, updated_at)
SELECT * FROM (VALUES
('20250101_000000_migration_name', 1, NOW(), NOW())
) AS v(name, batch, created_at, updated_at)
WHERE NOT EXISTS (
SELECT 1 FROM payload_migrations WHERE name = v.name
);
"# Check for outdated packages
bun outdated
# Update specific packages
bun update package-name
# Update all packages
bun updatebun run generate:typesDATABASE_URIPOSTGRES_URL_NON_POOLING# Use POSTGRES_URL_NON_POOLING for migrations
DATABASE_URL=$(grep POSTGRES_URL_NON_POOLING .env.local | cut -d'"' -f2)bun run generate:typesreferences/lexical-format.mdreferences/rest-api.mdreferences/database-security.mdscripts/md_to_lexical.pyscripts/create-post.ts