CourseForgeDocs v5.3.0

Administer

Settings

Every setting an administrator can change, what it does and its default - generated from the one declaration the Settings screen, the API and the MCP tools all read.

Administration โ€บ Settings holds everything the installation can be told to do differently, one card per group. There are 60 settings in 8 groups. Each field carries its own description, its range and whether this installation has changed it.

Settings: the scheduler card
Settings, one card per group. The scheduler card writes the cron line out for you.

How settings are stored#

text
config/defaults.json   ships with the release: settings, the security policy, the content
                       details and the whole prompt library. Replaced by every update.
                       Never written to.
data/config.json       what this installation changed, and only that. Written from the
                       admin screens. No update touches it.

Splitting them is what makes an update safe: a new release brings new defaults and new prompt slots, and your decisions live in a file the update may not write. It also makes Reset a delete rather than a copy - setting a value back to the shipped default removes it from data/config.json, which stays a short, readable list of what this installation actually decided.

Every setting is declared once in the code (Support\Settings). The Settings screen draws a field from that declaration, the API validates against it, and the MCP tools describe and change settings from it - so a setting added in a release appears in all three at once. The reference below is generated from the same declaration.

The ones with consequences#

app.cron_token - the secret in the URL your host calls once a minute. Without one, cron.php answers 404 to everybody and CourseForge offers no background runs at all. At least sixteen characters; the screen generates one and hands you the finished URL. Rotating it invalidates the old URL immediately. See The scheduler.

app.cron_workers - how many scheduler ticks may work side by side, which is where parallelism in background generation comes from. Raise it only as far as your provider's rate limits allow; too high gives a run full of 429 errors, not a faster course.

The timeouts - app.ai_timeout_seconds defaults to 1800, because a long page on a reasoning model takes minutes; below about 600 you will lose work the provider was about to deliver. Your web server has its own limit too, and the smallest one wins.

updates.auto_install - off by default. On, the installation replaces its own files unattended at the configured hour. It backs up first and rolls back if the new version fails to start, but it is still an unattended change to a production system. See Updates.

mcp.allowed_origins - empty by default, which refuses every browser-based MCP client and affects nothing else. Add an exact origin only when you have such a client.

app.debug - puts exception details and stack traces into API responses and MCP errors. Leave it off on anything reachable from the internet.

app.task_max_attempts - how often a publish that ran into trouble is resumed before it is given up (twenty by default). Each attempt waits longer, up to a quarter of an hour.

Two settings hold secrets - app.cron_token and updates.github_token. Neither is ever sent to a browser: the screen is told whether one is stored, not what it is, and saving an empty box leaves the stored value alone. Neither can be stored until Security has passed.

Diagnostics and Set up PHP#

The Settings screen also carries Diagnostics - the same rows php tools/diagnose.php prints: PHP version and extensions, writable directories, the database, the scheduler's last tick, open invites - and Set up PHP, which raises PHP limits that are too low through .user.ini (Installation).

Over MCP#

list_settings, set_settings and reset_setting in the admin group reach every setting by its key, with the same validation as the screen. generate_cron_token rotates the cron token; get_cron_url reads the URL.

Every setting#

General#

What this installation is called and how it behaves by default.

Setting Default What it does
Installation name
app.name
"CourseForge" Shown in the header and in the browser tab. Useful when you run more than one.
Default course language
app.default_language
"English" What a new profile starts with. Every course can still choose its own. Fuzzy search, or type any language at all.
Pages at a time, in the browser
app.default_concurrency
2 How many pages the in-tab generator writes in parallel. Background runs use the cron worker count instead. Range 1-16.
Public address
app.public_url
empty The address this installation is reached at. CourseForge works it out from the request, so leave it empty unless it guesses wrong - behind a reverse proxy, for instance. It is what the cron URL is built from; the MCP connection line has its own setting below.
Correct punctuation after the AI
app.typography
true Sets the quotation marks, apostrophes, ellipses, dashes and spacing of a generated page the way the course language does, before it is stored - German gets โ€ž and โ€œ where the model wrote " and ", French gets its guillemets and its narrow spaces, an ellipsis becomes one character and a hyphen between two words becomes a dash. Code, links, formulas and the markers CourseForge writes are never touched. This is what a new profile starts from, and each profile can decide for itself. It says nothing about a course that is already written: Course > Settings > Punctuation corrects one of those whatever this is set to.
Debug mode
app.debug
false Puts exception details into API responses. Leave this off on anything reachable from the internet.
Searches for a course briefing
app.research_default_searches
8 How many searches to ask for when researching a whole course and the course itself names no number. This is the one-off briefing that get_research_brief asks for, not the per-page budget under Content details. Range 0-50 max.
Description length BookStack accepts
app.bookstack_description_max
2000 BookStack validates description_html at 2000 characters and refuses anything longer, so a description past that is shortened for the cover page - never in CourseForge, where it stays whole and is what the pages are written from. Raise it only if your BookStack raised it too; 0 turns the shortening off entirely. Range 0-100000 characters.

Course defaults#

What a generated page is made of before any course has decided otherwise. This is the bottom of the chain the Details tab shows: course, then chapter, then page, each overriding the one above.

Setting Default What it does
Learning objectives
details.features.objectives.default
false Opens the page with a short list of what the reader will be able to do afterwards. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Summary section
details.features.summary.default
true Closes the page with a compact recap of the key points. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Practice exercises
details.features.exercises.default
true Adds hands-on tasks with worked solutions. Uses the "Exercises per page" value. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Key terms glossary
details.features.key_terms.default
false Adds a short glossary of the terms introduced on this page. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Further reading
details.features.further_reading.default
false Points to official documentation, standards or classic references. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Code examples
details.features.code_examples.default
true Allows fenced, runnable code samples with language identifiers. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Comparison tables
details.features.tables.default
true Allows Markdown tables for comparisons, options and overviews. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Note / Tip / Warning callouts
details.features.callouts.default
true Allows blockquote callouts for the remarks that really matter. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Mermaid diagrams
details.features.mermaid.default
true Allows ```mermaid blocks for flows, states, hierarchies and timelines. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
MathJax formulas
details.features.mathjax.default
true Allows LaTeX formulas using the delimiters BookStack renders. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Emojis
details.features.emojis.default
true Allows a handful of emojis in headings, callouts and do/don't markers. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Anki cloze cards
details.features.anki.default
false Appends an importable cloze-deletion card set. Uses the "Anki cards" value. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Auto links
details.features.auto_links.default
false Lets the AI drop (๐Ÿ”— Title) cross references, which CourseForge turns into real BookStack links after publishing. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Web research
details.features.web_research.default
false Look up the current state of the topic before writing - latest versions, current documentation, recent releases - and cite what was found. Costs money on most providers, and a client connected over MCP does its own searching instead. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Minimum length
details.params.min_length.default
3000 Lower bound for the body of a page. 0 leaves it to the model. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-100000 words.
Maximum length
details.params.max_length.default
15000 Upper bound for the body of a page. 0 leaves it to the model. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-100000 words.
Diagrams per page
details.params.diagram_max.default
2 Upper bound for Mermaid diagrams. Only used when diagrams are enabled. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-20 max.
Exercises per page
details.params.exercise_count.default
3 How many practice tasks a page gets. Only used when exercises are enabled. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-50 tasks.
Anki cards per page
details.params.anki_cards.default
5 How many cloze cards a page gets. Only used when Anki cards are enabled. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-100 cards.
Auto links per page
details.params.link_count.default
5 Roughly how many cross references a page gets. Only used when auto links are enabled. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-50 links.
Audience
details.params.audience.default
empty Who the text is written for. Empty means the model derives it from the course topic. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not.
Searches per page
details.params.research_max_searches.default
0 Upper bound on web searches while writing one page. 0 lets the model decide how much to look up. Only used where web research is switched on. Every course starts from this and any course, chapter or page can override it; changing it here moves everything that has not. Range 0-20 max.

Scheduler#

The cron endpoint that keeps writing courses after the browser is closed.

Setting Default What it does
Cron token
app.cron_token
empty The secret in the URL your host calls once a minute. Without one, cron.php answers 404 to everybody and background runs are not offered at all.
Seconds of work per tick
app.cron_seconds
50 A tick stops handing out new pages after this long, so it finishes before your host cuts the request off. Keep it under the PHP time limit. Range 5-3000 seconds.
Parallel workers
app.cron_workers
2 How many ticks may work side by side. Two writes roughly two pages a minute. Raise it only as far as your provider rate limits allow. Range 1-16.
Attempts per page
app.cron_max_attempts
3 How often a page that fails is handed back to a later tick before it is given up on. Range 1-10.
Worker lease
app.cron_item_timeout_seconds
1800 How long a page stays claimed by a worker that has stopped answering, before another one may take it. Range 60-7200 seconds.
Attempts per publish
app.task_max_attempts
20 How often a publish or a link pass that ran into trouble - a wiki that stopped answering, a host time limit - is picked up again from where it stopped before it is given up on. Each attempt waits a little longer than the last, up to a quarter of an hour, and a task that was given up on can still be retried by hand. Range 1-200.

Batch and runs#

How queued generation is polled and how long its records are kept.

Setting Default What it does
Minimum time between polls
app.batch_poll_seconds
60 How rarely CourseForge asks a provider whether a queued batch has finished. Batches take hours; polling every minute wastes rate limit for nothing. Range 10-3600 seconds.
Keep finished runs for
app.batch_keep_days
30 Finished run records are removed after this long. The pages they wrote are never touched. Range 1-3650 days.
Default output ceiling
app.anthropic_max_tokens
32000 Used where a provider demands an explicit ceiling and the profile does not set one. Too low truncates a long page mid-sentence: a page at the shipped maximum length of 15,000 words is well over 20,000 tokens, which is why this ships at 32,000. A model whose own ceiling is lower is held to that ceiling, never to this number. Range 1000-200000 tokens.

Updates#

Checking GitHub for a new version, and installing it.

Setting Default What it does
Updates enabled
updates.enabled
true Off means CourseForge never contacts GitHub and never replaces its own files.
GitHub repository
updates.repository
"ZcarecroW/CourseForge" Where releases are published, as owner/name. Change it only if you run your own fork.
Channel
updates.channel
"stable" Stable takes published releases only. Pre-release also takes betas and release candidates. One of stable, prerelease.
Check for updates automatically
updates.auto_check
true Once a day, from the scheduler, so this screen is current when you open it. Needs cron. Automatic installation asks GitHub on its own and does not depend on this.
Install them automatically
updates.auto_install
false Unattended updates at the time below, from the scheduler. Needs cron. A backup is taken first and restored if the new version fails to start.
Time of day
updates.auto_time
"05:00" Local server time. Pick an hour when nobody is generating anything.
Time zone for that clock
updates.timezone
empty An IANA name such as Europe/Berlin - fuzzy search the list, or type one. CourseForge itself works in UTC; this is only for reading the hour above. Leave it empty and the server's own time zone is used, which is almost always the one you meant.
Keep backups of
updates.keep_backups
2 How many replaced versions stay on disk so an update can be rolled back. Range 0-10 versions.
GitHub token
updates.github_token
empty Only needed for a private fork, or to lift the 60-requests-an-hour limit GitHub applies per IP address to anonymous callers.

MCP#

The endpoint Claude and other MCP clients connect to.

Setting Default What it does
MCP endpoint enabled
mcp.enabled
true The second front door, for Claude Code and other MCP clients. Turning it off refuses every token at once.
Public URL
mcp.public_url
empty The address an MCP client should use, if CourseForge cannot work it out for itself - behind a proxy, for instance.
Allowed browser origins
mcp.allowed_origins
[] Origins a browser-based MCP client may connect from. Command-line clients send no Origin and are unaffected. Leave empty to refuse all of them.

Security#

Sign-in throttling and session lifetime.

Setting Default What it does
Failed sign-ins before an account is locked
security.max_login_attempts
5 Counted for one account, wherever the attempts came from. This is what stands between a password and somebody working through a list of guesses at it. Range 1-100.
Failed sign-ins before an address is locked
security.max_address_attempts
20 Counted for one address, against any account, and deliberately looser than the figure above: an address is shared - an office, a mobile network, a VPN - and a cap of five there would let one person mistyping their password lock out everybody behind it. Raise it for a busy shared address; lower it towards the per-account figure for an installation only you reach. It is never used below that figure, because an address that locked first would put the door shut before the per-account count could ever fill. Range 1-1000.
Counting window
security.attempt_window_minutes
15 Failures older than this stop counting towards a lockout. Range 1-1440 minutes.
Lockout length
security.lockout_minutes
15 undefined Range 1-1440 minutes.
Sign out after inactivity
security.session_lifetime_minutes
480 undefined Range 5-43200 minutes.

Timeouts#

How long CourseForge waits for somebody else.

Setting Default What it does
AI request timeout
app.ai_timeout_seconds
1800 A long page on a reasoning model can genuinely take minutes. Below about 600 you will start losing work. Range 30-7200 seconds.
Model list timeout
app.ai_models_timeout_seconds
240 For the call that asks a provider which models the account can use. Range 10-1200 seconds.
Connection timeout
app.connect_timeout_seconds
60 How long to wait for a provider to answer at all, before any content arrives. Range 5-300 seconds.
BookStack timeout
app.bookstack_timeout_seconds
240 Publishing a large course is one long sequence of API calls. Range 10-1800 seconds.

Type to search every page. โ†‘ โ†“ to move, Enter to open.