Developing Software
telagod/code-abyss
Software development knowledge reference covering Python, Go, Rust, TypeScript, Java, C++, and Shell.
Guides adding or modifying a feature in the HOT-Step CPP Node/TypeScript server (Express route + service pattern, better-sqlite3 schema changes, engine calls via aceClient, logging, tsx watch dev…
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install scragnog/HOT-Step-CPP server-feature-dev --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/server-feature-dev .claude/skills/server-feature-dev && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .claude/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-devType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install scragnog/HOT-Step-CPP server-feature-dev --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/server-feature-dev .agents/skills/server-feature-dev && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .agents/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install scragnog/HOT-Step-CPP server-feature-dev --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/server-feature-dev .cursor/skills/server-feature-dev && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .cursor/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/scragnog/HOT-Step-CPP.git --path .claude/skills/server-feature-dev--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install scragnog/HOT-Step-CPP server-feature-dev --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/server-feature-dev .gemini/skills/server-feature-dev && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .gemini/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install scragnog/HOT-Step-CPP server-feature-devInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/server-feature-dev .github/skills/server-feature-dev && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .github/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install scragnog/HOT-Step-CPP server-feature-dev --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/scragnog/HOT-Step-CPP.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/server-feature-dev .opencode/skills/server-feature-dev && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "server-feature-dev" agent skill from https://github.com/scragnog/HOT-Step-CPP/tree/master/.claude/skills/server-feature-dev into .opencode/skills/server-feature-dev/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "server-feature-dev", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
server-feature-devGuides adding or modifying a feature in the HOT-Step CPP Node/TypeScript server (Express route + service pattern, better-sqlite3 schema changes, engine calls via aceClient, logging, tsx watch dev…
Server Feature Dev is an agent skill from scragnog/HOT-Step-CPP. Guides adding or modifying a feature in the HOT-Step CPP Node/TypeScript server (Express route + service pattern, better-sqlite3 schema changes, engine calls via aceClient, logging, tsx watch dev loop). Use when creating/editing files under server/src/, adding an /api/ endpoint, changing the SQLite schema, adding a config/env setting, wiring a server feature to the C++ engine, or debugging server-side failures (stalled/stuck generation jobs, engine HTTP timeouts, SQLite errors, engine crash-respawn loops).
Its SKILL.md is about 6.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `reference.md`).
It sits in Backend & APIs, covering REST APIs, React components and Backend development. It works with SQLite, C++, TypeScript and npm. The repository describes itself as: Turn dials. Summon bangers! NOW WITH MORE C++! Local AI music generation powered by GGML. The licence is MIT.
11 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 24b12b5. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxnpmgittsxcmakeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npx, npm and git, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Server Feature Dev loads about 6.5k tokens when it runs. Until then it costs about 133 tokens; SKILL.md has 2,872 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
a config value or a Settings-UI-exposed `.env` key (`server/src/config.ts`).## Procedure: add a config / .env setting`server/data/hotstep.db`; `DATA_DIR` in `.env` resolves relative to `server/`, NOT the repo root — config.ts:192. A stal95) — **without this the value saves to `.env` but never hot-patches the live config**., the code is POST; code wins) rewrites `.env` preserving comments and line endings, calls `reloadEnvConfig()`, and retuver/src/config.ts` | All configuration; `.env` hot-reload (`EXPOSED_ENV_KEYS` / `RESTART_REQUIRED_KEYS` / `reloadEnvConf| `server/src/routes/settings.ts` | `.env` read/rewrite + hot-reload endpoint (`POST /api/settings/env`) |Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from scragnog/HOT-Step-CPP at commit 24b12b5, republished under its MIT licence (© scragnog). 2,872 words, ~6,480 tokens.
.claude/skills/server-feature-dev/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.The Node server (server/src/) is the middle tier of HOT-Step CPP, a local AI music-generation app. It serves the React UI, owns the SQLite database, and orchestrates the C++ inference engine (ace-server.exe, spawned as a child process). This skill covers how to add or change a server feature the way this codebase does it.
Glossary (no prior context assumed):
server/src/services/aceClient.ts:38-151.translateParams).UI (fetch /api/*) → Express :3001 (dev: Vite on :3000 proxies /api to it) → routes/*.ts → services/*.ts
├→ getDb() (better-sqlite3, synchronous)
└→ aceClient (HTTP → ace-server :8085)/api/* endpoint or a whole feature (route + service).server/src/db/database.ts)..env key (server/src/config.ts).npx tsc --noEmit during dev; only npm run build before user testing. (Institutional rule, verbatim.) tsx watch runs TypeScript directly, so a build is wasted work mid-dev — but tsx also tolerates errors that tsc rejects, so type-check before committing.cd d:\Ace-Step-Latest\hot-step-cpp\server; npx tsc --noEmitserver/package.json:5-7 enforces >=20.0.0 <25.0.0. better-sqlite3 is a native module; postinstall runs npm rebuild better-sqlite3 (package.json:14)..js even though sources are .ts. server/package.json:8 sets "type": "module". import { config } from '../config.js' — omitting .js may run under tsx but fails tsc. There is no __dirname; the pattern is const __dirname = path.dirname(fileURLToPath(import.meta.url)) (config.ts:7, index.ts:46).getDb() at module import time. initDb() runs at index.ts:60; a query executed during module load throws Database not initialized. Call initDb() first. (database.ts:17-22). Query only inside handlers/functions./:id params. Express matches in order — GET /recent after GET /:id returns a 404 for id "recent". See the explicit warning at songs.ts:47 and seeds.ts (/favorites, /random at lines 131/143 precede /:name at 156).master, stage explicit paths (never git add -A, never git add -f on gitignored paths — data/, logs/, docs/plans/, checkpoints/ are gitignored on purpose), commit locally often, push only with explicit user approval. Pushing any v* tag triggers a full multi-platform CI release build.; not && for command chaining on this machine.engine/src/), rebuild via dev-rebuild.bat at repo root — never engine/build.cmd directly (you cannot reliably tell whether the app is running; the Node server auto-respawns ace-server on crash, index.ts:284-309 → infinite respawn + file-lock loop). Never cmake --clean-first (20+ min CUDA recompile); for stale .obj issues delete only engine/build/acestep-core.dir/ and engine/build/Release/acestep-core.lib.d:\Ace-Step-Latest\hot-step-cpp\dev.bat — runs Vite (UI, :3000, HMR) plus server\restart-loop.cmd, which loops npx tsx watch src/index.ts (restart-loop.cmd:6). Develop against http://localhost:3000. LAUNCH.bat (Node :3001 serving prebuilt ui/dist/) is the end-user prod path — agents don't run it.server/src/**/*.ts file → tsx watch restarts the whole Node process, which kills and respawns ace-server too (it's a child process). Expect a few seconds of engine downtime after every save; a generation in flight will die..restart-requested marker file exists at repo root — this is how the in-app "restart server" works without killing Vite.cd d:\Ace-Step-Latest\hot-step-cpp\server; npx tsc --noEmit.logs/<YYYY-MM-DD_HH-MM-SS>/ at repo root: node_console.log (server), ace_engine.log (engine), generations/gen_<jobId>_<task>.log (per generation). Newest folder = current session.server/src/routes/myFeature.ts. Convention: open with a comment block stating the mount point and a route table (best example: seeds.ts:1-20).// myFeature.ts — one-line purpose
// Mounts at: /api/my-feature
// Routes:
// GET /api/my-feature — list things
import { Router } from 'express';
import { config } from '../config.js'; // note the .js extension
const router = Router();
router.get('/', (req, res) => {
try {
res.json({ ok: true });
} catch (err: any) {
console.error('[MyFeature] list failed:', err.message);
res.status(500).json({ error: err.message });
}
});
export default router;server/src/index.ts — two edits: add the import to the block at index.ts:21-44 (import myFeatureRoutes from './routes/myFeature.js';) and mount it in the block at index.ts:72-95 (app.use('/api/my-feature', myFeatureRoutes);). URL segments are kebab-case (/api/model-manager, /api/cover-art, /api/stem-studio). One legacy exception: songBuilder.ts mounts at /api/builder.server/src/services/myFeature.ts. When a feature grows, use a sub-folder — services/generation/ holds translateParams.ts, lmCache.ts, postProcessing.ts, sourceAudio.ts, etc., all extracted from the once-monolithic generate.ts.import { getUserId } from './auth.js'; thenconst userId = getUserId(req);
if (!userId) { res.status(401).json({ error: 'Unauthorized' }); return; }Map<token, userId> that resets on restart, with a single auto-created local user "Producer" (auth.ts:13-26). getUserId is auth.ts:98-102.res.status(...).json(...); return; — do not return res... from typed handlers. The SPA fallback uses Express-5 wildcard syntax app.get('/{*splat}', ...) (index.ts:136) — Express 4 '*' patterns do not work.console.log('[MyFeature] ...'). Existing tags: [Server], [DB], [Config], [Generate], [Settings], [Logger], [ace-server]. This convention is what makes node_console.log greppable. To also surface lines in the UI's live log panel, import { pushLog } from './logs.js'; pushLog('text', 'server');.npx tsc --noEmit), test via the running dev server, then commit explicit paths:cd d:\Ace-Step-Latest\hot-step-cpp; git add server/src/routes/myFeature.ts server/src/services/myFeature.ts server/src/index.ts; git commit -m "feat(server): my feature"Not every feature needs SQLite. routes/seeds.ts stores JSON files under server/data/seeds/ on purpose (ComfyUI-compatible, import/export-friendly) with a filename-sanitization regex at seeds.ts:44. Use seeds.ts as the template for small self-contained features; use generate.ts for engine-orchestrating ones.
All DB work lives in server/src/db/database.ts. One connection, synchronous better-sqlite3 API, module singleton (initDb() once at startup, getDb() everywhere else, closeDb() on shutdown at index.ts:564). Pragmas at open: WAL, synchronous = NORMAL, foreign_keys = ON (database.ts:32-34).
CREATE TABLE IF NOT EXISTS block inside the big db.exec(...) at database.ts:37-209. Schema is re-run idempotently at every startup — there is no migration framework and no version table.songsMigrations array pattern, database.ts:213-259):{
check: `SELECT COUNT(*) as c FROM pragma_table_info('songs') WHERE name='my_col'`,
alter: `ALTER TABLE songs ADD COLUMN my_col TEXT DEFAULT ''`,
},ALTER only when the column is absent and logs [DB] Migration: .... Use this idiom for new columns. (A second, older idiom — try { db.exec("ALTER TABLE ...") } catch {} — exists for the lireek tables at database.ts:262-278; don't add to it.)uuidv4()) for core tables; lireek (Lyric Studio) tables use INTEGER PRIMARY KEY AUTOINCREMENT; timestamps TEXT DEFAULT (datetime('now')); booleans are INTEGER 0/1, re-hydrated as !!row.is_public (songs.ts:38); complex values are JSON-in-TEXT parsed with JSON.parse(s.tags || '[]').getDb().prepare(sql).get/all/run(...params) with ? placeholders — no statement-caching layer. Dynamic filters append to the SQL string and a params array (songs.ts:24-32), including JSON queries like json_extract(generation_params, '$.source') = ?.db/lireekDb.ts is a query-helper module over the same connection; its initLireekDb/closeLireekDb are deprecated no-ops (lireekDb.ts:12-23). The old separate lireek.db was consolidated into server/data/hotstep.db (one-time ATTACH DATABASE migration at database.ts:293-386, a good reference if you ever need bulk data migration).server/src/config.ts builds one exported config object (config.ts:96-257) grouping aceServer (engine exe autodetected from 4 candidate paths at config.ts:46-52; port default 8085), server (port 3001), data (getter dbPath → server/data/hotstep.db; DATA_DIR in .env resolves relative to server/, NOT the repo root — config.ts:192. A stale legacy data/ dir may exist at repo root with an outdated hotstep.db; ignore it), lireek (LLM keys/endpoints), vst, whisper, essentia. .env lives at repo root and is auto-bootstrapped from .env.example on first launch (config.ts:22-30).
To expose a new env setting in the Settings UI, you must touch three places in config.ts or it silently won't work:
EXPOSED_ENV_KEYS whitelist (config.ts:265-286) — "nothing else leaks" to the UI.RESTART_REQUIRED_KEYS (config.ts:289-294) so the UI shows "restart required".apply('MY_KEY', setter, getter) line inside reloadEnvConfig() (config.ts:300-395) — without this the value saves to .env but never hot-patches the live config.The Settings route (POST /api/settings/env, settings.ts:109-174 — note: the header comment says PUT, the code is POST; code wins) rewrites .env preserving comments and line endings, calls reloadEnvConfig(), and returns restartRequired.
server/src/services/aceClient.ts is the typed wrapper over ace-server's HTTP API (BASE = config.aceServer.url, i.e. http://127.0.0.1:8085 by default).
Critical constraint (aceClient.ts:6-8, verbatim comment): "ace-server uses single-threaded httplib. During heavy compute (DiT generation, adapter merge, VAE decode) it cannot respond to HTTP requests." Hence three timeout tiers via AbortSignal.timeout (aceClient.ts:17-19) — pick one deliberately for any new call:
| Tier | Value | For |
|---|---|---|
TIMEOUT_QUICK | 15 s | health, props, job submit |
TIMEOUT_POLL | 30 s | job polling — fail fast, let the watchdog decide |
TIMEOUT_RESULT | 300 s | fetching large audio bodies |
submitLm / submitSynth / submitUnderstand / warm POST and return a job id string; poll with pollJob(id) → { status: 'running'|'done'|'failed'|'cancelled', phase?, phase_step?, phase_total? } (phases like adapter_precompute, dit_inference — aceClient.ts:165-180); fetch the result with getJobResult(id) (GET /job?id=N&result=1); cancel with cancelJob(id). Sync endpoints (/spectral-lifter, /pp-vae-reencode) return processed WAV bytes directly.failed/cancelled statuses as terminal (see generate.ts:158-166).AceRequest interface first (aceClient.ts:38-151), then plumb it through services/generation/translateParams.ts (UI params → AceRequest). Known gotcha (institutional, from the LM-echo bug): server-only fields do not survive the engine's /lm round trip — synth requests are rebuilt from the original aceReq plus only the LM-generated fields (audio_codes, caption, lyrics, bpm, duration, keyscale, timesignature — generate.ts:237-246). Never assume a field you sent to /lm comes back.request JSON part plus named binary parts (audio, ref_audio, src_latents, ref_latents, seed_latents). The multipart path takes a single JSON object, not an array (aceClient.ts:374-378). Copy submitSynthMultipart (aceClient.ts:347-424).throw new Error('ace-server POST /x failed (status): body') (aceClient.ts:266-270); soft-fail helpers return null/false (getJobLatent, isReachable).import { engineReady, engineBootStatus } from '../engineState.js'; — this module exists solely to break a circular import between index.ts and routes (engineState.ts:1-5). Pattern: generate.ts:1356-1363.routes/generate.ts (~1600 lines) is the canonical "server orchestrates engine" feature. Copy its skeleton for anything long-running.
interface GenerationJob (id = uuid, userId, status pending|lm_running|synth_running|saving|succeeded|failed|cancelled, stage/progress for the UI, aceJobId, acePhase, result, error, params) in const jobs = new Map() (generate.ts:41-79). A TTL sweeper prunes terminal jobs older than 1 h every 10 min, with .unref() so the interval never blocks process exit (generate.ts:83-94)./api/generate (generate.ts:1355-1388): 503 if !engineReady; 401 if no user; build the job object from req.body; jobs.set(...); enqueueGeneration(job); respond { jobId, status } immediately.generationRunning boolean — one generation at a time (the in-code comment explains why: subscribeLines() is a global log pub/sub with no job tagging, so concurrent jobs would cross-contaminate progress). One retry on transient failure with a fresh random seed; Cancelled/Unauthorized are non-retryable.runGeneration, generate.ts:173 onward): translateParams(job.params) → aceReq; write the resolved seed back into job.params so the DB stores the actual seed used (reproducibility, generate.ts:193-197); decide whether to skip the LM phase (explicit skipLm, audio_codes already present, or a cover-type task — generate.ts:207-210); startGenerationLog(job.id, taskType) + logGenerationParams(job.id, aceReq); check the LM cache (services/generation/lmCache.ts, keyed by seed+params); submit via aceClient.submitSynth or, when any source/reference audio or latents are present, submitSynthMultipart (generate.ts:814-827); stage timings via a small timed() helper.pollUntilDone, generate.ts:102-170): 500 ms interval; honors an AbortController for cancellation; stall detection — no stage/progress change for 120 s → cancel the engine job and throw (generate.ts:126-134); wall-clock timeout clamped to 5–120 min, default 45 (generate.ts:104-106); transient poll errors are logged and retried.INSERT INTO songs (...) with a fresh uuid, generation_params = JSON.stringify(job.params) (generate.ts:1150-1161); audio files go under config.data.audioDir and are served statically at /audio/* (index.ts:98).GET /status/:id returns { jobId, status, stage, progress, result, error, ace_job_id, ace_phase, ace_phase_progress } (generate.ts:1391-1406); POST /cancel/:id sets status, cancels the engine job, fires the AbortController; plus /cancel-all, /queue, /reset-queue, and GET /stream/:id (SSE previews).Per-generation logging (services/logger.ts): startGenerationLog(jobId, taskType) → logGeneration(jobId, 'INFO'|'DEBUG'|'WARNING'|'ERROR', msg) / logGenerationParams(jobId, obj) → finishGenerationLog(jobId, taskType) or failGenerationLog(jobId, error, taskType). Lines are buffered in memory and flushed to logs/<session>/generations/gen_<jobId>_<task>.log only on completion (logger.ts:95-178) — a crash before finish loses the buffer, but every line is also streamed live via pushLog.
| Path | Role |
|---|---|
server/src/index.ts | App entry: route registration (imports :21-44, mounts :72-95), engine spawn/respawn (:158-316), graceful shutdown (:538-572) |
server/src/config.ts | All configuration; .env hot-reload (EXPOSED_ENV_KEYS / RESTART_REQUIRED_KEYS / reloadEnvConfig) |
server/src/db/database.ts | SQLite singleton, schema (CREATE TABLE IF NOT EXISTS), column migrations |
server/src/db/lireekDb.ts | Lyric-Studio query helpers over the same connection (init/close are deprecated no-ops) |
server/src/services/aceClient.ts | Typed HTTP client for the engine; AceRequest; timeout tiers; multipart |
server/src/engineState.ts | engineReady / engineBootStatus flags (circular-import breaker) |
server/src/routes/generate.ts | Worked example: job map, queue, watchdog, persistence |
server/src/services/generation/translateParams.ts | UI params → AceRequest translation |
server/src/routes/seeds.ts | Template for a small self-contained feature (filesystem storage, route-table header) |
server/src/routes/songs.ts | Template for auth-scoped SQLite CRUD (incl. the static-before-/:id warning) |
server/src/routes/auth.ts | Token-lite auth; getUserId(req) helper |
server/src/services/logger.ts | Session log dirs, logEngine, per-generation buffered logs |
server/src/routes/logs.ts | 2000-line ring buffer + SSE at GET /api/logs; pushLog / subscribeLines |
server/src/routes/settings.ts | .env read/rewrite + hot-reload endpoint (POST /api/settings/env) |
server/restart-loop.cmd | Dev-mode tsx watch wrapper with .restart-requested re-entry |
server/package.json | Scripts (dev/typecheck), "type": "module", Node <25 engines pin |
| Symptom | Cause | Fix |
|---|---|---|
Database not initialized. Call initDb() first. | A module ran a DB query at import time, before index.ts:60 | Move queries inside handlers/functions |
| Engine requests time out during generation | Normal — single-threaded httplib engine can't respond mid-compute | Use the right timeout tier; retry transient poll errors; never treat a poll timeout as job failure |
Generation stalled — no progress for Ns | The 120 s watchdog fired and cancelled a wedged engine job | Check gen_*.log + ace_engine.log in the newest logs/ session; the queue is unblocked automatically |
[ace-server] Crashed 3 times within 30s — giving up | Missing engine DLL / broken build; crash limiter halts respawn and sets engine not-ready (index.ts:296-301) | Fix the engine build (via dev-rebuild.bat); check ace_engine.log |
| New env setting saves but never takes effect | Key missing from the apply(...) list in reloadEnvConfig() or from EXPOSED_ENV_KEYS | Touch all three places in config.ts (see procedure above) |
| Setting saved, hot-reload reports OK, engine ignores it | Key is spawn-time (in RESTART_REQUIRED_KEYS) | Restart the app so the engine child respawns with new args |
GET /api/things/recent → 404 with id "recent" | Static route declared after /:id | Reorder — static routes first (songs.ts:47) |
better-sqlite3 native/ABI error after npm install or Node switch | Addon built for a different Node ABI or skipped native rebuild | Use Node 24; npm rebuild better-sqlite3 when the app is idle |
tsc errors on imports that run fine under tsx | Missing .js extension on a relative ESM import | Add .js to the import path |
| Spawned engine can't find DLLs despite a PATH edit | Spreading process.env on Windows creates a case-sensitive duplicate (Path vs PATH) that shadows | Find the real key case-insensitively before prepending — pattern at index.ts:221-244 |
Multipart submit to /synth fails with a parse error | Sent a JSON array as the multipart request part | Engine multipart expects a single object (aceClient.ts:374-378) |
npx tsc --noEmit during dev; only npm run build before user testing./lm round trip. Rebuild synth requests from the original aceReq plus LM-generated fields only; never whitelist-copy from the LM response.process.env is a case-insensitive proxy but spreading it makes plain case-sensitive keys — mutating PATH blindly creates a shadowing duplicate of Path.subscribeLines() is global pub/sub with no job tagging (generate.ts:1286-1290); don't "fix" concurrency without solving log attribution first.ACESTEPCPP_DRAFT_LM env re-enables it; auto-detect is commented out (config.ts:160-173).adapter_section_isolation still exists in AceRequest (aceClient.ts:97) but the engine-side regional self-attn isolation was reverted for breaking musical continuity — treat the field as inert (unverified on the engine side — check engine code before relying on it).uncaughtException/unhandledRejection are logged but do not exit the process (index.ts:576-581), and there is no global Express error middleware — a throw in an async handler will not produce a clean JSON 500, so catch locally in every handler.More depth (full aceClient method catalog, engine spawn args, settings hot-reload internals, DB idiom code, SSE log stream details): reference.md.
CLAUDE.md (repo root) — orientation map, build/git rules.engine/docs/ARCHITECTURE.md — engine internals, CLI, request JSON, generation modes (committed).FEATURES.md — full feature catalogue (committed).docs/dev/plugins-authoring.md — Lua plugin authoring; solvers/schedulers/guidance are plugins, not C++ (committed).docs/plans/ — internal design/investigation docs. Gitignored, local-only — may be absent on a fresh clone.server/src/data/assistant-knowledge.md — in-app assistant knowledge base (committed).© scragnog, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .claude/skills/server-feature-dev of scragnog/HOT-Step-CPP.
Open the folder on GitHubat commit 24b12b5
Server Feature Dev next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Server Feature Dev this skillscragnog/HOT-Step-CPP | 170 | — | ~6.5k | Automated safety check: Notes | MIT | |
| Developing Softwaretelagod/code-abyss | 244 | — | ~410 | Automated safety check: Pass | MIT | |
| React Emailviclafouch/meme-studio | 110 | 2 repos | ~3.6k | Automated safety check: Pass | MIT | |
| Nodejs Expresscohen-liel/hivemind | 110 | — | ~856 | Automated safety check: Pass | Apache-2.0 | |
| Implementing MCP ToolsPostHog/posthog-foss | 721 | — | ~3.7k | Automated safety check: Pass | MIT | |
| MCP Server BuildershareAI-lab/learn-claude-code | 78k | 5 repos | ~1.2k | Automated safety check: Pass | MIT |
telagod/code-abyss
Software development knowledge reference covering Python, Go, Rust, TypeScript, Java, C++, and Shell.
viclafouch/meme-studio
A skill your agent uses when creating HTML email templates with React components - welcome emails, password resets, notifications, order confirmations, newsletters, or transactional emails.
cohen-liel/hivemind
Node.js + Express backend patterns. An agent skill from cohen-liel/hivemind.
PostHog/posthog-foss
Guide for exposing PostHog product endpoints as MCP tools. An agent skill from PostHog/posthog-foss.
shareAI-lab/learn-claude-code
Walks through building MCP servers in Python or TypeScript that expose tools, resources and prompts to Claude, with templates, registration and testing.
utensils/nxv
Find any version of any Nix package across nixpkgs git history using the nxv CLI or HTTP API.
scragnog/HOT-Step-CPP
The standard way to run a listening test in HOT-Step - a local HTML score sheet next to the renders where Rob plays each track, scores it 1-5 on named criteria, and the page charts the two score…
scragnog/HOT-Step-CPP
Explains where HOT-Step generation time goes (LM/DiT/VAE), how the TensorRT paths activate, how to benchmark from logs, and which knobs trade quality for speed.
scragnog/HOT-Step-CPP
Maps HOT-Step's native MiniMax-Music3 backend — engine port modules, endpoints, server/UI integration, parity/fixture infrastructure, and the hard-won trap list.
scragnog/HOT-Step-CPP
The validated recipe for training MiniMax-Music3 planner-LM style adapters (artist/album clones) with ace-train mm3-lm-train and the Training Studio.
scragnog/HOT-Step-CPP
Runbook for cutting and publishing a HOT-Step CPP release via a v git tag that triggers the multi-platform CI build and drafts a GitHub Release.
scragnog/HOT-Step-CPP
Safely pulls upstream acestep.cpp changes into the HOT-Step engine fork without destroying its integration hooks.
Works with
Categories
Guides adding or modifying a feature in the HOT-Step CPP Node/TypeScript server (Express route + service pattern, better-sqlite3 schema changes, engine calls via aceClient, logging, tsx watch dev…. Server Feature Dev is an agent skill from scragnog/HOT-Step-CPP. Guides adding or modifying a feature in the HOT-Step CPP Node/TypeScript server (Express route + service pattern, better-sqlite3 schema changes, engine calls via aceClient, logging, tsx watch dev loop).
Server Feature Dev fits situations like: creating/editing files under server/src/; adding an /api/ endpoint; changing the SQLite schema; adding a config/env setting.
Run `npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a claude-code`. Or copy the skill folder (.claude/skills/server-feature-dev in scragnog/HOT-Step-CPP) into .claude/skills/server-feature-dev in your project. Claude Code loads it when a task matches its description.
Run `npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a codex`. Or copy the skill folder (.claude/skills/server-feature-dev in scragnog/HOT-Step-CPP) into .agents/skills/server-feature-dev in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add scragnog/HOT-Step-CPP --skill server-feature-dev -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/server-feature-dev, .gemini/skills/server-feature-dev, .github/skills/server-feature-dev and .opencode/skills/server-feature-dev in your project.
Going by SKILL.md and its folder, Server Feature Dev needs the command-line tools its instructions call (npx, npm, git, tsx and cmake). Our summary lists: Node.js.
SKILL.md contains no URLs. Its commands use npx, npm and git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Server Feature Dev is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.5k tokens (SKILL.md is roughly 26k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Server Feature Dev: Developing Software (telagod/code-abyss, 244 stars), React Email (viclafouch/meme-studio, 110 stars), Nodejs Express (cohen-liel/hivemind, 110 stars) and Implementing MCP Tools (PostHog/posthog-foss, 721 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
scragnog (a GitHub user) maintains it in scragnog/HOT-Step-CPP, which has 170 GitHub stars. The repository holds 18 skills in this directory. The repository was last updated on October 5, 2026.
Source: scragnog/HOT-Step-CPP on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.