Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Iblai Api Studio Settings

BSecurity

Read and update an Open edX course's settings on Studio — schedule (start, end, enrollment dates), pacing, language, title/subtitle/description/short description/overview (about page), effort, intro video, course and banner images (asset upload), catalog fields that flow to the ibl.ai LMS app (subject, tags, level, topics, promotion, slug, agent), plus advanced settings such as advanced_modules — and the ordering rules (settings before content, pacing before the course starts, enrollment befo...

15 stars
0 votes
0 copies
0 views
Added 9/20/2026
developmentpythongobashnodeapi

Works with

api

Security Analysis

B88/100
criticalDownloads and executes remote scripts — classic supply chain attack

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add iblai/vibe --skill iblai-api-studio-settings --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Iblai Api Studio Settings?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Iblai Api Studio Settings
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/iblai-iblai-api-studio-settings/badge)](https://www.skillsdirectory.com/skills/iblai-iblai-api-studio-settings)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: iblai-api-studio-settings
description: Read and update an Open edX course's settings on Studio — schedule (start, end, enrollment dates), pacing, language, title/subtitle/description/short description/overview (about page), effort, intro video, course and banner images (asset upload), catalog fields that flow to the ibl.ai LMS app (subject, tags, level, topics, promotion, slug, agent), plus advanced settings such as advanced_modules — and the ordering rules (settings before content, pacing before the course starts, enrollment before start). Use when the user says course settings, schedule & details, dates, description, about page, course image, intro video, self-paced, catalog tags, advanced settings, or upload a file. Session auth via studio.env; run the auth preflight first.
metadata:
  kind: api
---

# iblai-api-studio-settings

Course settings on ibl.ai Studio live behind one JSON endpoint that merges the
Open edX "Schedule & Details" fields with the ibl.ai catalog fields the LMS app
shows. Read it, send back only the keys you change. Files (course image,
banner, any asset) go through the assets endpoint first; advanced settings
(`advanced_modules` and friends) have their own endpoint.

## Before you start

1. Preflight: `node .claude/skills/iblai-api-studio-auth/scripts/studio-login.mjs --check` prints two `ok`s; otherwise run **`/iblai-api-studio-auth`** first — do not attempt the calls below.
2. A course key from `/iblai-api-studio-course-create`.
3. **Do this before building content and before the first publish.** Three rules that Studio enforces silently:
   - **Pacing is locked once the course has started.** `self_paced` can only change while `start_date` is in the future; after that the endpoint returns `200` and echoes the old value. Decide pacing now. (Workaround for a started course: set `start_date` to a future date, flip `self_paced`, restore `start_date`.)
     **The lock is evaluated against the `start_date` in the request, not the stored one** — so sending `self_paced` and a past/today `start_date` in the *same* body silently keeps the old pacing, even on a fresh course still sitting at `2030-01-01`. Always send `self_paced` in its own call first, verify the echo, then set the real dates in a second call. (Verified live: `self_paced` + a *future* `start_date` in one body is accepted even on a started course, which is why the workaround above works in two calls; `self_paced` + a past `start_date` in one body applies the date and drops the pacing change.)
   - **Enrollment opens before the course starts:** `enrollment_start` must be earlier than `start_date` (and `enrollment_end`, if set, later than `enrollment_start`).
   - The `/iblai-api-studio-outline` builder publishes the whole course; set dates, description and images first so the catalog never shows a half-configured course.

## Auth & conventions

- **Base URL:** `$STUDIO_URL`; Studio session cookies from `studio.env` (its values are single-quoted — bash strips the quotes; any other parser must strip them too, or Studio answers 500: `/iblai-api-studio-auth`).
- **Snippet:**
  ```bash
  set -a; . ./studio.env; set +a
  S=(-s -b "studio_session_id=$STUDIO_SESSION; csrftoken=$STUDIO_CSRF" -H "X-CSRFToken: $STUDIO_CSRF" \
     -H "Origin: $STUDIO_URL" -H "Referer: $STUDIO_URL/" -H "Accept: application/json" -H "Content-Type: application/json")
  U=("${S[@]:0:11}")   # same headers without Content-Type, for multipart uploads
  ```
- `COURSE="course-v1:<org>+<number>+<run>"`; **URL-encode it in query strings** (`CE=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "$COURSE")`).
- Dates are ISO 8601 UTC (`2026-10-01T00:00:00Z`) or `null`.
- Settings changes take effect on the LMS immediately (no publish step); content still needs `/iblai-api-studio-publish`.
- Do **not** use the stock `/settings/details/{course}` for writes: partial bodies return `500`.
- **Silent no-ops:** the settings endpoint answers `200` with the stored object even when a field was refused (pacing after start, unknown keys). Always compare the response with what you sent.

## Reads

- **GET** `/api/ibl/v1/course_settings?course_key={CE}` → `{ "formData": { …59 keys… } }`:

  | Group | Keys |
  |---|---|
  | identity | `org`, `course_id` (number), `run`, `course_key`, `platform_key` (org key), `slug` |
  | schedule | `start_date`, `end_date`, `enrollment_start`, `enrollment_end`, `self_paced` (bool), `certificate_available_date`, `certificates_display_behavior` (`end` · `end_with_date` · `early_no_info`) |
  | about page | `title`, `subtitle`, `description`, `short_description`, `overview` (HTML), `about_sidebar_html`, `duration`, `effort` (e.g. `"3:00"` h:mm per week), `language` (`en`), `license`, `syllabus`, `learning_info` (list of strings), `instructor_info` (`{instructors: [{name, title, organization, image, bio}]}`), `pre_requisite_courses`, `entrance_exam_*` |
  | media | `intro_video` (YouTube video **id**, e.g. `dQw4w9WgXcQ`), `course_image_name` + `course_image_asset_path`, `banner_image_name` + `banner_image_asset_path`, `video_thumbnail_image_name` + `video_thumbnail_image_asset_path` |
  | ibl.ai catalog | `subject`, `tags` (list), `level`, `topics` (list), `promotion`, `audit_allowed`, `certificate_type`, `usage_limit`, `job_role`, `industry`, `custom`, `credential`, `social_team`, `social_channels`, `mentor_uuid` (agent attached to the course), `mentor_hidden`, `agent_content_mode`, `course_content_mode`, `agent_autoplay`, `agent_content_mode_audience`, `course_content_mode_audience`, `enable_agent_based_completion` |

- **GET** `/settings/advanced/{COURSE}` → `{ "<key>": { "value", "display_name", "help", "deprecated" }, … }` (about 68 keys: `advanced_modules`, `display_name`, `max_attempts`, `showanswer`, `rerandomize`, `days_early_for_beta`, `cert_html_view_enabled`, `mobile_available`, `invitation_only`, `catalog_visibility`, …).
- **GET** `/assets/{COURSE}/?page=0&page_size=50&sort=date_added&direction=desc&asset_type=Images|Documents|Audio|Code|Other&text_search=…` → `{ "assets": [ { "display_name", "content_type", "url", "portable_url", "external_url", "thumbnail", "id", "locked", "file_size", "date_added", "usage_locations" } ], "totalCount", "page", "pageSize", "start", "end" }`.
- **GET** `/api/ibl/manage/course/?course_key={CE}` → `{ course_key, org, number, run, display_name, url }` (display name only).

## Writes

- **POST** `/api/ibl/v1/course_settings` — merge-update; body = `course_key` + the keys to change (everything else is preserved). Response = the full updated settings object (top level, no `formData` wrapper).
  ```json
  { "course_key": "course-v1:acme+DATA101+2026-T1",
    "enrollment_start": "2026-09-15T00:00:00Z", "start_date": "2026-10-01T00:00:00Z", "end_date": "2026-12-15T00:00:00Z",
    "self_paced": false, "language": "en",
    "title": "Intro to Data", "subtitle": "Reading, measuring, deciding",
    "short_description": "A six-week introduction to working with data.",
    "overview": "<section class=\"about\"><h2>About This Course</h2><p>…</p></section>",
    "effort": "3:00", "intro_video": "dQw4w9WgXcQ",
    "subject": "Data", "tags": ["data", "statistics"], "level": "beginner" }
  ```
  The LMS reads the same object back (`GET $LMS_URL/api/ibl/v1/course_metadata?course_key=…`) and the ibl.ai catalog picks up the catalog keys — nothing else to sync.
  To clear a value send `null` (or `""` for the string fields Studio stores as text).
- **Course image / banner:** upload, then point the settings at the asset:
  1. **POST** `/assets/{COURSE}/` multipart `file=@cover.png` (use `"${U[@]}"`) → `{ "asset": { "display_name": "cover.png", "url": "/asset-v1:…+type@asset+block@cover.png", "portable_url": "/static/cover.png", "external_url": "https://<lms>/asset-v1:…", "id": "asset-v1:…", … }, "msg": "Upload completed" }`.
  2. **POST** `/api/ibl/v1/course_settings` `{ "course_key": "…", "course_image_name": "cover.png", "course_image_asset_path": "/asset-v1:…+type@asset+block@cover.png" }` (same pair for `banner_image_*` and `video_thumbnail_image_*`; use `asset.url` for the `_asset_path`).
  - Same filename re-uploaded replaces the file (URL unchanged). **DELETE** `/assets/{COURSE}/{asset_id}` → `204` removes one (confirm with the user first); **POST** `/assets/{COURSE}/{asset_id}` `{ "locked": true }` → `201 { "locked": true }` restricts it to enrolled users. (The v1 `course/asset/upload` route returns `500` — use this one.)
- **POST** `/settings/advanced/{COURSE}` — merge-update of advanced settings, `{ "<key>": { "value": … } }`; response = the full map. Example: `{ "advanced_modules": { "value": ["pdf"] } }` (read first and merge lists), `{ "invitation_only": { "value": true } }`, `{ "catalog_visibility": { "value": "about" } }`, `{ "days_early_for_beta": { "value": 7 } }`. A bad value returns `400` with `[ { "key", "message", "model": { "value" } } ]` and nothing is saved.

## Example

```bash
set -a; . ./studio.env; set +a
S=(-s -b "studio_session_id=$STUDIO_SESSION; csrftoken=$STUDIO_CSRF" -H "X-CSRFToken: $STUDIO_CSRF" \
   -H "Origin: $STUDIO_URL" -H "Referer: $STUDIO_URL/" -H "Accept: application/json" -H "Content-Type: application/json")
U=("${S[@]:0:11}")
COURSE="course-v1:acme+DATA101+2026-T1"; CE=$(python3 -c "import urllib.parse;print(urllib.parse.quote('$COURSE',safe=''))")

IMG=$(curl "${U[@]}" -X POST "$STUDIO_URL/assets/$COURSE/" -F "file=@cover.png" \
  | python3 -c 'import sys,json; a=json.load(sys.stdin)["asset"]; print(a["display_name"], a["url"])')
set -- $IMG
cat > settings.json <<EOF
{"course_key": "$COURSE", "enrollment_start": "2026-09-15T00:00:00Z", "start_date": "2026-10-01T00:00:00Z",
 "self_paced": false, "title": "Intro to Data", "short_description": "A six-week introduction to working with data.",
 "course_image_name": "$1", "course_image_asset_path": "$2", "subject": "Data", "tags": ["data", "statistics"]}
EOF
curl "${S[@]}" -X POST "$STUDIO_URL/api/ibl/v1/course_settings" -d @settings.json \
  | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d["start_date"], d["enrollment_start"], d["self_paced"], d["title"], d["subject"])'
# compare: every printed value must equal what settings.json sent
```

## Notes

- A new course has `start_date: 2030-01-01` — users see "coming soon" until you set a real start; `enrollment_start` after "now" blocks self-enrollment.
- `self_paced: true` makes due dates relative and hides the schedule; set it before building subsections with due dates, and before the start date passes (see above).
- `overview` is the about page HTML (`<section class="about">…</section>` blocks); keep the authoring rules of `/iblai-api-studio-html`.
- `intro_video` takes the YouTube id only; the LMS turns it into `http://www.youtube.com/watch?v=<id>` in `media.course_video`.
- Catalog keys (`subject`, `tags`, `level`, …) are what the LMS app filters on; `mentor_uuid` attaches an ibl.ai agent to the course (ids from `/iblai-api-agent-setting`).
- Verify what users see with `/iblai-api-studio-lms` (`course_metadata`, `courses/v1/courses/{key}`).

Attribution

iblaiiblai
View sourceMore from iblai →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →