Settings
Configure LLM, pipeline, tracks, prompts, and system
this.saved = false, 3000);
} catch(e) {
this.error = e.message;
} finally {
this.saving = false;
}
},
async saveAll() {
this.saving = true;
this.error = '';
try {
const res = await fetch('/api/settings', {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(this.settings)
});
if (!res.ok) throw new Error(await res.text());
this.saved = true;
setTimeout(() => this.saved = false, 3000);
} catch(e) {
this.error = e.message;
} finally {
this.saving = false;
}
},
async resetAll() {
if (!confirm('Reset ALL settings to defaults? This cannot be undone.')) return;
try {
await fetch('/api/settings/reset', {method: 'POST'});
location.reload();
} catch(e) {
this.error = e.message;
}
},
async resetPrompt(stage) {
if (!confirm(`Reset ${stage} prompt to default?`)) return;
try {
await fetch(`/api/settings/prompts/${stage}/reset`, {method: 'POST'});
const res = await fetch(`/api/settings/prompts/${stage}`);
const data = await res.json();
this.settings.prompts[stage] = data.prompt;
this.saved = true;
setTimeout(() => this.saved = false, 3000);
} catch(e) {
this.error = e.message;
}
},
async addTrack() {
if (!this.newTrackName) return;
try {
const res = await fetch('/api/settings/tracks', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: this.newTrackName,
description: 'Custom track',
slug_prefix: this.newTrackName + '-',
enabled: true,
gates: {
brief: {enabled: true, required_fields: [], min_word_count: 200, max_word_count: 0},
thesis: {enabled: true, required_fields: [], min_word_count: 300, max_word_count: 0},
outline: {enabled: true, required_fields: [], min_word_count: 100, max_word_count: 0},
script: {enabled: true, required_fields: [], min_word_count: 1000, max_word_count: 0},
fact: {enabled: true, required_fields: [], min_word_count: 0, max_word_count: 0},
publish: {enabled: true, required_fields: [], min_word_count: 0, max_word_count: 0},
},
metadata: {}
})
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
this.settings.tracks[this.newTrackName] = data.track;
this.newTrackName = '';
this.saved = true;
setTimeout(() => this.saved = false, 3000);
} catch(e) {
this.error = e.message;
}
},
async deleteTrack(name) {
if (!confirm(`Delete track '${name}'?`)) return;
try {
await fetch(`/api/settings/tracks/${name}`, {method: 'DELETE'});
delete this.settings.tracks[name];
this.saved = true;
setTimeout(() => this.saved = false, 3000);
} catch(e) {
this.error = e.message;
}
},
async testPaths() {
try {
const res = await fetch('/api/settings/paths/test', {method: 'POST'});
const data = await res.json();
this.pathTestResults = data.paths;
} catch(e) {
this.error = e.message;
}
},
pathTestResults: null,
promptPreview: '',
previewStage: '',
previewPrompt(stage) {
this.previewStage = stage;
const p = this.settings.prompts[stage];
this.promptPreview = `--- SYSTEM ---\n${p.system}\n\n--- USER ---\n${p.user}`;
},
addDirToList(section, field) {
const input = prompt('Enter directory path:');
if (input) {
this.settings[section][field].push(input);
}
},
removeDirFromList(section, field, index) {
this.settings[section][field].splice(index, 1);
}
}" class="space-y-6">
✓ Settings saved successfully
LLM Configuration
Stored in memory only — never persisted to disk
(off = rule-based fallback)
Pipeline Configuration
(auto-progress through gates)
(retry failed gates automatically)
Content Tracks
Prompt Templates
Preview:
Directory Paths
✓
✗
Security — Allowed Directories
Server Configuration
Requires restart to take effect
System Information
Version
0.2.0
Python
3.12+
Stack
FastAPI + HTMX + Tailwind + Alpine.js
State Store
Filesystem (status.yaml)
LLM Provider
LLM Enabled
Tracks
Settings File
settings.yaml