Skip to content

Latest commit

 

History

History
543 lines (510 loc) · 259 KB

File metadata and controls

543 lines (510 loc) · 259 KB

server/lib/ — shared server helpers

Pure / side-effect-free helpers, validators, parsers, prompt builders, and shared constants. Before adding a new helper here, grep this catalog first — if a similar module exists, extend it. When you add a new module, add it to index.js AND add a row here.

Service-layer orchestration (multi-step business logic) lives in server/services/, not here.

Discovery rule

grep -i "what you want to do" server/lib/README.md

The barrel server/lib/index.js is a machine-checkable enumeration of every public surface; server/lib/index.test.js verifies that every non-test .js/.jsx file is re-exported AND appears in this README, AND that no two flat-exported modules share an identifier name.

Namespace exports. The validation modules (brainValidation, digitalTwinValidation, etc.), runners, and storyBible are surfaced through the barrel as namespace exports — barrel.brainValidation.settingsUpdateInputSchema, not bare settingsUpdateInputSchema — because their generic names collide with peers. Direct deep imports (import { settingsUpdateInputSchema } from './brainValidation.js') are unaffected.


Validation (Zod schemas + request validators)

Module Purpose
appDeployFlags.js Shared allowlist of flags PortOS may forward to a managed app's deploy.sh, consumed by socket validation and deployment orchestration without reversing the lib/services dependency.
apiContractSchemas.js Canonical Zod request contracts for externally callable APIs plus zodToOpenApiSchema (plain JSON Schema — the 3.0.3 conversion happens at the OpenAPI document boundary, not here); runtime routes and OpenAPI use the same schema objects.
socketEventContracts.js Runtime-backed payload contracts for modeled inbound Socket.IO events, reusing the same Zod schemas as live validation.
socketEventInventory.js Cached source-derived Socket.IO event inventory: event names and directions only, with no checked-in manifest or positional source metadata.
agentContextValidation.js Shared settings, MCP request/tool input/output schemas, result + approximate-token bounds, source-freshness status, and advertiseAgentContextTools(scopes) for the opt-in read-only agent-context surface.
validation.js Catch-all Zod schemas (app/process/provider, social accounts, GitHub, backup/sharing, document/legacy-export) + the validateRequest middleware + shared helpers (optionalBooleanMap, isSafeRecordId, parseIndexParam, parsePagination). Re-exports the per-domain validation files below so existing deep imports keep working.
taskDataInputCatalog.js Pure catalog and persisted ids for deterministic context sources that scheduled agent tasks can preload before dispatch.
sharedSchemas.js Cross-domain Zod fragments that validation.js and the per-domain *Validation.js files both need, kept in a leaf module so the domain files never import back through validation.js (its hoisted export * from lines would TDZ). grokVideoDurationSchema (grok clip-length union), cloudModelIdString(message) (cloud-CLI model-id charset/bounds), recordRenderPinFields (the imageMode/imageModelId per-record render pin pair), and isSafeSubdirFilter(v) (relative path with no wildcard, .. segment, or leading /), and csvIdsParam({ max, maxIdLength, truncate }) (the ?ids=a,b,c batch-by-id query param: trims, drops empties, reads all-blank as absent, and either 400s or silently slices an over-cap batch).
generationModes.js Shared immutable image/video render-backend alphabets (IMAGE_GEN_MODE[S], QUEUEABLE_IMAGE_MODES, VIDEO_GEN_MODE[S], and cloud subsets), kept below both validation and generation services so schemas never import orchestration modules.
fableLoomLimits.js FableLoom record caps (LOOM_LIMITS) — the single source of truth shared by the route schemas and the record sanitizer. A leaf module, below both.
fableLoomCameraMovements.js Shared FableLoom camera-movement registry for generated cut direction and the manual scene editor selector.
fableLoomPlayback.js FableLoom node playback modes (cut auto-advances; decision loops while awaiting input), with the backward-compatible default.
fableLoomParticipation.js FableLoom audience roles (helper vs protagonist), per-scene connection availability, prompt contracts, and backward-compatible defaults.
fableLoomFormats.js FableLoom scene formats (LOOM_FORMATS, asLoomFormat, sceneFormatContract, …) — how a loom writes scene text, read by validation, the sanitizer, and every generative stage.
fableLoomProduction.js FableLoom production batch planning and topological orchestration: shared still/video render-format presets and story-level image/video provider preferences (16:9 default), ordered episode storyboard gates, DAG resolution, asset enumeration, execution stages, and exact-input provenance verification.
fableLoomContinuity.js FableLoom episodic continuity review: multi-vector deterministic checks for visual entity bindings, convergence clarity, voice profile consistency/drift, pronunciation anchors, and playback safety.
fableLoomOutline.js FableLoom story-first episode beat outlines: bounded log-lines, deterministic arc validation, and compact prompt rendering before teleplay expansion.
fableLoomPlaytest.js FableLoom branching-playthrough harness: bounded exhaustive path enumeration, ending/loop/coverage diagnostics, aggregate loom reports, and compact traces for narrative-quality review.
postDrillTypes.js MeatSpace POST drill vocabularies (CACHEABLE_TYPES, COGNITIVE_DRILL_TYPES), kept below validation so a route schema never pulls in the POST services (and, through them, the LLM drill generator).
spriteVocabulary.js Sprite id pattern, record kinds, the canonical 8-direction order + derived anchor set, TURNAROUND_ID, and the animation provider ids — the alphabets the sprite route schemas enumerate, kept below the sprite services.
spriteChromaKey.js Chroma-key selection color math (CHROMA_KEYS, CHROMA_KEY_HEXES, DEFAULT_CHROMA_KEY, hue-distance picking). Pure color math, no image I/O — that lives in services/sprites/normalize.js.
spriteAnimationTracks.js The animation-track registry (ANIMATION_TRACKS, WALK_TRACK, TRACK_BOUND_TRIPLES, AUTHORED_TRACK_FIELDS) — a zero-import table of per-track frame/fps bounds.
spriteAnimationTrackStore.js The EFFECTIVE track table — compiled built-ins plus the user-defined store read from one small JSON config, so sprite schemas stay module-load constants rather than lazily-built.
agentOutputMarkers.js Status lines PortOS itself appends to an agent's output buffer: SENTINEL_COMPLETION_MARKER (the line ingestDoneSentinel writes just before the agent's .agent-done summary) plus isAgentLifecycleLine(line)/stripLifecycleLines(lines), which match PortOS's telemetry on its actual message shapes rather than on a leading emoji (an agent's own summary may well start a line with ). Pure — shared by the emitter (services/agentTuiSpawning.js) and by readers that must show only the agent's own words (notably the generated PR description).
agentRunEvents.js CoS run lifecycle-event envelope (#4540) — pure half of the append-only ledger in services/agentRunEventLog.js. AGENT_RUN_EVENT_KINDS (closed vocabulary: spawned, handoff, output, reconnected, paused, resumed, interrupted, pr-verified, orphan-recovered, runner-recovered, finalized), agentRunEventSchema (Zod, .strict()), buildRunEvent() which redacts then mints a CONTENT-derived eventId (sha256 of the canonicalized envelope) so a redelivered lifecycle transition dedupes instead of double-counting, redactRunEventData() (drops prompt/description/output/result-class keys to a { redacted, chars } stub, scrubs the home-dir prefix out of every remaining string via scrubHomePath, runs redactOutput, and caps string/array/key/depth per RUN_EVENT_LIMITS), and projectRunStates() — the clock-free fold that derives current run status from the ordered stream, so replay-after-restart and read-current-status are one code path. Unknown kinds fold as no-ops so a newer install's ledger replays on an older one.
agentRunReconcile.js CoS run reconciliation (#4540) — pure diff between a ledger projection (projectRunStates) and the durable run record. Closed finding vocabulary RUN_RECONCILE_FINDINGS (record-open, record-missing, verdict-mismatch, ledger-open), diffRunRecord(), reconcileRunRecords() with a zero-filled per-kind summary, and planRunRecordRepair() — the metadata patch that closes a record the ledger proves is finished. Repairs are one-directional (ledger → record) by design: a record closed while the ledger missed the close is reported, never back-filled, so the stream stays an audit of the record rather than a copy of it. I/O half: services/agentRunReconciler.js.
agentScratchPaths.js Runtime scratch PortOS itself writes into an agent worktree and never commits — PUBLIC_REVIEW_INPUT_FILENAME / PUBLIC_REVIEW_PATCH_DIRNAME (the public-review bundle materialized by services/modelAbuseGuard.js), the AGENT_SCRATCH_PATHS list, prefix-aware matchesScratchRoot(path, roots) and isAgentScratchPath(path). classifyWorktreeDirt (services/worktreeManager.js) subtracts these for EVERY caller and uses the same matcher for its per-call ignoredPaths, so a worktree holding only scratch reads as clean end to end — before this, it was preserved by removeWorktree, held by reapMergedWorktrees, filed as a repo-state recovery task, and dispatched to a branch-reconcile coordinator, forever. Only STATIC names live here; a run-scoped name like .agent-done-<agentId> (agentSentinel.js) is passed per call instead.
agentSentinel.js The .agent-done completion sentinel: DONE_SENTINEL_NAME, doneSentinelName(agentId) → the per-instance filename .agent-done-<agentId> (worktree-less agents share one workspace, so a shared name lets concurrent runs clobber — and finalize on — each other's signal), doneSentinelPath(workspacePath, agentId) → the single path every producer and consumer resolves, + pure parseSentinelPayload(contents){ summary, payload }. Back-compat — a plain-markdown sentinel yields payload: null; a JSON object yields its structured payload for a programmatic-I/O task type's processTaskOutput hook. salvageSentinelPayload(contents) (async) is the lenient second tier — runs jsonExtract over a fenced/prose-trailed/control-char-corrupted envelope so a less-capable model's near-valid output still surfaces its payload instead of being dropped. extractSentinelPayloadFromTranscript(transcript, isPayload) (async) is the third tier for programmatic-I/O types ONLY — scans the ANSI-stripped PTY transcript, newest balanced JSON block first, for a payload the model PRINTED instead of writing, and adopts it only if the owning hook's shape predicate accepts it (#3640). PROGRAMMATIC_OUTPUT_COMPLETION_HEADING names the briefing section that prints this run's absolute sentinel path — a task-type hook renders its prompt before spawn, so it points the agent at that section by name rather than at a filename it cannot know.
persistentMind.js Pure persistent-CoS-mind runtime state: default-off durable shape, normalization, FIFO-message/self-wake selection, interrupted-wake requeue, image-work rollback guard, bounded exponential backoff, watchdog staleness, and next-wake projection.
persistentMindCapabilities.js Default-off persistent-mind action grants plus bounded typed CoS-task, private-Eidoverse, and self-cleanup contracts (app/provider/model/effort, PR completion policy, the optional exact provider/model task allowlist, and mind-owned context scopes).
cosToolContracts.js Provider-neutral portos_tool catalog/call schema version, request-id and per-turn bounds, catalog query formats, and Persistent Mind tool-call shape.
persistentMindTrajectory.js Pure persistent-mind trajectory vocabulary, sequence cursor parsing, replay projection, provenance-tagged rollup validation, and hard-budget context assembly with explicit empty/missing/failed/stale summary states.
persistentMindProfile.js Versioned, default-off persistent-mind provider profile (enabled, provider/model/effort, text interface, maximum quiet interval), its strict API schema, duration resolver, and safe partial-update merge that clears model/effort on a provider switch.
persistentMindPrompt.js Editable persistent-mind identity and operating-instructions schema/defaults; saving it never starts inference.
persistentMindPublic.js publicPersistentMindState(state) — the sole client/socket projection of durable mind state: exposes lifecycle fields, queue count, and the derived next wake time; drops queued message bodies/active wake payloads, and replaces free-form provider errors with coarse safe reasons.
persistentMindThinkingPresets.js Saved named temporary thinking presets for the persistent mind (exact provider/model/effort alternates to its one home profile): default-empty durable shape, normalization that drops half-pinned entries, strict API schema, whole-list replace merge, and preset lookup. Storage only — saving or selecting a preset starts no inference.
heavyJobClaim.js Cross-process, machine-wide accelerator claim: claimHeavyLocalJob({ kind, id, timeoutMs? }) either acquires an ephemeral data/ lock or reports its active holder; dead-PID claims are reclaimed, and a spawned child can take over the recorded PID across a server restart.
agentValidation.js Social-bot agent schemas (personality, Moltbook/Moltworld accounts, automation schedules, agent tools + Moltworld payloads) and CoS Feature Agent definitions.
quotaBurnConfig.js Quota-burn plan shape: the provider families, the burn-job type alphabet + catalog the config page renders its form from, QUOTA_BURN_BOUNDS (the one bounds table the normalizer clamps to, the Zod schemas reject against, and the catalog descriptors publish as min/max), and total normalization (normalizeQuotaBurnConfig). Owns the dispatch-cap sentinel too (QUOTA_BURN_UNLIMITED_DISPATCHES / isUnlimitedDispatchCap) — -1 means the window is not counted, and is the default. Also owns the queued burn task's description shape (burnTaskDescription / quotaBurnFamilyOfDescription), shared with migration 225, and the run once vocabulary (quotaBurnJobKey / jobIsSpent, plus the two family predicates familyIsConfigured and familyHasRunnableJobs). Pure — no storage, no provider I/O.
quotaBurnPresets.js QUOTA_BURN_PROMPT_PRESETS — ready-made single-focus audit prompts for agent-prompt burn jobs (UX, a11y, mobile, failure paths, perf, test gaps, dead code, data safety, docs, security), each filing GitHub issues and changing no code. Templates: picking one COPIES its prompt into the job, so editing them never rewrites a configured job. findQuotaBurnPreset(id).
auditCatalog.js Shared catalog of scheduled AUDIT task types (AUDIT_DEFINITIONS / AUDIT_TASK_TYPES) that can either implement a fix or file tracker issues. isFileIssuesMode, auditDoWorkRequiresWorktree, getAuditFilingPreset, modeContractFor, applyAuditModeWrapper. Each quota-burn audit preset maps to a scheduled type here (guarded by auditCatalog.test.js). Pure — no I/O.
quotaBurnValidation.js Zod schemas for the Quota Burn routes (partial config PUT, manual-run body, run once re-arm body).
quotaReset.js parseHumanReset turns a provider CLI's human reset string into ISO 8601 (call it from the adapter); normalizeResetAt/hoursUntilReset compute time remaining without treating unknown values as imminent resets; parseObservedReset pulls the reset a provider stated in its own refusal text, and isObservedBlockActive is the shared "is that refusal still holding?" predicate every observed-refusal ledger uses.
quotaWindows.js Classifies a quota window by PERIOD (windowPeriodHours); classifyWindows splits one card's windows into the weekly allowance that expires unused and the 5-hour one that refuses first, in one pass. windowLabelOf names a window. Pure.
recurrenceValidation.js Shared Zod shape and vocabulary for anchored calendar recurrences that cannot be represented faithfully by five-field cron.
appleHealthValidation.js Apple Health import payloads.
brainValidation.js Brain/memory route schemas (search, ingest, edit).
catalogValidation.js Creative ingredients catalog route schemas (scraps, ingredients, links, relations, tags, revisions, sync envelope).
cosValidation.js Chief-of-Staff task/job/loop/learning schemas, the Code-Review settings slice, and the task-metadata sanitizer. The Review-Loop reviewer vocabulary lives in reviewerConfig.js (#5702) and is re-exported flat from here.
creativeCommissionValidation.js Creative Commission (Autonomous Creation Engine) create/update + brief/schedule/generation schemas. Brief field caps are mirrored by the commission form in client/src/components/creative-commission/commissionForm.js (parity: creativeCommissionValidation.mirror.test.js).
creativeDirectorValidation.js Creative Director project/treatment/scene + Create-Suite importer schemas. CREATIVE_DIRECTOR_GOAL_MAX is mirrored in client/src/lib/creativeDirectorPlan.js (parity: creativeDirectorValidation.mirror.test.js).
digitalTwinValidation.js Digital twin document/category schemas.
eidoverseValidation.js Eidoverse world-projection schemas — the EIDOVERSE_PROJECTION_SOURCE_KEYS allowlist, the V1/V2 projection recipe union (includes/assets/terrain/scale/districts/environment, with the ..-escape guard on every asset path), and the world augment/say/config-patch route bodies (incl. the 8KB augment-argument cap). Split out of validation.js (#5698), which re-exports it.
fableLoomValidation.js FableLoom branching-narrative route schemas (loom/episode/node/transition CRUD, weave/branch/review, play turns).
genomeValidation.js Genome upload + search schemas.
identityValidation.js Identity section + chronotype + scheduling schemas.
meatspaceValidation.js Meatspace (location/health log) schemas.
mediaValidation.js Media-generation & local-model infra schemas (LoRA training, local-LLM/Ollama/LM Studio management, media-collection bulk ops).
memoryValidation.js Memory record + retrieval schemas.
modelPersonalityValidation.js LLM personality self-profile test schemas: trait taxonomy (versioned), self-eval + twin-alignment response schemas, run/settings route inputs.
moodBoardValidation.js Mood board + board-item create/update schemas.
musicVideoValidation.js Music Video project/scene/reorder + cached audio-analysis schemas.
notesValidation.js Notes route schemas + safe-relative-path guard.
peerSyncValidation.js Federated peer-sync wire/request schemas (push payload, subscribe, sync-now, pull-metadata).
pipelineValidation.js Creative-production pipeline schemas (Writers Room works/folders/live-mode/drafts, story-bible character/place/object, editorial checks, storyboard shots/scenes, prompt-stage config, issue-list query).
postLlmContracts.js Versioned POST LLM generation/scoring schemas, semantic-verdict validation, and secret-free generator/scorer provenance with explicit legacy normalization.
postRhetoric.js Shared rhetoric evaluator rubric, mode/drill ids, structured evaluator prompt/response validation, and the 40-item fictional gold-reference corpus used by POST background reports and local-model performance checks.
postValidation.js MeatSpace POST (Power On Self Test) schemas — drill config (incl. adaptive toggle), drill generation/scoring, sessions, memory builder, training log.
privacyValidation.js Privacy Center schemas — PII Vault (issue #2140): vault record create/update (partial PUT), list query, UUID params; the vault type/status vocabularies + the sensitive-type (ssn/passport/drivers_license/financial_account) useForScans hard-false rule and per-type scan defaults. Trusted Organizations registry (issue #2141): org create/update (partial PUT), list query, UUID params, and the replace-set holdings schema. Data-broker database + case ledger (issue #2144): broker list/case-list query filters, the scan-start + refresh action bodies, and the PRIVACY_BROKER_CASE_STATES vocabulary.
roundsValidation.js Rounds workbench shape bounds + pure record sanitizers (sections, layers, recordings, pitch analysis, references, progress) — sanitizeRound(raw, builtinIds) and the length/count limits shared with routes/rounds.js.
socketValidation.js Socket event payload schemas.
spriteValidation.js Sprite Manager Zod schemas — record import/create/update, reference generate/lock/unlock + fork, walk-cycle generate/approve/reopen/trim, per-track generate/approve schemas built from the animation-track registry, publish binding + runtime contract, atlas publish/compile, and user-defined animation-track create/update. Split out of validation.js (#3873), which re-exports it.
storyBuilderValidation.js Unified Story Builder session/step schemas.
telegramValidation.js Telegram bot config + test schemas.

Story & narrative

Module Purpose
editorial/ Extensible editorial-check registry (#1284) — EDITORIAL_CHECKS + fail-fast guards + lookup/state helpers. See editorial/README.md. The runner that executes checks lives at server/services/pipeline/editorial/checkRunner.js.
fableLoomGraph.js FableLoom branching-narrative graph analysis: analyzeEpisodeGraph (deterministic validation — reachability, dead ends, dangling paths, intent hygiene), computeGraphLayers (BFS layering), describeGraphForPrompt (compact text rendering for LLM stages), GRAPH_ISSUE_CODES.
storyBible.js Canonical Character / Place / Object shapes + BIBLE_LIMITS. Also the reveal-gated canon / spoiler-scoping helpers (#2178): filterCanonForIssue / filterCanonListForIssue / isCanonEntryGatedForIssue (hide or surface-substitute a gated entry in a drafting prompt), canonHasRevealGated + revealGatedCanonRows (for the continuity.premature-reveal check gate/summary).
storyArc.js Canonical Arc + Season + Reader-Map shapes for pipeline arc planning.
styleGuide.js Per-series house style (tense/POV/audience/rating/reading-level/tone/conventions): sanitizeStyleGuide + renderStyleGuide generation block + enums.
storyBuilderSteps.js Unified Story Builder ordered step definitions + helpers (STEPS, STEP_IDS, STEP_STATUSES, isValidStepId, stepIndex).
streamLines.js createLineReader(onLine, {splitRe?, maxCarry?}) + createOutputTail({budget?}) — buffered chunk→line splitter for child-process stdout/stderr. Carries the partial trailing line across data chunks and flush()es the final unterminated line on close; carry clamp guards a newline-less runaway stream. One reader per stream (a shared buffer corrupts marker lines). splitRe: /[\r\n]+/ handles torch/tqdm bare-\r progress redraws. createOutputTail is the sibling rolling buffer of recent lines (char-budgeted, decoration-only lines skipped so an ASCII-art banner cannot push the real error out) that turns "exited with code 1" into what the tool actually printed — used by streamingSpawn.js.
storyBuilderIntegrity.js Pure staleness hashing for the Story Builder (hashUpstream, computeStaleSteps, computeSyncDrift).
projectStoreKit.js Shared project-store sync normalization, LWW batch decisions, and tombstone selection for file and PostgreSQL adapters.
canonPrompt.js Per-kind field-precedence rules; SHORT/RICH/PREVIEW spec tables; flattenCanonDescriptorFragments / mapCanonDescriptorFragments / descriptorForCanonEntry.
scenePrompt.js Scene-prompt composer + bible matchers (chars/places/objects in text).
proseExportSettings.js Per-series prose-export settings (#2181): sanitizeProseExportSettings + resolveExportSettings + TRIM_SIZES/INTERIOR_FONTS for the manuscript/ePub/PDF exports.
shotGrammar.js Pure shot-grammar vocabularies (SHOT_TYPES, SCREEN_DIRECTIONS) + normalizers (normalizeShotType, normalizeScreenDirection) for a storyboard shot's camera framing + on-screen direction. Shared by the scene extractor's sanitizer, the storyboards Zod schema, and the visual.shot-continuity editorial check (#1315).
storyboardScenes.js Durable ids + id-first addressing for stages.storyboards.scenes[] (#3413). ensureStoryboardIds(scenes) stamps a deterministic scene-NN / shot-NN id on any entry lacking one — and re-stamps later copies of a DUPLICATE id (collision-escaped with a -2 suffix, so peers and concurrent readers derive identical ids); resolveStoryboardTarget(list, { id, index }){ index, record, matchedBy, stale } resolves a captured id against a fresh array, falling back to the index only when no id was captured, and reporting stale: true (409, never an index retarget) when a captured id is gone.
seasonStructure.js Season/episode structure recommendation.
seriesCharacterArc.js Per-character story-arc shapes (series.characterArcs[]): want/need, start → end state, transition beats. Sanitizers + renderCharacterArcsForPrompt for the arc.transitions editorial check.
llmRoutePin.js The per-record LLM route pin { providerId, model, effort }LLM_ROUTE_PIN_LIMITS + llmRoutePinSchema (door check, effort as the shared EFFORT_LEVELS enum), sanitizeLlmRoutePin(raw) (trim/cap, null for an all-empty pin), and resolveLlmRoutePin(pin, perCall){ providerId, model, effort, providerMatchesPin }. Owns the never-cross-providers rule once, in its two shapes: resolveLlmRoutePin merges a record pin with an independent per-call pick per FIELD (guarded by a provider-id comparison), while pickLlmRoutePinLayer(...layers) + llmRoutePinNamesProvider(layer) take the most specific layer WHOLE for pins whose provider and model were chosen together in one control (falling through to the base layer). Consumed by seriesLlmOverride.js, FableLoom's play pin, and the Creative Director stage pins.
seriesLlmOverride.js Pure resolveSeriesLlmOverride(series, { overrideProvider, overrideModel }){ provider, model, providerMatchesSeries } — shared fallback so Pipeline LLM actions honor the series' configured provider/model, only inheriting the series model when the effective provider still matches.
catalogBulkParsers.js Dependency-free markdown/CSV/JSON parsers for POST /api/catalog/bulk-import and YAML/markdown serializers for GET /api/catalog/export.
catalogChunking.js Pure lossless scrap-text chunker (chunkRawText, CATALOG_CHUNK_MAX_CHARS) — splits a long paste into ≤maxChars chunks on paragraph/newline/sentence/whitespace boundaries so the catalog extractor processes each child and unions results.
catalogTypes.js Shared catalog ingredient TYPE REGISTRY — one entry per type drives validation enum, ID prefix, FTS field set, extraction shape, per-record payloadSchemaVersion + upgraders, per-type defaultTags. Also exports the relation-kind registry and the tag-taxonomy helpers (canonicalTagKey, tagIdForKey, defaultTagsForType). Mirrored on the client at client/src/lib/catalogTypes.js.
catalogUniverseTags.js Pure transform that rewrites legacy machine universe tags (from-universe, universe:<id>) on backfilled catalog ingredients into friendly universe-NAME tags, preserving user tags + the structured catalog_ingredient_refs link. Used by the boot-time repair and the bible→catalog backfill.
comicScriptParser.js Marvel/DC-format comic script parser.
composeStyledPrompt.js Compose user prompt + negative with an optional style preset.
scriptVideoCompiler.js Compiles a scene script + bible into beat-level continuous-video clip specs (duration/frame-grid snapping, byte-stable descriptor injection, chain-length fresh-cut rule).
creativeDirectorPresets.js Locked-at-creation aspect ratio + quality presets for the Creative Director.
creativeLatitude.js The IP-latitude clause every creative LLM request carries (withCreativeLatitude, CREATIVE_LATITUDE_TOKENS), plus the one creative-vs-operational table both stamp keys are matched against (isCreativeStage for stage names, isCreativeRunSource for run source tags).
universeBibleCompleteness.js Is a universe bible entry actually described? The shared per-kind expand-field vocabulary (BIBLE_EXPAND_FIELDS, BIBLE_CORE_FIELDS) and the core/full completeness predicates the quota-burn describe job scans with. Pure.
universeMarkdown.js Pure deterministic Universe Builder world-bible export: universeToMarkdown(record) plus safe Markdown download filename helpers.
universePromptRenderers.js Renderers that turn a universe's categories map + canon into prompt context.
universeVisualStyle.js The style a universe contributes to an IMAGE prompt: buildVisualStyleClause(universe, {override, mode}) (curated influences.embrace tokens + a series stylePromptOverride, NEVER the free-text styleNotes, which is writing-stage direction), universeAestheticLine (the labeled variant canon sheet/LoRA renders lead with), universeVisualStyleTokens, splitPromptTokens, stripStyleClause(text, clause) (removes the copy the browser already prefixed, so the compiler keeps the LEADING one — matched on the joined clause so a token with its own punctuation like M.C. Escher still matches) and mergeNegativePromptTokens (token-level union of comma-joined negatives).
writersRoomPresets.js Writers Room enums (WORK_KINDS, WORK_STATUSES, ANALYSIS_KINDS).
writersRoomStylePresets.js Curated style presets for storyboards + universe.

Prompt & AI

Module Purpose
aiToolkit/ Vendored toolkit (providers + runner + prompts + status). See aiToolkit/index.js. aiToolkit/endpointGuard.js is the public SSRF / key-exfiltration guard for provider endpoint URLs (evaluateSecretEndpoint / assertSecretEndpoint) — import it from there, not from internal/.
aiToolkitState.js Module-level singleton for the toolkit instance shared by the providers/runner/promptService shims — setAIToolkitInstance / requireToolkit (throws AI_TOOLKIT_NOT_INITIALIZED) / getAIToolkitInstance (no-throw for cleanup paths).
antigravity.js Antigravity (agy) CLI provider helpers — id/sentinel constants (ANTIGRAVITY_CLI_ID, ANTIGRAVITY_CONFIGURED_DEFAULT, LEGACY_GEMINI_*), isAntigravityCommand/isAntigravityCliProvider predicates, and ensureAntigravityPrintArgs(args, {model, effort})/ensureAntigravityTuiArgs(args, {model, effort})/stripAntigravityUnsupportedArgs argv normalizers. parseAntigravityModelList(stdout) parses agy models rows — accepts both the modern <id>\t<Label> shape and the older bare-id-per-line one, deduped, sentinel dropped (mirrored in the vendored toolkit's internal/antigravity.js; used by both the provider-catalog refresh and Image Gen's agy model picker). isAntigravityModelId(id) is the same id shape as a bare predicate, for spawn sites building an agy --model argv from a value no route schema bounded. The strip drops legacy Gemini --yolo/-m/--output-format but PRESERVES the long --model (agy accepts it as a per-session flag, so a user-baked pin is a real selection and suppresses the injected one); the two builders inject --model/--effort from the per-run overrides, always ahead of the trailing --print marker whose value is the prompt.
llmText.js Pure LLM-output text helpers — stripCodeFences (unfence a model reply) and parseLLMJSON (unfence then JSON.parse with a descriptive throw). Below the provider layer, so lib can clean model output without importing provider orchestration.
providerCooldown.js Provider bench policy — resolveProviderBench(analysis)null (don't bench) / a usage-limit marker / an unavailable marker with the per-category cooldown from COOLDOWN_MS_BY_CATEGORY. Declines to bench request/response-specific categories (isRequestSpecificCategory / isSchemaTypeCategory) so one bad model id or off-shape response can't take a healthy provider offline. Shared by services/promptRunner.js (prompt cascade) and services/agentFinalization.js (finished CoS agent run) so both bench a category for the same window. Pure.
reviewerConfig.js Review-Loop reviewer vocabulary (split out of cosValidation.js, #5702; Zod-free): the reviewer roster + aliases (REVIEWER_VALUES / REVIEWER_ALIASES / DEFAULT_REVIEWER), the local-LLM / PortOS-only / model-capable / effort-selectable subsets, the slug→CLI-binary map (REVIEWER_CLI_BINARIES, isCliReviewer, reviewerCliBinary), the keyed model/effort/max-rounds pin normalizers + resolvers (normalizeReviewers, normalizeReviewerModels, normalizeReviewerEfforts, resolveReviewerConfig, resolveClaimReviewerConfig, KEYED_REVIEWER_PINS), the override-key rosters that say when a task has pinned its own reviewers (REVIEWER_OVERRIDE_KEYS — everything the picker writes and its reset clears; REVIEWER_LIST_OVERRIDE_KEYS / hasReviewerOverride — only the keys that can change the resolved LIST), and the emitters that render a reviewer set into slashdo argv (buildReviewWithArgs, buildReviewersCsv) and into agent-prompt notes (buildReviewerPinNote, buildReviewerEffortNote). Re-exported flat by cosValidation.js, so existing validation.js imports keep resolving.
providerPrerequisites.js Can a provider run on this host AT ALL — providerPrerequisites(provider, { runtime, gatewayKeySet }){ met, missing: [{ code, label }] } (CLI binary on PATH, API key stored for a public endpoint, the sibling key a gateway-backed wrapper inherits from the API record of its own gateway id unless it carries its own), plus providerRuntimeKey (null for an API provider, for a command carrying an explicit path, and for a provider with its own PATH in envVars — the runtime table only answers "does the BARE binary resolve on PortOS's PATH?", which is not those providers' question), isPrivateNetworkEndpoint (mirror of the client copy: loopback/RFC1918/tailnet CGNAT + ULA/.ts.net/single-label hosts need no key) and describeMissingPrerequisites. runtime: null = NOT PROBED and never counts as missing. Feeds BOTH GET /api/providers and the fallback chain in aiToolkit/providerStatus.js (via services/providerPrerequisites.js), so a NEEDS SETUP card and the router read one computation (#4611). ROUTING_BLOCKING_CODES/blocksRouting(missing) narrow what ROUTING may act on to the missing binary. Stored, inherited, and environment-backed credential findings stay presentation-only here because the server cannot assume the eventual process environment; the client card classifies sanitized env metadata through tri-state lookups (#4612). Pure.
tuiShellLaunch.js buildTuiShellLaunch(provider){ commandLine, env } for launching a TUI provider by hand in a Shell session (the AI Providers card's "Launch in Shell" button). Resolves the command via tuiHandshake.js#buildTuiInvocation (so the vendor posture flags and --model/--effort injection match a real TUI spawn) and the env via cliChildEnv.js#composeProviderEnv. The env is why this is server-side and the deep link carries only a provider ID: a TUI provider's backend lives in envVars (ANTHROPIC_BASE_URL for an Ollama-backed or Bedrock claude, OPENCODE_CONFIG_CONTENT for an OpenCode wrapper), so a shell handed only the command line would run the right binary against the vendor cloud instead of the local daemon the user configured — and those values are secret, so they can't ride a URL. Returns null for a non-TUI provider. Must be given a RAW provider, never a client-sanitized one (redacted '***' env reads truthy).
tuiHandshake.js Shared TUI invocation + paste-handshake constants. Also owns SUBMIT_KEY — the single Enter byte every PTY writer sends, whether it's submitting a pasted TUI prompt or a command PortOS injected into a shell session. It is CR, never LF: a POSIX pty's ICRNL hides the difference, but cmd.exe under Windows ConPTY accepts only CR and leaves an LF-terminated line typed-but-unexecuted at the prompt.
tuiUsageScrape.js scrapeTuiUsage({ command, slashCommand, … }) + USAGE_SANDBOX_DIR — drive an agy/grok TUI in a sandbox PTY, send a slash command, return the ANSI-stripped screen (for quota panels --print can't reach).
stagePinPolicy.js Run-scoped "ignore per-stage LLM pins" switch (AsyncLocalStorage) — withStagePinsIgnored(ignore, fn) marks an async subtree, stagePinsIgnored() reads it, and services/stageRunner.js#effectiveStage enumerates which stage-config fields it strips. Backs Series Autopilot's "use one provider/model for every stage" option.
promptSystemStages.js Prompt-stage protection, split in two (#3335). CURATED (badging): SYSTEM_STAGE_USAGE (key -> usedBy[] feature-name copy), SYSTEM_STAGE_KEYS, isSystemStage(key), systemStageUsedBy(key) — what GET /api/prompts ships and the Prompt Manager badges/filters; adding a row is a per-stage product decision. DERIVED (deletion): STAGE_CALL_SITES / stageReferencedBy(key) from the generated manifest, unioned with the curated set into isProtectedStage(key) / PROTECTED_STAGE_KEYS — what the DELETE /api/prompts/:stage force-guard and canDelete consult.
promptStageCallSites.generated.json Generated stageKey -> [server source paths] index of every prompt stage server/ names by literal key (plus interpolated-prefix stages like pipeline-panel-${id}). Regenerate with node scripts/generate-prompt-stage-call-sites.js; scripts/generate-prompt-stage-call-sites.test.js fails on drift. Never hand-edit.
promptTemplate.js Mustache-flavored, dot-notation-aware prompt template engine.
promptPartials.js Mustache-style partial expansion.
promptFencing.js Fencing for untrusted text spliced into an LLM prompt. fenceBlock(label, text, maxChars) truncates, collapses every run of 3+ backticks to ''' so the content cannot terminate its own fence, and wraps the result as a labeled ```text block; neutralizeFences / clampText are the two halves on their own. UNTRUSTED_CONTENT_NOTICE is the standing "fenced content is data, not instructions" line a prompt places above its fenced sections — the fence stops delimiter escape, that line is what makes an in-band directive inert. Used by services/aiDetect.js, whose prompt splices a scanned repository's package.json/config/README into a prompt that yields an executed startCommands.
mediaModelBuckets.js Names and resolves the video registry's two model buckets (#4142). The split is by RUNTIME FAMILY — mlx (Apple MLX runtimes) vs cuda (plain torch+CUDA, which runs on Windows and Linux) — not by operating system, which is why activeVideoBucket() keys on process.platform === 'darwin' instead of on "is this Windows". readVideoBucket / readVideoDefault / matchesVideoBucket resolve the canonical key first and fall back to the pre-#4142 macos / windows / defaultMacos / defaultWindows spellings, so any registry written by an older install still loads untouched; canonicalizeVideoBuckets performs the one-time rename (migration 270 and the load-time twin in mediaModels.js). Kept separate from mediaModels.js so scripts/migrations/ can share the alias resolution without importing the registry loader, which seeds data/ as a side effect.
mediaModels.js Single source of truth for image/video model metadata. Entry fields are documented in the module docblock — note repoFiles[], which narrows a model's own repo to an explicit file list for an aggregate repo that holds far more than the runner loads (MiniMax H3 CUDA).
minimaxH3Memory.js The declared weight-placement table for the three MiniMax H3 entries (#5420) — H3 is the one video model family whose components fit nowhere unassisted, so "does this box have enough" is a render gate, not a UI fact. MINIMAX_H3_MEMORY_PROFILES maps entry id → { shippedRepo, shippedRevision, profiles }, each profile carrying an honest minMemoryGb host floor and (CUDA only) a minVramGb device floor, ordered best-first. Every capacity number is HOISTED from what already existed — the CUDA tiers are resolve_offload_profile()'s own thresholds in scripts/generate_minimax_h3_cuda.py, the host floors are the entries' memoryGb — the sole new number being MINIMAX_H3_HOST_RESERVE_GB, a policy reserve held back for the OS. applyMiniMaxH3MemoryProfiles(list) is the load-time backfill (twin of migration 317) and guards BOTH repo and revision, like the speed-profile decorator. selectMiniMaxH3MemoryProfile({ model, totalMemoryGb }) picks the best profile the HOST can hold (VRAM is the runner's call — the server has no synchronous device view); miniMaxH3MemoryDeclineReason() RETURNS the fail-closed reason so the render path can 400 it and a status surface can show it, and returns null on an UNMEASURED host — "not measured" is a deferral to the runner, never the same as zero. validateMiniMaxH3MemoryProfileTable / sanitizeMiniMaxH3MemoryProfiles warn + strip a hand-edited table (NaN floor, duplicate/reserved id, mis-ordered tiers) at load.
videoContinuity.js How chunk N+1 of a chained video render is conditioned on chunk N. resolveContextFrames(requested) normalizes the tail-window size (absent → DEFAULT_CONTEXT_FRAMES = 22 ≈ 1s @ 24fps; an explicit 0 is preserved as "last frame only", NOT collapsed into the default) and clamps to MIN_CONTEXT_FRAMES..MAX_CONTEXT_FRAMES. resolveContinuityStrategy({model, contextFrames}) picks 'window' (LTX-2 extend_from_video conditioned on the prior chunk's last N frames — motion, not just a pose) or 'frame' (extract the last frame, run i2v), degrading to 'frame' on any runtime outside CONTEXT_WINDOW_RUNTIMES rather than rejecting. extendLatentFrames / extendedPixelFrames convert across the VAE's LATENT_FRAME_STRIDE (8 pixel frames per latent), contextPrefixFrames({totalFrames, extendLatents}) measures how much of an extend render is echoed context to trim back off before stitching (0 = leave it alone), and tailWindowStartFrame gives the cut index for the window itself. Pure — importable from prepareParams.js without dragging in local.js. Mirrored for the picker in client/src/lib/videoGenParams.js, pinned by videoContinuity.parity.test.js.
videoPromptLinter.js Deterministic lint pass for continuous-video clip prompts (part of #6217, independent of scriptVideoCompiler.js #6225 by interface — lints already-built prompt strings plus caller-supplied framing/reference metadata rather than a compiler-shaped clip). lintClipPrompt(clip, {bible, maxLength}) checks a single clip: a cutType: 'continue' clip must open with "Hard cut to <framing>:" and use a framing distinct from previousFraming; every references entry (`{kind: 'cast'
videoDisclosure.js Video Gen provenance/licensing + backend policy-scope facts (#3674). VIDEO_MODEL_DISCLOSURES maps each shipped video model id to { shippedRepo, disclosure } (model card URL, weights license, runtime license, pinned-snapshot download size in decimal GB, review date) — every value checked against a primary upstream source, and any fact that could not be established is OMITTED so the UI renders "Unknown" instead of guessing. applyVideoDisclosures(list) is the load-time backfill (twin of migration 237) with the same preservation guards: an existing disclosure key wins, a custom id is skipped, and a repo pointed at a fork keeps Unknown. VIDEO_BACKEND_DISCLOSURES / videoBackendDisclosure(id) state where inference runs (execution: local or hosted) and whose policy applies — execution facts only, never a restrictiveness ranking. APACHE_2 / GEMMA_TERMS are the shared license descriptors videoTextEncoders.js reuses, so a license-text correction reaches both tables from one edit.
videoDraftDecoders.js Preview-fidelity ("draft") video decode (#5423). VIDEO_DRAFT_DECODERS declares each entry id → a separately downloaded decoder asset, pin-guarded on repo AND revision; applyVideoDraftDecoders(list) is the load-time backfill and validateDraftDecoderTable / sanitizeDraftDecoders warn + strip a hand-edited row (missing pin, a multi-shard or path-traversing file list, a runtime whose builder emits no draft flags) so a full decode can never report itself as a draft one. DRAFT_DECODE_FULL ('full') is a deliberate NO-OP — isFullDecode(id) makes absence and that sentinel the same request, so a full-decode render builds byte-identical spawn args. draftDecodeDeclineReason({ model, decodeId, models, runtimeRevision, assetCached }) RETURNS (never throws) the reason a draft decode does not apply — the model is a delivery target in the finish graph (isDeliveryVideoModel), it declares no decoder, the installed runner checkout is not the revision the asset was verified against, or the weights are not downloaded — because a knob that only makes a render cheaper must degrade rather than 400 a submitted job; resolveVideoDraftDecoder() returns the concrete asset or null. publicVideoDraftDecodeOptions(model) is the picker payload (empty for a model with no decoder, so the client renders no control) and downloadableVideoDraftDecoders(list) the download targets. The table ships NO entry, and as of 2026-08-30 that is a decision rather than a gap (ADR): the shim substitutes one file into upstream’s checkpoint root under a STRICT key match, so a candidate must be a complete unquantized full-VideoVAE checkpoint — which every genuinely light decoder (TAE, quantized repack, decoder-only head) is not.
videoFinishProfiles.js Draft → delivery ("Finish") relationships between video models (#3696). VIDEO_FINISH_PROFILES declares each fast draft entry id → { shippedRepo, finishModelId }, only for pairs that share a runtime, base repo and supported modes (the same weights at a different step budget), so re-rendering the draft's seed reproduces its composition instead of re-rolling it. applyVideoFinishProfiles(list) is the load-time backfill (twin of migration 238) with the usual preservation guards (existing key wins, custom id skipped, forked repo skipped); validateFinishProfileGraph(list) returns the graph problems (missing / self-referencing / chained target, runtime / repo / supportedModes mismatch) and sanitizeFinishProfiles(list) warns + strips them at load so a typo can never surface a Finish button targeting nothing. finishTargetForModel(model, availableModels) resolves the delivery entry scoped to what this install can run.
videoSpeedProfiles.js Named, pre-validated sampler schedules a user can pick instead of hand-tuning steps/CFG (#4875). VIDEO_SPEED_PROFILES declares each entry id → { shippedRepo, shippedRevision, profiles }; applyVideoSpeedProfiles(list) is the load-time backfill (twin of migration 295) and guards BOTH repo and revision — unlike the finish-profile decorator, because a sampler schedule is revision-sensitive in a way a draft→delivery edge is not. SPEED_PROFILE_DEFAULT_ID ('quality') is a deliberate NO-OP so a default render builds byte-identical spawn args and stamps no extra history fields; isDefaultSpeedProfile(id) makes absence and that sentinel the same request. speedProfileDeclineReason({ model, profileId, mode }) RETURNS (never throws) the reason a profile does not apply — wrong mode, unpinned weights, samplerLocked model, unknown id — so a knob that only makes a render faster degrades instead of 400ing a submitted job, and resolveVideoSpeedProfile() returns the concrete override or null. resolveVideoSpeedProfileForModes({ model, profileId, modes }) lifts that decline check to a CHAINED render — a chain is one clip whose chunks run in different modes (chunk 0 the request's, chunks 1+ extend on a window-continuity chain or image on a frame hop), so the profile applies to every chunk or to none rather than seaming a fast chunk onto quality ones. resolveVideoSampler({ model, steps, guidanceScale, speedProfile }) is the SINGLE precedence rule (samplerLocked > profile > explicit request > registry default), shared by the render path and the chained-render ETA so the two cannot drift. validateSpeedProfileTable(list) / sanitizeSpeedProfiles(list) warn + strip a hand-edited profile (NaN steps, duplicate/reserved id, samplerLocked collision) at load rather than letting it spawn a broken render. What the RUNNER could actually apply — is the pinned pipeline new enough for enable_teacache, is the distilled adapter in the pack — is probed by scripts/generate_ltx2.py and reported back on a SPEEDPROFILE: line.
videoModeProfiles.js The shipped supportedModes fact per video runtime (#3737), so "which modes does this model support?" has one answer on the registry entry instead of 25+ runtime comparisons. VIDEO_RUNTIME_MODES maps each runtime to the semantic modes its helper can actually render, including minimax_h3_ref2va as a2v-only; VIDEO_BASE_MODES remains the non-audio fallback for an unknown runtime. resolveVideoSupportedModes(entry) and applyVideoSupportedModes(list) provide the read-time decoration used by mediaModels.js#getVideoModels.
videoDurationProfiles.js Pure pinned duration/frame contracts shared by model-registry upgrades and migrations. LTX-2.5 A2V follows the full uploaded audio, rounds up to its 8n+1 temporal grid, and tops out at 1017 frames under the API's single-pass boundary.
videoReferenceModes.js The i2v reference-mode contract (#4874) — what a supplied conditioning image PROMISES. I2V_REFERENCE_MODES (anchor | inspire) + I2V_REFERENCE_MODE_OPTIONS (the label + the promise sentence the UI prints), I2V_REFERENCE_MODE_RUNTIMES (only ltx25 can honor inspire — it needs per-image conditioning strength), INSPIRE_DEFAULT_IMAGE_STRENGTH, plus normalizeI2vReferenceMode / isDefaultI2vReferenceMode / isKnownI2vReferenceMode / runtimeSupportsI2vReferenceMode / i2vReferenceModeLabel / resolveI2vReferenceStrength and the one rule i2vReferenceModeViolation({ model, mode, referenceMode, hasFirstImage }){ code, message } or null. Pure (no ServerError) because it is MIRRORED to client/src/lib/videoReferenceModes.js; videoGen/modeContract.js#videoReferenceModeError wraps it for the route + render boundaries.
videoTextEncoders.js Swappable prompt conditioners for local video runtimes. MiniMax H3 reads the unnormalized hidden state after Qwen3-VL language layer 49 (layers 50-63, the final norm and lm_head are never evaluated), so any checkpoint carrying the same embedding + layers 0-49 + vision tower is a drop-in conditioner — swapping it changes how the model reads a prompt without touching the diffusion weights. TEXT_ENCODERS_BY_RUNTIME declares the shipped options per runtime (pinned repo/revision plus an explicit files LIST — one repackaged safetensors, or just the shards of an upstream checkpoint that carry parameters the loader actually builds; in code rather than the media-models registry so a stale data/media-models.json can't name a file the runner can't map); videoTextEncoderOptions(model) returns the TRUE list stock-first (it deliberately does NOT collapse a one-entry runtime to [] — that is a presentation rule, and folding it in here would change what the server believes a model supports and empty the "offers …" list in the error; TextEncoderPicker owns the hide-when-there-is-no-real-choice check), isStockTextEncoder(id) makes absence and the stock sentinel the same request, resolveVideoTextEncoder(model, id) returns null for the stock choice or throws VIDEO_TEXT_ENCODER_UNSUPPORTED (with the non-throwing supportsVideoTextEncoder + videoTextEncoderUnsupportedError split out so the request path can reject before staging uploads), and downloadableVideoTextEncoders() (deduped by id — the table is keyed by RUNTIME, so one conditioner can be offered by two) / downloadableVideoTextEncoder(id) feed the /api/video-gen/text-encoders/:id/(download|repair) lane. Two loader-mechanics fields exist because a ComfyUI-packaged conditioner is namespaced differently from the HF checkpoint the MLX port matches: keyPrefixMap (model.model.language_model., visual.model.visual.) is applied to every checkpoint key by scripts/generate_minimax_h3.py BEFORE the pinned loader sees it — no fork of the pinned runtime — and finalNormKey names where the runner synthesizes a ones-filled norm.weight for a checkpoint published without one (correct upstream, since H3 reads the state before the norm, but the pinned loader refuses to load with any parameter missing). Both are absent for an UPSTREAM Qwen3-VL-32B checkpoint, which already uses the loader namespace and ships its own norm. A candidate must BE Qwen3-VL-32B (the shim reuses upstream's config/tokenizer/processor) — a different Qwen generation is not a substitute however close its conditioning width looks; see docs/features/video-text-encoders.md. publicTextEncoderOption(entry) is the client projection and deliberately drops both, so the UI can't reimplement the remap. The ltx25 table (#4320) uses a third mechanic, configOverrides, because an LTX-2.5 pack's OWN Gemma 4 tower wins over --gemma inside the pinned fork: the substitution is a standalone shim directory whose generated config.json is the substitute's own with these keys merged over it (only ever the model_type label a unified checkpoint gets wrong — never text_config/quantization), and a candidate must BE Gemma 4 12B at 48 layers / hidden 3840 / vocab 262144 / k_eq_v. verified gates a substitute out of BOTH lanes (picker AND download) until it has been A/B-rendered against its runtime's stock conditioner — required on every non-built-in entry and fail-closed on absence, so a new entry is unreachable until someone states a verdict; both ltx25 substitutes are verified: false today. declaredVideoTextEncoders() is the UNFILTERED table for shape/invariant checks only — never the render or download path, and videoTextEncoderRuntimes() enumerates the table's runtime keys so parity/shape tests cover every runtime rather than the one that happened to exist when they were written.
providerModels.js Provider model resolution sentinels + helpers (CODEX_CONFIGURED_DEFAULT / ANTIGRAVITY_CONFIGURED_DEFAULT / GROK_CONFIGURED_DEFAULT / KIMI_CONFIGURED_DEFAULT, resolveCliModel, filterSelectableModels, Bedrock/OpenCode model mappers, localRuntimeNamespace(provider) — the OpenCode namespace only when it names a LOCAL daemon, i.e. the composed "namespace and not a hosted gateway" test that cliChildEnv.js, localProviderRuntime.js and providerVendors.js all key on, OPENCODE_PUBLIC_REVIEW_AGENT — the read-only OpenCode agent a no-tool public-review stage runs as, kept in this leaf because providerVendors.js must not import opencodeConfig.js, parseOpencodeConfigContent — the shared "is this stored OPENCODE_CONFIG_CONTENT usable?" read — plus opencodeConfigIsLocalOnly / opencodeProviderIsLocalOnly, the ONE locality rule providerVendors.js (gate eligibility) and cliChildEnv.js (public-review env allowlist) must not disagree about: if eligibility says yes where the allowlist strips the config, the stage spawns against the user's own ~/.config/opencode with tools intact while still reporting an enforced tool-free gate, normalizeClaudeModelId / resolveClaudeCliModel — the Claude-argv chokepoint that rewrites a dotted first-party version (claude-fable-5.1) to the dashed id Claude Code actually serves before the Bedrock mapping runs, model-flag scan helpers incl. stripBrokenModelFlags, isCodexProvider, isKimiProvider, isAntigravityProvider, isCursorProvider) plus reasoning-effort helpers for the claude/codex/agy/cursor CLIs (CLAUDE_EFFORT_LEVELS / CODEX_EFFORT_LEVELS / ANTIGRAVITY_EFFORT_LEVELS / CURSOR_EFFORT_LEVELS / EFFORT_LEVELS, effortLevelsForProvider, resolveCliEffort — clamps an out-of-range effort to the nearest level the target CLI accepts rather than dropping it, so a value saved against a wider ladder survives a provider switch — hasEffortFlag, buildEffortArgs — the one emitter of --effort <level> / -c model_reasoning_effort=<level>, and deliberately silent for cursor — and foldCursorEffortIntoModel, which carries a cursor level inside --model as Cursor’s own variant syntax (gpt-5[effort=max]) because cursor-agent has no --effort flag) plus codex startup-arg helpers (CODEX_EFFORT_KEY, CODEX_UPDATE_CHECK_KEY, hasCodexUpdateCheckConfig, buildCodexStartupArgs — the one emitter of -c check_for_update_on_startup=false, spread by every codex spawn builder to disable the blocking startup update modal) plus PORTOS_CLI_CONFIG_KEYS / isPortosSuppliedConfigKey — the exhaustive list of -c <key>=<value> config keys PortOS injects, read by the cli-config-invalid error analyzer to tell a rejected PortOS override apart from a bad line in the user's own CLI config file.
providerVendors.js PROVIDER_VENDORS — one row per coding-agent CLI/TUI vendor (claude/codex/antigravity/opencode/grok/kimi/cursor, plus a deliberately-incomplete legacy gemini-cli row), consumed by every dispatch site that used to hand-roll its own vendor if-chain across ~8 branches in 5 files (#3618): applyCommandDefaults/prepareCliPrompt (re-exported from tuiHandshake.js/cliProviderArgs.js), buildVendorCliArgs/buildVendorSpawnConfig (consumed by cliProviderArgs.js#buildCliArgs / agentCliSpawning.js#buildCliSpawnConfig), inferTuiCommand (re-exported from tuiHandshake.js), and injectTuiModelAndEffort — the shared antigravity-validates-the-pair-vs-everyone-else --model/--effort injection used by both tuiHandshake.js#buildTuiInvocation and agentTuiSpawning.js#buildTuiSpawnConfig, replacing a second copy of that split that had already drifted once before this file existed. Doesn't rewrite any vendor's argv-building logic — that stays in antigravity.js/grok.js/kimi.js/cursor.js/codex.js. Dependency-light on purpose, mirroring those files.
modelCapabilityTests.js Catalog + scoring for the CAPABILITY tests on /models/performance (run by services/modelCapabilityTests.js): CAPABILITY_TESTS (sandbox repair / image analysis / story outline / fiction scene / rhetoric evaluator, each gated on the capability badges the install catalog already shows), applicabilityFor + applicableTests (applicable / not-applicable / unknown — an UNCLAIMED capability is never a failure, and null capabilities mean the runtime reported none, which is distinct from []), scoreKeywords + VISION_FIXTURE_KEYWORDS (required vs bonus terms, word-boundary matched with a negation guard so "no dog" doesn't score a dog), scoreStoryBeats + HEROS_JOURNEY_BEATS (coverage AND ordering, judged only over the beats present), scoreSandboxRepair (verdict from observed disk facts — editing the test instead of the module fails outright), formatAgentEvent (one agent stream frame → a transcript line), rollUpVerdict, and the verbatim CAPABILITY_TEST_PROMPTS / SANDBOX_TASK_PROMPT the consent gate shows. Pure, so any stored transcript can be re-scored with no provider call.
modelPricing.js Per-model API billing rates for the /devtools/usage cost estimates — resolveModelRates(providerId, model) (exact → family regex → provider default → blended fallback, with a matched tier; also derives cacheReadPer1M/cacheWritePer1M from the input rate via per-family multipliers), isFreeProvider (ollama/lmstudio/ollamaBacked/localhost = free), estimateCostUsd(tokensIn, tokensOut, rates, cache?)tokensIn is UNCACHED input; cache tiers are priced separately via the optional 4th arg — and PRICING_AS_OF. Informational only (PortOS runs on subscriptions); still excludes batch/long-context tiers.
usageRange.js resolveUsageRange({ period, from, to }) — pure period→inclusive-YYYY-MM-DD range resolution for the usage cost report (explicit dates win; all unbounded; default 7d).
subscriptionSavings.js Subscription-vs-API savings math for the usage page — resolveSavingsWindow (clamps an open-ended report range to today / first activity day), prorateMonthlyCost (monthly plan price → this window's share, DAYS_PER_MONTH, capped by MAX_MONTHLY_COST), savingsPercent / costMultiplier (null, never 0, when the comparison is undefined), attributeReportCostToFamilies (groups report rows by their stamped family), roundCents (the one money rounder), and buildSubscriptionSavings({ entries, range, unmatchedApiCost }) → per-family rows + totals. Pure.
credentialRegistry.js Pure catalog of PortOS credentials (CREDENTIALS, CREDENTIAL_IDS, CREDENTIAL_TIERS) — one entry per key/token an install can use (id, label, unlocks, tier, getUrl, envVars, settingsPath, configurePath, optional feature). Sits beside instanceFeatureRegistry.js so the two lists stay greppable together. Runtime resolution (settings / repo .env / inherited process.env / CLI / instance config) lives in services/credentialInventory.js. The Settings > Credentials page never receives a value or masked prefix.
instanceFeatureRegistry.js The registry of optional per-install features (INSTANCE_FEATURES, INSTANCE_FEATURE_IDS, APP_FEATURE_IDS) — pure data, so validation.js derives its feature schemas from it and navManifest.js can be checked against it without a service→lib inversion. Runtime resolution (stored override → auto-detection → defaultEnabled) lives in services/instanceFeatures.js. A feature id tagged on a nav entry hides that page from ⌘K and the sidebar when the feature is off.
providerFamilies.js Subscription-quota FAMILY identity — PROVIDER_FAMILIES ({ id, label, matches } for claude/codex/agy/grok), PROVIDER_FAMILY_IDS, familyLabel, familyForProvider(config) → family id or null (local-runtime wrappers and API-only providers belong to none). The pure half of the registry services/providerUsage.js attaches quota fetchers to, so cost attribution and route validation can ask "which plan is this provider on?" without importing the PTY-scrape graph. Distinct from providerVendors.js, which is argv-shaped and includes vendors with no subscription quota.
fleetQuotas.js Unifies subscription-quota readings across federated instances — one plan, several machines, each able to read only its own local CLI. sanitizeQuotaCards bounds a peer-supplied payload to the wire shape; mergeFleetQuotaCards(localCards, peerEntries) folds every peer's reading into this install's cards, taking the FRESHEST reading per limit key (the meters are account-wide, so summing them would multiply one allowance) and SUMMING activity counts (those are per-machine, which is why the provider captions them "does not include other devices"); fleetNote writes the caption naming what was combined. metrics[] is left local — its values are prose, not addends. Fed by services/providerQuotaShare.js (this machine's readings, persisted) and services/peerUsage.js (the usage sync category that carries them).
harnessOutput.js Parsers for what a coding-agent HARNESS prints about itself: parseHarnessVersion(stdout) (the one semver run in a --version banner, null when unparseable), compareHarnessVersions(a, b) (the null-guarding wrapper around versionUtils.js#compareSemvernull when either side is unparseable, so a version that did not parse never reads as "out of date"), parseHarnessModels(harnessId, stdout) + HARNESS_MODEL_PARSER_IDS (OpenCode's provider/model lines and Grok's bulleted list are parsed here; Antigravity and Cursor DELEGATE to antigravity.js#parseAntigravityModelList / aiToolkit/internal/cursor.js#parseCursorModelList, which the provider-card refresh has used for far longer), MAX_MODELS, and parseNpmLatestVersion. Pure: the service layer runs the child and hands the captured stdout here, so the vendor output shapes are pinned by table-driven tests instead of by running six real binaries in CI. Model ids come back in the exact spelling --model takes — namespaces kept where the vendor keeps them. Consumed by services/providerRuntimeInstaller.js and services/harnesses.js.
providerGateways.js PROVIDER_GATEWAYS — one row per hosted OpenAI-compatible gateway an OpenCode CLI/TUI wrapper can front-end (orcarouter, openrouter), plus PROVIDER_GATEWAY_IDS, gatewayById, isGatewayNamespace(ns) and gatewayForProvider(config) → row or null. Each row's id is simultaneously the OpenCode provider namespace, the gatewayBacked marker value, and the id of the sibling api record that owns the key — so the sibling lookup is providers[gateway.id] and an OrcaRouter key can never satisfy an OpenRouter wrapper. Replaces the orcarouterBacked boolean + literal 'orcarouter' that had been hand-copied across ~15 server and client files (namespace resolution, the OpenCode config builder, both zod schemas, the model-fetcher table, the sibling-key attach, the prerequisite check, and the two "not a local runtime" carve-outs in cliChildEnv.js/localProviderRuntime.js). Reads the legacy per-gateway boolean FOREVER, so stored records are never rewritten. Distinct from a local runtime (ollamaBacked, vllmBacked, …): remote, always authenticating, and no thinking toggle. Deliberately mirrored in aiToolkit/internal/gateways.js (the vendored toolkit may not import out) and client/src/utils/providers.js (the browser cannot import server code) — providerGateways.parity.test.js fails when the first two drift. Dependency-light: imports nothing.
providerTranscriptUsage.js Parsers for the session files the coding CLIs write to disk (0 tokens to read) — parseClaudeTranscript (~/.claude/projects/<cwd-slug>/*.jsonl), parseCodexRollout (~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl), parseGrokTurns/parseGrokChatHistory/decodeGrokSessionDir (~/.grok/sessions/<encodeURIComponent(cwd)>/<id>/), parseAgyTranscript/parseAgyHistory (~/.gemini/antigravity-cli/), claudeProjectSlug, totalTranscriptTokens. Each de-duplicates a format hazard that otherwise inflates counts badly: Claude repeats one response across several lines sharing a message.id, Codex's total_token_usage is cumulative and repeated, grok's turn_completed.usage has shipped in both per-prompt and cumulative shapes (detected and delta'd, never summed raw) while its _meta.totalTokens is context occupancy and never billed. Antigravity writes no token fields at all, so its parser returns chars for the caller to estimate from. Each parser returns per-model buckets (byModel) plus the message keys it counted (countedKeys), and accepts an exclude set — that is what stops two overlapping PortOS runs from both billing the same messages. Tolerant of truncated (mid-write) files; consumed by services/usageReconciler.js.
opencodeCatalogCache.js Primes the on-disk catalog opencode models prints from — primeOpencodeCatalogCache() fetches OpenCode's api.json with Node's fetch and atomically writes $XDG_CACHE_HOME/opencode/models.json (~/.cache when unset). OpenCode refreshes that file from a forked task whose failures it swallows (opencode models --refresh still prints Models cache refreshed) and its HTTP client has no Happy Eyeballs, so a host advertising an unreachable IPv6 default route freezes the catalog indefinitely while other machines on the same account list newer models. Refuses to fetch or write when OPENCODE_MODELS_PATH / a custom OPENCODE_MODELS_URL / OPENCODE_DISABLE_MODELS_FETCH means PortOS cannot be sure which file OpenCode reads, when the file is under five minutes old, or when the body did not parse as a catalog — a stale list beats an empty picker. Never throws; the caller probes either way.
opencodeConfig.js OpenCode config builder — buildOpencodeEnvVars(provider, model) builds dynamic OPENCODE_CONFIG_CONTENT declaring model ids under the namespace the provider's marker selects: a local runtime (ollama / mtplx / llama / vllm / sglang, bare ids) or a hosted gateway from providerGateways.js (vendor/model ids kept whole). Fixes --model rejection. Also attaches the key for a key-bearing namespace, and pins small_model to the run model for a gateway so OpenCode's own side calls (titles, summarization) can't land on its built-in default — a billed model the operator never chose. Under a no-tool public-review profile it also applies hardenOpencodeConfigForNoTool — root permission: deny, an emptied tool map on every agent, tool_call: false on every declared model, and no MCP/plugins/share/autoupdate — which IS OpenCode's enforced tool-free recipe, since it ships no read-only argv flag (providerVendors.js pairs it with run --agent + OPENCODE_PUBLIC_REVIEW_AGENT). The harden step also copies agent.build's generation settings onto that agent, so the stage's configured thinking effort reaches the model that actually runs.
localProviderRuntime.js Which LOCAL daemon a provider talks to, and where — LOCAL_RUNTIMES (llama.cpp / Ollama / LM Studio / MTPLX / vLLM: label, binary, canonical base URL read from opencodeConfig.js rather than re-typed, manage/docs links, model-download hint), localBackendForProvider + localEndpointPort + isLocalInstanceHost (moved here from services/localModelHealing.js, which re-exports them, so the healing path and the readiness checklist classify a provider identically — loopback/bind-all only, so a LAN/Tailscale peer on port 11434 is NOT claimed as a local daemon), localRuntimeKind(provider) (the *Backed markers first, then that classifier; orcarouter excluded as a remote API), modelPinIsOffered(provider, model) (the ONE rule for validating a stored model pin against a provider record: an empty models array and a local daemon's cached snapshot are both pass-throughs, so a freshly pulled Ollama model is never rejected as "not offered"), localRuntimeForProvider(provider) → the row with the endpoint the provider ITSELF configures (OPENCODE_CONFIG_CONTENT's baseURL, ANTHROPIC_BASE_URL, or endpoint), then the OLLAMA_URL/OLLAMA_HOST/LM_STUDIO_URL override the backend managers read, then the canonical default — and null when that resolved endpoint fails isLocalInstanceEndpoint (an API provider on another machine has no local daemon to check, whatever its name says) — plus normalizeOpenAiBaseUrl. Pure; the probing half is services/providerReadiness.js. Optional setupStateDetail overrides providerReadiness's per-state prose for a runtime whose local setup is not a model cache (vLLM's is a compose project); standbyWhenStopped marks an installed runtime such as llama.cpp whose stopped state is intentional standby rather than incomplete setup.
managedDaemon.js Shared mechanism for the local daemons PortOS runs as optional PM2 processes (services/llamaServerManager.jsportos-llama-server, services/mtplxServerManager.jsportos-mtplx, services/slotstreamServerManager.jsportos-slotstream). Owns their PM2 process names — LLAMA_APP, MTPLX_APP, SLOTSTREAM_APP, and the isModelServerProcess(name) predicate over them — so a caller like the CoS health monitor can recognize a model server without importing a manager; the managers re-export those names. createDaemonWatcher({...}) supplies the common PM2 launch-line re-adoption, endpoint probe, status skeleton, bounded log view, and port-release wait while managers retain daemon-specific parsing and lifecycle policy. createDaemonLogBuffer({maxLines?}) is the bounded timestamped ring buffer of what PortOS logged around a launch, plus withPm2Logs(output) → that buffer followed by anything pm2 logs has which it doesn't already hold, deduped and re-capped (PM2's lines are a VIEW, never folded into the buffer — PM2 owns them and re-reads them every status call). pm2ArgValue(args, flag) reads one value back out of a PM2 process's recorded argv so a manager can recover a still-online daemon's launch config after a PortOS restart; null means the flag was absent, which a relaunch must leave off rather than defaulting. Also the shared idle reaper, for a daemon that cannot release its weights any other way: registerIdleDaemon({name, getIdleMs, isPinned?, isRunning?, stop}) (seeds lastUsedAt to NOW, so a hand-started daemon gets a full window; isPinned exempts user-pinned servers), markDaemonUsed(name) — call on real traffic, NEVER on a status poll — daemonLastUsedAt(name), daemonReleaseReason(name), idleWindowMs(minutes) (minutes → ms; 0 = never, null = not configured, kept distinct), evaluateMemoryPressurePolicy({...}) (pure policy function evaluating current state, pressure reading, and recent history), reapIdleDaemons(now?, options?) → the names stopped (stops idle daemons whose window elapsed, and runs a pressure-aware pass releasing the least recently used unpinned daemon under sustained host memory pressure; at most one daemon stopped per tick), and startIdleReaper({intervalMs?}) / stopIdleReaper() (ONE interval for all registrants, unref'd, idempotent). mtplxServerManager and slotstreamServerManager register: llama.cpp releases its checkpoint in place via --sleep-idle-seconds and must NOT be stopped for it. Deliberately mechanism only — what a launch line means and when a daemon may start is exactly what differs between the two.
mtplxModels.js listMtplxCachedModels({command?}){models, error} from mtplx models --json (walks local directories — pulls no weights, loads no model, but see mtplxRuntime.js: on an un-warmed Homebrew wrapper the spawn ITSELF is a several-hundred-megabyte runtime download, so poll callers must gate on describeMtplxRuntime().ready first) and pickMtplxCachedModel(models) → the repo id to hand mtplx serve --model. models: null means the cache could not be READ (no binary, command failed, unparseable) and is deliberately distinct from [] (read, and empty), because services/localRuntimeSetup.js starts MTPLX on its own default in the first case and refuses with the mtplx pull command in the second. Exists because mtplx serve defaults --model to one hard-coded checkpoint and exits 1 before binding when that repo is not cached — even on a host holding a different MTP model that serves fine. Picks only entries MTPLX itself calls complete (validation.ok !== false, so a half-finished pull is not served), preferring one with a recorded mtplx_runtime.json exactness contract. describeMtplxCache(cache){state: 'unknown'|'empty'|'partial'|'ready', model, count, error} folds both into the one value services/providerReadiness.js puts on the checklist and describeRuntimeSetup picks a button from — so an empty cache is named up front instead of only inside the failure of a Start that could never work.
mtplxRuntime.js describeMtplxRuntime(binaryPath, {env?}){ready, wrapper, venvPath} — is MTPLX's own Python runtime on disk, decided by READING the binary rather than running it. Homebrew's mtplx is a shell wrapper that lazily bootstraps a version-keyed Python venv (a multi-hundred-megabyte pip install) on its first invocation, and brew upgrade re-arms it, so a status poll or an 8s-judged PM2 start is really a package download. This parses the wrapper's own VENV= assignment, honours $MTPLX_BREW_VENV the way ${MTPLX_BREW_VENV:-…} does, and tests <venv>/bin/mtplx for executability — the wrapper's own [ ! -x … ] guard, so the two cannot disagree. Anything unrecognisable (a pip install, a compiled binary, an unparseable script) reports ready: true, wrapper: false, i.e. the status quo — never a block over a parse failure.
slotstreamCatalog.js SLOTSTREAM_CATALOG — the curated mixture-of-experts checkpoints worth streaming from SSD (the technique only pays off on MoE: a dense model of the same size would stream every layer for every token). resolveSlotstreamRepo(idOrRepo) maps a catalog id or an owner/name repo id to a repo (null for anything else), slotstreamModelDirName(repo) flattens it to the single-segment cache directory whose NAME is the id a start hands --model, and selectSlotstreamRepoFiles(siblings) picks the .safetensors/config/tokenizer files a checkpoint is made of while dropping mirrored original/, GGUF, ONNX, and PyTorch copies of the same weights (which can double a 100 GB+ pull) and any name that is not a plain relative path.
slotstreamModels.js listSlotstreamCachedModels({cacheDir?}){models, error} from a local directory walk of the SSD-streaming MoE cache (no network, no model load), pickSlotstreamCachedModel(models, requested?) → the checkpoint id to hand slotstream serve --model, and planSlotstreamMemory({totalBytes?, overrideGb?}){targetGb, expectedPeakGb, expectedWarmDecodeToks, auto} so the LLMs row can show the memory plan instead of hiding it. models: null means the cache could not be READ and is deliberately distinct from [] (read, and empty), because a start never fetches weights.
recordedProjectDir.js Where PortOS remembers a container project it had to go and FIND — one .env line per stack in the INSTALL's root (PATHS.installRoot, so a worktree-booted server writes where the real install reads). readRecordedProjectDir(envVar, envPath?) / recordProjectDir(envVar, dir, envPath?) / projectDirIsSettled(envVar, env?, envPath?) / resolveRecordedProjectDir(envVar, defaultDir, env?, envPath?) are all keyed on the env-var NAME, so the vLLM and SGLang Qwen3.8-27B stacks share one implementation instead of drifting on the precedence rule — exported value (this run's decision) → the record (an earlier run's) → the stack's documented default. Read from the file on every call, never cached: a placement run writes it and the readiness poll in the same process must see it without a restart, and PortOS has no dotenv so .env reaches process.env for nobody. Writes are atomic and replace the key's line rather than appending (upsertEnvLine) — that file also holds the database password. envPath is a parameter so a test's sandbox answers instead of the developer's install. Written by services/wslProjectPlacement.js.
vllmQwenProject.js resolveVllmProjectDir() / inspectVllmQwenProject(){dir, hasProject, composeFile, hasWeights, weightsRoot} for the syv-ai/qwen38-27b-rtx3090 compose project, plus vllmStartBlockedReason(project) → the prose refusal (or null), and vllmProjectSetupState(project)ready/empty/unknown for the readiness checklist. hasWeights is tri-state: true found / false caches read and empty / null no cache readable (a docker-volume cache is invisible from a native-Win32 PortOS), and services/localRuntimeSetup.js refuses to docker compose up on anything but true so the start button can never kick off the ~20 GB prepare. Also owns WHERE the project lives, as this stack's keyed view of recordedProjectDir.js: readRecordedVllmProjectDir(envPath?) / recordVllmProjectDir(dir, envPath?) / vllmProjectDirIsSettled(), resolving VLLM_QWEN_PROJECT_DIR (this run's decision) → the record → ~/qwen-serving; envPath is a parameter so a test's sandbox answers instead of the developer's install. Directory reads plus that one config line — never docker, never a registry. Other override: VLLM_QWEN_WEIGHTS_DIR.
wslDistro.js Which WSL2 distro a native-Win32 PortOS should put Linux-side work in. detectWslProjectDir(leaf){dir, distro, home} or {dir: null, reason} (no-wsl / no-distro / internal-distro / unreadable-share), built from wsl.exe -e sh -c 'echo "$WSL_DISTRO_NAME"; echo "$HOME"' — the distro's OWN shell, because wsl --list prints UTF-16LE that a UTF-8 reader mangles while an executed program's stdout passes through byte for byte. Verifies the derived \\wsl.localhost\… path is readable from Windows before returning it (WSL running and its share answering are separate facts) and refuses a container engine's own distro (docker-desktop and friends are recreated on a reset). parseWslProbe / parseWslDistroList (NUL-stripping the UTF-16 bytes, for an error message only) are exported for their own tests; WSL_UNC_PREFIX names the share root for callers writing refusal prose. Exists so the vLLM stack places its ~20 GB of weights on the distro filesystem instead of asking a human to fill in a UNC template — every read from a C:\ checkout would cross a 9p share.
qwenAgentParsers.js The tool-call / reasoning parser flags a local runtime MUST carry to serve a Qwen3-family model to a coding agent — one table PortOS owns instead of three docs. QWEN_AGENT_PARSERS maps runtime → {toolCallParser, reasoningParser, enableAutoToolChoice} (vLLM qwen3_xml + --enable-auto-tool-choice, SGLang qwen3_coder + --reasoning-parser qwen3, llama both null — a positive "no such flag today", not a placeholder). parserFlagsFor(runtime) returns the argv fragment (always an array, so no caller type-checks) and vllmExtraArgs() its string form for the compose project's .env EXTRA_ARGS; an unknown runtime THROWS, because the failure it prevents is silent — a parser-less server answers fluently and returns tool markup as ordinary text with tool_calls: null, so the agent never touches a file. Spellings are empirical (docs/research/2026-08-21-qwen38-rtx3090-vllm.md, …-sglang-qwen38-27b.md); never auto-detect one from the chat template — that is how hermes got picked. Pure.
vllmQwenProvision.js The .env half of provisioning that same project: generateVllmApiKey(), isWsl2Engine() (win32 counts — Docker Desktop's engine IS a WSL2 VM), vllmEnvDefaults({apiKey, wsl2}) → the load-bearing tool-parser/pin-memory/alloc-conf settings, parseEnvContents(contents) → a key→value Map (keyed on mention, so a commented-out key reads as absent and KEY= as an intentional empty), and the two writers over one shared newline guard: mergeEnvFileContents(existing, defaults){contents, added, kept, effective} is additive only — an operator's existing key or tuning is never overwritten, and effective reports what the container will actually read — while upsertEnvLine(contents, key, value) REPLACES one key's line, for a value PortOS owns and re-derives (vllmQwenProject.js's recorded project directory); its replacement is a function, not a string, so a $-sequence in the value is written literally. Plus WSL2_PREPARE_MIN_BYTES / WSL2_PREPARE_CONFIG_HINT for the ceiling prepare needs (detected and warned about, never raised).
sglangQwenProject.js resolveSglangProjectDir() / inspectSglangQwenProject(){dir, hasProject, composeFile, hasWeights, weightsRoot} for the operator's SGLang Qwen3.8-27B project, plus sglangStartBlockedReason(project) → the prose refusal (or null). Sibling of vllmQwenProject.js with the same tri-state hasWeights contract (true found / false caches read and empty / null no cache readable) and the same directory-reads-only rule — never docker, never a registry. Differs in that PortOS OWNS this launch line (SGLang publishes an image but no compose project), so the refusals point at the compose file in docs/features/sglang-qwen38.md rather than at a git clone. Also this stack's keyed view of recordedProjectDir.jsreadRecordedSglangProjectDir(envPath?) / recordSglangProjectDir(dir, envPath?) / sglangProjectDirIsSettled() plus SGLANG_PROJECT_LEAF — so resolveSglangProjectDir() reads SGLANG_QWEN_PROJECT_DIR → the UNC path services/sglangQwenManager.js detected and recorded on Windows → ~/sglang-qwen38. Overrides: SGLANG_QWEN_PROJECT_DIR, SGLANG_QWEN_WEIGHTS_DIR.
sglangQwenRecipe.js The sglang serve launch line PortOS owns, per NVIDIA card class. buildSglangQwenRecipe({hw, contextLength, ssmDtype, spec, radixStrategy, host, port}){image, modelName, modelPath, cell, mambaRatio, stateSlots, flags, env}, and sglangComposeYaml(recipe) renders the docker-compose.yml from it (one source of truth; a test pins the doc against it). mambaFullMemoryRatio(...) derives --mamba-full-memory-ratio from the cookbook formula (S + D) × state_bytes / (L × kv_bytes_per_token) — load-bearing, because the cookbook default 0.9 under-sizes the GDN state pool at CoS prompt lengths and silently clamps max_running_requests. Both Qwen parsers (--reasoning-parser qwen3, --tool-call-parser qwen3_coder — NOT vLLM's qwen3_xml) are baked into every cell: getting them wrong fails silently, with the model emitting raw markup and the agent never calling a tool. sglangCellForGpu(gpu) maps a cudaCapability.js compute-cap row to a cell (SM 9.x → h200, SM ≥10 → rtx6000/rtx5090 by VRAM, Ampere → null, which is a refusal: 24 GB stays on vLLM), and sglangUnsupportedReason({platform, status, gpus}) is the prose for every no — never collapsing a probe 'unknown' into "no GPU". Pure: no filesystem, no docker, no network.
opencodeStream.js OpenCode's --format json event stream — ONE parser, shared by services/localModelAgentBenchmark.js (which wants chars/tokens) and services/modelCapabilityTests.js (which wants a readable transcript). eventPart (accepts the flat {part} and nested {properties.part} envelopes OpenCode has both used), isToolEvent / eventText, parseAgentLine / parseAgentEvents (blank and unparsable lines yield nothing rather than throwing), formatAgentEvent (one frame → a transcript line a person can read, with the path or command the tool acted on), and summarizeOpenCodeEvents (assistant chars, tool calls, and output tokens — null, never 0, when OpenCode reported no usage; tool ARGUMENTS are deliberately not counted as answer text). Pure. The runner that produces the stream is services/opencodeTask.js.
openAiModelsProbe.js probeOpenAiModels(baseUrl, { timeoutMs, apiKey }){ reachable, models, error } — the one GET {base}/models probe for the local OpenAI-compatible daemons, shared by services/providerReadiness.js and services/llamaServerManager.js. Distinguishes unreachable from reachable-but-unlistable (models: null) from up-with-nothing-loaded ([]), names the real transport failure via describeFetchError (undici reports every one as a bare fetch failed), and cancels an unread body on a non-OK response. apiKey attaches a Bearer header for a key-gated daemon (vLLM's compose stack), and a 401/403 answers reachable: true with error: 'authentication required' — a server that refused the request is definitively running, and calling it unreachable would send the user to start it again. Consolidated after the two copies drifted — one passed its timeout as a timeout key inside the fetch init object, where it is not an option, silently running a 500ms poll loop on the 15s default.
openAiChatStream.js iterateOpenAiChat(...) → normalized async content/reasoning chunks and streamOpenAiChat(...) → the streamed text — one streaming POST {base}/chat/completions against any OpenAI-compatible endpoint; both own timeout/abort composition, retries, parsing, backpressure, and reader cleanup. streamOllamaChat(...) is the assessment-only native /api/chat transport that preserves Ollama's exact eval counts and nanosecond timings. Also exports buildMessages, parseStreamFrame, parseOllamaStreamFrame, normalizeUsage (snake/camel/Ollama token-count keys → {completionTokens, promptTokens}, null = not reported), and resolvePartialOutput. Registering onStats on the OpenAI path asks for token counts; a daemon that rejects stream_options is retried once without it and remembered per endpoint. Sibling of openAiModelsProbe.js. Shared by Ask (services/askService.js), services/localLlmPlayground.js (provider-backed runs with a /runs record), and its runEndpointLlmTest (a bare loopback daemon PortOS holds no provider record for, which is how services/localModelAssessments.js measures llama.cpp / MTPLX / vLLM). An abort mid-stream throws with .partialOutput carrying what already streamed.
cliChildEnv.js The one place the AI-CLI child environment is composed, replacing the hand-rolled copy every spawn site carried — which made each env-level fix an N-file sweep (#3194). buildCliChildEnv({ baseEnv, before, provider, model, cwd, extra, guard }) returns a COMPLETE env for spawn: filters the inherited base to runtime essentials/provider auth, then layers baseEnv → before → Ollama-Claude defaults → provider.envVars → buildOpencodeEnvVars → extra, pins PWD to cwd, strips CLAUDECODE, and (with guard: true) prepends the pm2 guard shim onto the final PATH. The Ollama-Claude layer raises Claude Code's default output ceiling to 65,536 tokens so a thinking-capable local model cannot finish its reasoning past the stock 32K ceiling and die before its final tool call; an explicit provider env value wins. composeProviderEnv({ before, provider, model, extra }) returns just the ordered provider layers, for sites that build a DELTA someone else bases and spawns (the CoS runner payload, a shell-session overlay). The two slots are not interchangeable: before sits UNDER provider.envVars (forgeTokenEnv/claudeSettingsEnv, so a provider override still wins), extra sits OVER it (TERM/COLORTERM for a PTY). cliChildEnv.test.js asserts the composed order per call site and discovers any new site that hand-rolls the tuple instead of calling these — so the call-site list stays in the test, not in prose here.
agentExecutionProfiles.js Named agent execution postures shared by lifecycle dispatch, CLI/TUI spawners, and child-environment filtering. A stage declares a PROFILE (PUBLIC_REVIEW_EXECUTION_PROFILE, PUBLIC_REVIEW_GATE_EXECUTION_PROFILE, PUBLIC_REVIEW_ACTIONS_EXECUTION_PROFILE); publicReviewPostureForProfile maps it to the enforceable POSTURE a provider must carry a maintained recipe for (no-tool or sandboxed-actions), which is how a pipeline stage stays vendor-agnostic.
localEndpoint.js Dependency-light local-instance URL predicates (isLocalInstanceHost, isLocalInstanceEndpoint, localEndpointPort) shared by provider safety policy and local-runtime classification without importing backend configuration or daemon managers.
cliProviderArgs.js Per-CLI argv conventions (buildCliArgs) for stdin prompt delivery — dependency-light extraction from runner.js so out-of-process callers (autofixer) can import it.
cliProviderRun.js One-shot CLI provider invocation (pickCliProvider + runCliProviderPrompt) — lightweight path for the autofixer + calendar MCP sync to honor the configured provider/model.
cliStderrNoise.js isKnownCliStderrNoise(trimmedLine) — drops the real Anthropic claude CLI's harmless [claude-code:unrecognized_model] SDK telemetry line, which fires on every claude-ollama / claude-ollama-tui run because those providers point the binary's ANTHROPIC_BASE_URL at a local Ollama model the SDK doesn't recognize.
codex.js OpenAI Codex CLI (codex) provider helpers — the CODEX_COMMAND/CODEX_CLI_ID constants, the isCodexCommand predicate, and ensureCodexTuiArgs (injects --dangerously-bypass-approvals-and-sandbox + disables the startup update-check config, skipped when the argv already declares an approval/sandbox posture via argvHasFlag). Extracted from tuiHandshake.js (#3618) to match the one-file-per-vendor shape of antigravity.js/grok.js/kimi.js/cursor.js, which providerVendors.js consumes as registry rows.
cursor.js Cursor Agent (cursor-agent) provider helpers — the CURSOR_COMMAND binary constant, the isCursorCommand predicate, and the ensureCursorHeadlessArgs (--print --force, folding any pinned reasoning effort into --model) / ensureCursorTuiArgs (--force) argv builders. --force is load-bearing beyond approvals: it also clears cursor's workspace-trust gate, which otherwise EXITS a headless run before any work happens. The prompt rides raw stdin (like claude/codex, unlike grok/kimi), and cursor needs no configured-default sentinel — its auto router is a real model id passed straight to --model.
grok.js xAI Grok Build (grok) provider helpers — id/endpoint constants (GROK_API_ID/GROK_CLI_ID/GROK_TUI_ID/GROK_API_ENDPOINT), isGrokCommand/isGrokCliProvider/isGrokTuiProvider predicates, ensureGrokHeadlessArgs/ensureGrokTuiArgs argv builders (grok reads its prompt from --prompt-file /dev/stdin, not raw stdin; model selection uses the GROK_CONFIGURED_DEFAULT sentinel in providerModels.js so PortOS omits --model like Antigravity), and prepareGrokPromptFile (Windows temp-file delivery fallback).
grokVideoClip.js Clip lengths grok's image_to_video actually delivers — GROK_VIDEO_DURATIONS ([6, 10], measured in #3022: a 2s/3s request returns the same 6.04s clip), GROK_VIDEO_DEFAULT_DURATION, resolveGrokDuration() (validate an already-grok-shaped request, else default), and nearestGrokDuration() (round a length authored against another backend's continuous contract UP to the shortest clip that covers it — for translating a CD/commission targetDurationSeconds). Dependency-free so validation.js / routes/videoGen.js can derive their schemas from the same list the services gate on.
kimi.js Moonshot AI Kimi Code (kimi) provider helpers — id constants (KIMI_CLI_ID/KIMI_TUI_ID), isKimiCommand/isKimiCliProvider/isKimiTuiProvider predicates, ensureKimiHeadlessArgs (model flag only — non-interactive mode is implicit in --prompt, and kimi has no --print/--afk and refuses approval flags alongside --prompt) / ensureKimiTuiArgs (--yolo) argv builders (model selection uses the KIMI_CONFIGURED_DEFAULT sentinel in providerModels.js so PortOS omits --model like Grok/Antigravity), and prepareKimiPrompt (delivers the prompt as the --prompt <value> argv, not stdin).
runners.js Image-runner family constants (RUNNER_FAMILIES, loraCompatKey), video LoRA families, MiniMax H3 runtime predicates, and the shared AUDIO_TO_VIDEO_RUNTIMES / isAudioToVideoRuntime capability gate (LTX plus H3 Ref2VA). Mirrored to client/src/lib/runnerFamilies.js.
codexAccount.js The ChatGPT-subscription half of the Codex providers (#5589), pure. The fixed codex app-server invocation, the account/* method + notification names, CODEX_ACCOUNT_STATUS (runtime-missing / unknown / signed-out / login-pending / ready / quota-exhausted / reauth-required) and CODEX_ERROR_CODES, isCodexSubscriptionProvider (keyed on the codex COMMAND, so a renamed clone still resolves), the normalizeCodexAccount / normalizeCodexRateLimits / normalizeCodexLoginStart payload normalizers, redactCodexPayload (every log/error/response path runs through it, so "PortOS never writes down a Codex token" is one function rather than a rule per call site), and deriveCodexAccountStatus. Sentinels are load-bearing: runtimeInstalled: null = NOT PROBED, accountFetched: false ≠ signed out, rateLimits: null (failed fetch) ≠ a fetched window with nothing to report. The process half is services/codexAppServer.js.
codexTurn.js The INFERENCE half of the Codex ChatGPT-subscription provider (#5590), pure. The thread/start / turn/start / turn/interrupt / model/list method names and the turn notifications, CODEX_TEXT_TRANSPORT plus providerDeclaresCodexTextTransport (advertises, reusing codexAccount.isCodexSubscriptionProvider so the two halves cannot drift) vs isCodexTextTransportEnabled (requires both the explicit opt-in and the Providers-UI read-risk acknowledgement), the CODEX_TEXT_THREAD_CONFIG safety envelope a generic text call runs under (empty throwaway cwd, no writes, no network, fail-closed approvals, no MCP servers, no web search — Codex can still read local files by absolute path; see the module docstring), normalizeCodexModels / normalizeCodexTokenUsage / resolveCodexEffort, the createTurnAccumulatorapplyCodexTurnEventfinalizeCodexTurn projection (a non-completed turn yields an error, NEVER the partial text), and classifyCodexTurnError / classifyCodexTransportError, which fold both failure shapes onto the shared ERROR_CATEGORIES the cooldown policy reads. models: null = never fetched, [] = fetched-and-empty. The process half is services/codexAppServer.js.
codexAssistantExtract.js Strip Codex CLI banner + echoed metadata from session transcript.
codexCliOutput.js Network/system error patterns for agentErrorAnalysis.js.
contextBudget.js Context-window budgeter for editorial passes. estimateTokens/estimateTokensFromChars (chars/4), usableInputTokens, manuscriptContentBudgetChars (single-block content cap floored at a manuscript minimum so a standalone stage trims to fit a small window instead of overflowing a fixed 48–60K floor, #1488), planManuscriptPass({ contextWindow, sections }){ mode: 'whole' | 'chunked', chunks }. Also fitContextToManuscriptFloor/capContextOverhead/trimContextToBudget — trim a re-sent context block (scene map, character arcs, …) so a large reverse outline on a small window can't starve the manuscript chunk below a budget floor (#1459). Decides whole-manuscript vs chunked given a model's window.
localPromptBudget.js What a large prompt costs to PREFILL on a model server running on this machine (#6117). planLocalPromptBudget({ prompt, endpoint, baseDurationMs }){ promptTokens, prefillMs, expectedDurationMs, longPrefill, … }, or null for a cloud endpoint / no prompt to measure — a sentinel a caller must read as "no estimate", never as a small one. estimateLocalPrefillMs and describeLocalPromptBudget are the token→ms and plan→sentence halves; LOCAL_PREFILL_TOKENS_PER_SECOND is a deliberately pessimistic constant, since over-estimating only widens the window a healthy run gets. Never refuses a dispatch: it raises the run's duration estimate so a ~100K-token public-review envelope reads as a long silent prefill instead of a wedged run. Pure.
ansiStrip.js Streaming ANSI / control-byte stripper.
hfErrors.js Parse huggingface_hub gated-access errors: isGatedRepoError(text) classifies a failure as gated (403/restricted), extractGatedRepo(text)owner/name (or null) for the UI's license deep-link. Shared by the image runner and MIDI transcription (LoRA trainer keeps its own regex to also match bare 401). Pure.
hfCache.js HuggingFace Hub cache inspection (inspectModelCache(repoId,{revision?}){cached,sizeBytes,snapshotPath}, isModelCached, getHfCacheRoot). Drives the inline "Available / Download" badge on the image + video gen forms. Also verifyModelCache(repoId,{deep,revision?}) (structural safetensors-header + optional sha256 integrity check) and repairModelCache(repoId,{deep,revision?}) (delete corrupt weight files so the download path re-fetches them) — power the "Repair model" banner. findCachedRepoSnapshot(repoId,revision) resolves an immutable local snapshot; findCachedRepoFile(repoId,filename,{revision?}) resolves ONE known file without walking it, and findCachedRepoFiles(repoId,filenames,{revision?}) is its all-or-nothing plural form (paths in request order, or null if ANY is missing — a caller needing several pinned files, e.g. the shards of one checkpoint, can do nothing useful with a partial set); isSafeHfRepoRelativePath rejects traversal/absolute dependency filenames; verifyCachedRepoFiles / repairCachedRepoFiles apply that revision-aware exact-file contract to pinned adapter pairs; and repairCachedFile(path,{snapshotPath?}) is the containment-checked matching single-file repair. verifySafetensorsStructure(path,size) is the reusable header/size structural check.
icLoraWeights.js IC-LoRA weight registry for the local LTX-2 remix modes (IC_LORA_MODES, IC_LORA_MODE_VALUES, listIcLoraWeights(), isIcLoraMode(mode), icLoraSpecForMode(mode), icLoraRepos(), icLoraWeightCandidates(spec), findCachedIcLoraWeight(spec), resolveIcLoraWeight(mode){path,cached,spec}). Single source of truth mapping each remix mode (ic-control, ic-colorize, ic-ingredients) → its HF repo/filename, reference-count rule, per-weight referenceDownscaleFactor (read from the weight's safetensors metadata, never assumed), and input surface (`referenceKind: 'video'
sseHeaders.js SSE_HEADERS — the canonical SSE response headers (incl. X-Accel-Buffering:no) in a dependency-free module so any producer (sseDownload.js, sseUtils.js) can share them without pulling in a heavier module's transitive imports.
sseDownload.js `startHfDownloadStream({req,res,repo
installLogger.js createInstallLogger({installer,target}){start,onEvent,success,failure,cancel} — server-console chokepoint for install/venv-setup SSE flows (the install-side analogue of sseDownload.js). Logs a START line, throttled heartbeats + stage milestones (not every raw pip/bash line), and the OUTCOME (success/fail/cancel) with elapsed time. onEvent(ev) auto-detects terminal complete/error SSE events. Used by the music/video runtime installers and the FLUX.2 venv bootstrap.

File & I/O

Module Purpose
borderKey.js Sharp-free image primitives shared by sprites and image-to-3D: statistics median, subsampled border-band sampling, solid-border coverage detection, and alpha meaningfulness/variation checks.
collectionStore.js Per-type, per-record JSON storage with explicit type-level schemaVersion stamping. Use for collections that have outgrown a monolithic JSON file. createCollectionStore({ dir, type, schemaVersion, sanitizeRecord }) returns loadOne / saveOne / saveOneNow / listIds / loadAll / loadAllResult / deleteOne / loadTypeIndex / saveTypeIndex / verifySchemaVersion. loadAll silently drops corrupt records; loadAllResult(){ records, failedIds } keeps the "which ids failed to load" signal so a caller can tell a partial set from a complete one. Per-id write queue means writes to different records don't serialize; saveOneNow is for callers already inside a collection write queue. Boot-time verifyCollectionVersions([store, ...]) logs schema-version mismatches. Type-index config slot holds cross-record state (see the TypeIndexConfig typedef + header convention): { runs?: [], featureFlags?: {}, lockPolicies?: {} }runs is the shipped slot (universeBuilder's capped history log), the other two are reserved names; consumers may add their own keys but should reuse a reserved name when it fits and document the shape next to the consumer. saveTypeIndex({ config }) shallow-merges config one level deep (a patched runs replaces the whole array), so a read-modify-write of a slot must load → mutate a copy → write inside queueTypeIndexWrite(fn).
conflictJournal.js Non-blocking edit-conflict journal for cross-install LWW merges. maybeJournalBeforeOverwrite({kind,id,local,remote,source}) (call right before a merge overwrite) archives the losing local version when a true 3-way divergence is detected (detectConflict via per-record syncBaseHash + contentHashForRecord), then advances the base hash; flushBaseHashes() persists the batched base-hash side store; withBaseHashFlushBatch(fn) defers every interior flush so an await-separated multi-record loop — the peer:online convergence push and every base-hash-evicting pruneTombstoned* loop — collapses N sync_base_hashes.json rewrites into one terminal write (depth-counted, so concurrent batches merge too; flushes in finally). deleteSyncBaseHash(kind,id) evicts a record's base hash when its tombstone is hard-pruned, so those paths don't let the side store grow without bound; pruneOrphanedBaseHashes(resolves) is the backstop sweep (resolves(kind,id) => bool; unknown kinds kept) that drops keys whose record no longer resolves, wired into the tombstone GC sweep. conflictJournalStore() is the pending/resolved entry store (discard resolves an entry; DELETE hard-removes it — there is no dismissed status). Local-only — never crosses the wire.
schemaVersions.js Cross-instance sync version contract. PORTOS_SCHEMA_VERSIONS (frozen map of { category: layoutVersion }), RECORD_KIND_SCHEMA_CATEGORIES (frozen map of federated record kind → the schema categories it writes), buildPortosMeta() (envelope for every outbound sync payload), compareSchemaVersions(sender, receiver) returning { ahead, behind, compatible }, scopeVersionDiff(diff, categories) (restrict that diff to the categories a specific transfer touches), and formatVersionGap() for UI/log lines. Receivers gate applyIncomingPush / share-bucket import / snapshot apply per-category on the scoped comparator result so an upgraded sender can't corrupt a downstream peer — and a bump to one category doesn't sever sync of the others.
dataRoot.js Data-root resolution + worktree-checkout detection (#1947). resolveInstallRoot(fallbackRoot) prefers the PORTOS_DATA_ROOT env var (pinned at real launch in ecosystem.config.cjs) over an import.meta.url-derived fallback, so a process booted from inside a CoS agent git worktree still resolves data//data.reference/ to the real install instead of the worktree's empty tree. isWorktreeRoot(rootDir) is the boot-migration backstop — true when rootDir lives under data/cos/worktrees/ (keyed on the path segment only, so a fresh install's empty data/ isn't a false positive). resolveCodeRootForModule(moduleUrl) is the single source of truth for the "two directories above this file" depth assumption — paths.js's CODE_ROOT and services/userActions.js's data-root guard both derive through it so they cannot silently drift apart. DATA_ROOT_ENV is the env-var name constant. Consumed by fileUtils.js (PATHS), server/index.js, and scripts/run-migrations.js.
downloadPreflight.js Free-disk preflight + resumable weight download. assessDownloadPreflight({ destPath, expectedBytes }){ freeBytes, requiredBytes, headroomBytes, verdict: ok|tight|insufficient }; assertDownloadFits throws typed DISK_INSUFFICIENT (507) when the volume cannot hold the payload. streamResumableDownload Range-resumes a .partial on transport failure, discards it on user cancel, and verifies a published sha256 before rename. sweepOrphanedPartials(dirs, { maxAgeMs }) unlinks leftover .partial (+ .partial.etag) files older than 7 days (default) and skips recent/in-flight dests; missing dirs are a no-op. probeRemoteSize / siblingDownloadMeta / verifyDownloadHash are the size+digest helpers the four weight-download entry points share. createDownloadSlot({ codePrefix, idleStallEnvVar, exclusive, keepPartialOnCancel }) is the one transfer-slot registry a weight download claims before its first await — in-flight map, abort controller carrying a cancel/stall reason, typed <PREFIX>_DOWNLOAD_IN_FLIGHT/_STALLED/_CANCELLED errors, a per-chunk progress throttle, and an isInFlight(path) predicate covering the dest, its .partial, and shards under a claimed directory. Call it at module scope only. isAnyDownloadInFlight answers for every registered slot at once, which is how the orphaned-partial GC protects live transfers.
agentInstructionsFile.js The AGENTS.md + bridge CLAUDE.md pair a repo carries (#4852). writeAgentInstructions(repoPath, content) writes the body to AGENTS.md and the one-line @AGENTS.md import beside it — use it in scaffolders instead of a bare writeFile(join(repoPath, 'CLAUDE.md'), …), since a generated repo carrying only one name is unreadable to half the CLIs PortOS can point at it. Constants: AGENT_INSTRUCTIONS_FILENAME, CLAUDE_BRIDGE_FILENAME, AGENT_INSTRUCTIONS_IMPORT.
fileCore.js Cross-cutting filesystem primitives (atomicWrite, writeFileGuarded, appendFileGuarded, copyFileGuarded, rmGuarded, unlinkGuarded, createWriteStreamGuarded, directory helpers, bounded tail reads/watchers), time/format helpers, directory sizing, and SHA-256 helpers.
fileUtils.js Backward-compatible facade re-exporting the focused file utility modules so existing deep imports need no caller changes.
portosEnv.js Single server-side helper for PortOS's own .env (PORTOS_ENV_PATH anchored to installRoot per #1947, parseEnvContents, readPortosEnvValue, upsertPortosEnvLine + upsertEnvLine), with replacer-function guard for $-patterns and process.env wins precedence; scripts/lib/envFile.js stays as the zero-dependency boundary copy.
secretText.js scrubSecretTokens(text) — replace credential-SHAPED substrings (prefixed API keys, GitHub/Slack tokens, JWTs, AWS key ids, pasted Bearer headers, 48+-char hex) with [REDACTED] in free text bound for an LLM provider or a world-readable artifact; scrubSecretTokensDeep(value) walks arrays/plain objects and scrubs every string value. Value-side counterpart to the operator-action ledger's key-based redactPayload and commandSecurity.js#redactOutput's JSON patterns; conservative so prose, 40-hex git SHAs, and short ids survive.
homePath.js scrubHomePath(value) — replace the running user's home-directory prefix with ~ anywhere in a string, so /Users/<name>/… never embeds the OS username in anything a user pastes into a bug report. Non-strings pass through; a root-user container reporting / as home is left alone (substituting on it would rewrite every separator in every path). Zero-dependency by design: agentRunEvents.js re-exports it for the CoS ledger, and scripts/doctor.js imports it statically because it must load from a bare checkout with no node_modules (scripts/pre-install-entrypoints.test.js enforces that).
jsonIo.js JSON/JSONL parsing and file IO, strict read sentinels, append/read/write helpers, and createCachedStore.
mimeTypes.js MIME tables and extension allowlists, image format detection, and filename sanitization.
paths.js Canonical source/install PATHS, dataPath, and home-directory expansion.
pathContainment.js Dependency-free leaf holding isPathAtOrInsideDir(dir, path) (containment where the root itself counts as inside — what a guard policing a whole tree wants, as opposed to pathSafety.js's strict isPathInsideDir; case-folded on Windows/macOS) and canonicalizePath(path) (realpath of the deepest EXISTING ancestor plus the not-yet-created tail, so a target that does not exist yet still resolves through symlinked ancestors). Split out so fileCore.js's #6176 guard can reach them without dragging errorHandler.js/paths.js into the closure of every server suite — see the budget in importScoping.test.js. Keep it free of non-builtin imports.
pathSafety.js Filename/traversal validation, path containment, and approved image-asset resolvers.
uploads.js Upload staging/import, base64/image persistence, and safe local-file serving.
icloudFile.js Guards against blocking reads of evicted (dataless) cloud files. macOS Optimize-Mac-Storage offloads a file in an iCloud ubiquity container (or a ~/Library/CloudStorage File Provider mount); the path and size remain but no blocks are local, and the first data access BLOCKS in the kernel until materialization completes — indefinitely and uncancellably when iCloud is wedged. Four such reads exhaust libuv's 4-thread fs pool and every later fs call in the process queues forever, including the express.static read that serves the UI bundle (the whole UI hangs while memory-only routes still answer). Retry-on-error can't help: the read doesn't fail, it hangs. readIfMaterialized(path, {encoding, label}) screens with a stat() (safe — never materializes) and rejects with err.code === ICLOUD_NOT_MATERIALIZED instead of issuing the read, kicking a background brctl download so the next cycle succeeds; concurrent callers for one path+encoding share a single read. isUbiquityPath(path) resolves the containing directory's real path (memoized) rather than substring-matching, so a symlinked route into iCloud — ~/Documents/... under "Desktop & Documents Folders" sync — is still recognized. isDatalessStats(stats) is the raw predicate (size > 0 && blocks === 0) and is not safe alone (a sparse or decmpfs-compressed ordinary file matches it); pair it with the platform + cloud-root scoping via isEvictedStats(path, stats), which is what a caller holding a Stats should use, or isSuspectedDataless(path) which does the stat itself. requestMaterialization(path, {label, retryAfterExit, onFailure}) is the fire-and-forget brctl download every brctl caller shares — read paths kick it (default retryAfterExit: true) to heal an evicted file, per-path-deduped in a shared in-flight map capped at 4 concurrent children (an evicted vault walk would otherwise fork one per note) and each killed at DOWNLOAD_DEADLINE_MS so a wedged brctl can't hold every slot for the life of the process; the boot/settings pin in mortalLoomStore passes retryAfterExit: false so it is NOT tracked in that shared map (it owns a single-sticky-path dedupe at its call site) plus an onFailure hook to clear that sticky path on a failed/killed download. claimBrctlMissingWarning() returns true on the first call only, so the "brctl not found on PATH" warning fires at most once per process across every brctl caller (the fire-and-forget path here and the awaited materializeAndWait). materializeAndWait(path, {label, timeoutMs}) is the awaited, bounded counterpart used by WRITE paths (mortalLoomStore before overwriting its store, obsidian.updateNote before overwriting a note): a write must not silently skip, so it materializes and waits rather than firing and forgetting, bounded by MATERIALIZE_TIMEOUT_MS (20s — much tighter than the background DOWNLOAD_DEADLINE_MS because a caller is blocked on it) and run in a child process, which is what makes the wait cancellable when the kernel write it replaces would not be. It resolves true only on brctl exit-0, which means the download was accepted, not completed — always re-screen before trusting the file. Measured (#3706, #3713), and recorded in the module docblock's syscall table: stat/open/rename/unlink never materialize, while read, write (including after O_TRUNC — truncating does NOT skip the download), link, and clonefile all do. unlink being free is a measurement, not the POSIX inference — link is pure metadata too and it does materialize — so delete paths need no screen. The docblock also carries the reproduction recipe: brctl evict <path> works (undocumented, like brctl download), which is what makes the evict/measure/heal loop scriptable. Consumed by services/mortalLoomStore.js and services/obsidian.js.
boundedStateMap.js createBoundedStateMap({ maxSize, ttlMs }) — a Map that self-evicts so a per-key state cache can't grow one entry per key forever. Lazy TTL + LRU eviction on get/set (no timers); get doubles as the LRU touch. Used by the moltbook/moltworld rate-limiters to bound their per-agent state.
createKeyCachedQueue.js Per-KEY serialized async work queue (sibling to fileWriteQueue.js's single tail). createKeyCachedQueue() returns queue(key, work) that chains each work thunk onto the prior in-flight promise for that key — same-key work runs one-after-another (later sees earlier's committed result), different keys run concurrently. Self-pruning tail Map; work runs on both fulfil and reject so one failure can't stall the chain; carries .clear() for test reset. Used by the media-job completion hooks (writers-room / catalog / music-video scene-image attach) to serialize per-record.
createNewestWinsGuard.js Newest-render-wins ordering guard for out-of-order async completions. createNewestWinsGuard() returns { isStale(key, at), mark(key, at), clear() } — tracks the newest applied queuedAt per slot key so an older render completing after a newer one is dropped (isStale true) instead of clobbering the newer frame. ISO timestamps compare as strings; absent at is never stale. Used by createMediaJobImageHook's opt-in guard and the catalog hook's portrait slot.
fileWriteQueue.js Serialize read-modify-write cycles so they don't interleave. createFileWriteQueue() → single-tail queue(fn) for one shared file; createRecordWriteQueue(assertId?) → id-keyed queueRecordWrite(id, fn) where same-id cycles serialize and different-id cycles run in parallel (the queue the PG/file store facades use for collectionStore.queueRecordWrite parity); createKeyedFileWriteQueue()queueKeyedWrite(key, fn) that collapses the pipeline stage stores' hand-rolled Map + per-key createFileWriteQueue factory (falsy keys → shared '__unknown__' tail; self-pruning via createKeyCachedQueue).
forgeIssueState.js normalizeIssueState(state) — collapse a forge issue/PR/MR state string to open/closed. GitHub reports OPEN/CLOSED; GitLab reports opened/closed/locked; anything unrecognized is treated as open so an unfamiliar state can never read as "already resolved". Shared by layeredIntelligence/forgeFiler.js and services/blockedIssueReconcile.js.
imageClean.js cleanImageBuffer(buf, { metadata, denoise }) (composable opt-in pipeline: lossless metadata/C2PA strip + optional median/sharpen denoise) · stripPngMetadataChunks / stripPngC2PAChunk (lossless PNG-chunk removers) · compositeIgnoreZone(base, original, mask, { feather }) (preserve-region compositing: restore original pixels into a feathered mask over a diffused result) · autoCleanGeneratedImage (in-place clean for post-generation hook). HTTP route in routes/imageClean.js wraps cleanImageBuffer and appends a CPU light diffusion pass (applyLightRegen from services/imageGen/regen.js) for the diffusion=light SynthID-disruption step.
imageFrameStats.js Degenerate-frame classifier (#4173) — describeFrameStats(bufferOrPath) runs one sharp .stats() decode and returns { ok, reason, perChannel }, rejecting solid-fill (every colour channel stdev under SOLID_FILL_STDEV_EPSILON), fully-transparent (alpha max 0) and near-empty (greyscale entropy under NEAR_EMPTY_ENTROPY_FLOOR), except when a non-opaque alpha channel carries a substantial silhouette itself. Deliberately NOT a quality judge: a legitimately dark or minimalist render keeps real per-channel variance and is accepted. ok is three-valued — true/false/null, where null means could-not-measure (undecodable buffer, or under MIN_JUDGEABLE_PIXELS) and must never read as degenerate; gate on isDegenerateFrame(stats) / ok === false, never !ok. Called by the Image Gen provider completion seams, sprite reference normalization, and visionTest.js (so a paid vision call is never spent on a blank frame). A buffer verdict is memoized on the sha256 of its bytes (#6004) — the probe costs ~4ms regardless of pixel count and the sprite compiler re-probes identical frames dozens of times per run; a path is never memoized (the file behind it can change), so hand it bytes you already read. stats-unavailable is never memoized either — that branch catches transient probe failures too, and pinning ok: null on valid bytes would disable the gate for them. __resetFrameStatsCache() drops the memo in tests.
imageRgba.js Sharp-backed RGBA boundary: decodeRgbaFrame decodes an image to { data, width, height }, and encodePng turns a raw frame into PNG bytes for the caller's destination/hash policy.
imageWatermark.js removeCornerWatermark (erases the visible Gemini/Nano-Banana bottom-right ✦ via dependency-free harmonic/Laplace inpaint) + pure helpers resolveWatermarkRegion / inpaintRegion. Distinct from SynthID regen — this targets the visible corner logo.
localImageFilename.js localImageFilename(urlOrPath) resolves a stored image reference to the bare gallery-image filename under data/images/ (or null for empty/external-URL/non-image-path) — the unit the peer-sync asset pipeline hashes + transfers. Single source of truth for the authors/artists/albums/Creative-Director filename resolvers (headshotImageFilename/portraitImageFilename/coverImageFilename/startingImageFilename are thin wrappers). Also exports assetBasename(pathOrName), the shared strip-querystring→basename primitive (reused by moodBoard's imageUrlToAppAsset).
threejsModel.js Validated declarative procedural-model schema plus deterministic standalone Three.js factory export for the Three.js Models workspace. Also the cross-section gate: evaluateThreejsFlatness(spec) counts distinct vertex planes per axis — relative to the mesh's own size, with a rotation-invariant zero-volume check behind it — and treats an extrude with no bevel thickness as the two-plane slab it is to report when the majority of identity-priority features are built only from flat parts — a model that reads right head-on and like cardboard when orbited. buildThreejsFlatnessFeedback(flatness) turns that into default refinement feedback; listSpecNames(names) is the shared capped name-list formatter both gates use in finding messages. Also the material-plausibility gate: evaluateThreejsMaterialPlausibility(spec) keys a bounded per-family prior table (metal, wood, plastic, glass, fabric, ceramic, rubber, stone, leather, paper) off tokens in each material's id and reports channels whose values the named substance does not support — metalness 0.9 oak, transmission 1.0 steel — skipping any id that names no family or two, and any channel the material's type never forwards to Three.js. Advisory only: it never clamps, because a stylized model may legitimately break every prior. buildThreejsMaterialFeedback(plausibility) turns that into default refinement feedback. The same pass emits a reflective-material-without-environment note when a spec authors reflective channels (metalness above 0.6, or any transmission/clearcoat/iridescence) while environment.preset is none — those channels read off an environment, so in that scene their values cannot be judged at all. Attachments are declared in two forms — the original anchor-less attachmentPartIds and the anchored `attachments: [{ partId, anchorPartId
threejsModelAnimation.js summarizeThreejsAnimation(spec) — clip inventory and playback gate over an already-validated Three.js spec: { animated, clipCount, cueCount, sequenceCount, movingPartCount, longestClipSeconds, findings, warningCount, clips }. The schema proves a declared animation block is well formed (sequences on real parts, inside their clip, never two on one channel at once, never a cue without motion); this reports what the model declared — one entry per clip with its role, duration, sequence and distinct-cue counts — plus the ways a well-formed clip still plays badly: a clip authored against a pose the assembly does not build (clip-start-pose-mismatch), a handover between sequences that do not meet (clip-sequence-jump), a loop: true clip that does not return to where it began, a one-shot idle, an unfired cue, a long dead tail, and an articulation graph with no clip at all. Advisory warnings only — a static assembly is a complete answer. buildThreejsAnimationFeedback(animation) turns those findings into default refinement feedback. A spec with no animation key summarizes as not animated — never as evaluated-and-empty.
threejsModelCoverage.js evaluateThreejsPartCoverage(spec, { family }) — structural assembly gate over an already-validated Three.js spec: flags promised features fused onto the same part set, geometry claimed by no detail, and details nothing was built for (folded minor relief stays a note). With a subject family it also warns on a required component the spec never mentions at all — the one check that can fault a spec for what it failed to promise. buildThreejsCoverageFeedback(coverage) turns the error findings (plus any family gap) into default refinement feedback.
threejsModelEnvironment.js The image-based-lighting and render-profile half of the procedural sculpt contract, kept dependency-free so the client suite can import it to assert parity with client/src/lib/threejsEnvironment.js (threejsModel.js pulls in zod, which the client CI job does not install). THREEJS_ENVIRONMENT_PRESETS (none/neutral/studio) is the bounded preset list the spec schema builds its enum from; resolveThreejsEnvironment(spec) normalizes a spec's { preset, intensity } block, reading an absent, partial, or unrecognized one as DEFAULT_THREEJS_ENVIRONMENT per field — a record stored before the block shipped has no key and was rendered with no environment, so none is the honest reading of it. THREEJS_RENDER_PROFILE is the output-colour-space / tone-mapping / exposure contract buildThreejsFactorySource() stamps onto every export.
threejsModelFamilies.js Curated subject-family checklists for Three.js generation. THREEJS_MODEL_FAMILY_OPTIONS / THREEJS_MODEL_FAMILY_IDS drive the picker and route validation; buildThreejsFamilyChecklist(id) returns the prompt block spliced into generation ('' for the default general, so an un-narrowed subject keeps the unchanged general-purpose prompt); findMissingFamilyComponents(spec, id) reports which required components the spec never mentions.
threejsModelPenetration.js evaluateThreejsPenetration(spec) — cross-part penetration gate over an already-validated Three.js spec, the one check that compares two parts to each other. Rebuilds each part's world placement (the same THREE.Euler 'XYZ' composition the preview applies), derives an analytic solid per geometry type, and samples one part's interior against another's to flag a part entirely buried inside an unrelated one (error) or unrelated parts occupying substantially the same space (warning). Parts in the same subtree and declared attachmentPartIds are exempt — embedding is what those relationships are for — and a shallow or transparent-container overlap is reported as an undecided note, never as a defect. buildThreejsPenetrationFeedback(penetration) turns the errors and warnings (never the undecided notes) into default refinement feedback.
threejsModelPhysicalAudit.js evaluateThreejsPhysicalAudit(spec) — pure bounds and pose audit gate over an already-validated Three.js spec: inspects static resting poses and animated clip poses to detect floating parts (floating-part), swallowed geometry (buried-geometry), z-fighting coplanar surfaces (coplanar-surface), unprovenanced appearing geometry (unprovenanced-transition), non-uniform parent scale cascading into descendants (nonuniform-parent-scale), attachments declared with nothing to hang from (unanchored-attachment, warning), and attachments measured further from their declared anchor than maxOffset allows (attachment-far-from-anchor, error — the spec asserted the relationship itself), across the resting pose and the sampled clip poses so a clip that carries an attachment away from its anchor is caught too. Named left/right pairs are additionally audited for handedness in the resting pose — measured in the frame of the pair’s nearest common ancestor, since the lateral plane a pair mirrors across is the one their shared parent defines and not world x = 0 — which no bounds check can see — a limb mirrored by a 180° yaw about the vertical axis rather than a lateral reflection (bilateral-chirality), by a negated scale component (bilateral-mirror-scale), or not mirrored at all so both halves sit on one side of the lateral plane (bilateral-pair-same-side), all warnings. An attachment whose anchor geometry could not be measured is listed in unmeasuredAttachments rather than counted as passing. buildThreejsPhysicalAuditFeedback(physicalAudit) turns actionable findings into default refinement feedback.
threejsModelPlayerSource.js THREEJS_PLAYER_SOURCE — the fixed clip-player source buildThreejsFactorySource emits into every exported Three.js module, giving a standalone consumer createSculptAnimationPlayer(root, { onCue }) (plus evaluateSculptClipPose / collectSculptCues) over the node map and validated animation block the factory already carries. A STRING constant, not generated text: nothing provider-authored is interpolated into it, so the export stays data-plus-PortOS-code. It takes update(deltaSeconds) from the host render loop rather than owning one, scrubs silently and fires cues only on playback (mirroring the preview), and clones a shared material before driving opacity. Semantics mirror client/src/lib/threejsAnimation.js — change one and change the other.
threejsModelRig.js evaluateThreejsRigReadiness(spec) — honest rig-readiness report over an already-validated Three.js spec: { articulationReady, reasons, jointCount, socketCount, attachmentCount, anchoredAttachmentCount, unanchoredAttachmentCount, rootJointId, subjectType }. The schema proves the optional articulation graph is well formed (one root, no cycles or forward refs, joints and pivots pointed at real parts/sockets); this reports whether it is useful (more than a lone root, every child joint carrying a pivot axis, every declared attachment naming what it hangs from) and names the reason when it is not. It reports rather than rejects, and never claims skinning: PortOS generates static assemblies and declared articulation intent, not skeletons or bind poses.
threejsTransform.js Affine transform primitives shared by every server-side gate that reconstructs where a Three.js scene-spec part sits in the world — rotationMatrix (row-major 3×3 matching THREE.Euler order XYZ, the composition the preview canvas and exported factory both apply), scaleLinear, multiplyLinear, applyLinear, applyTransform, composeTransform(parent, { position, rotationDegrees, scale }), vectorLength, degreesToRadians, IDENTITY_LINEAR / IDENTITY_TRANSFORM. One owner for math threejsModel.js, threejsModelPenetration.js and threejsModelPhysicalAudit.js each used to spell separately. A non-finite rotation component reads as 0 degrees and a non-finite scale component as 1, matching what the renderer does with a malformed stored spec — feeding null/NaN through instead produced NaN bounds that the audits read as "no overlap" and "no defect".
pgFileFacade.js Shared PG/file store-backend backbone for the six storage dispatchers (pipeline series/issues, story builder, universe builder, catalog user-types, writers room). isFileBackend() (dev/test escape-hatch predicate) · resolvePgBackend({ requirement, migrate?, loadDb, makePg }) (health-check → ensureSchema → one-time migration → import db.js → build the PG backend) · createPgFileFacade({ makeFile, makePg }) (promise-memoized lazy selection so concurrent first calls don't run the migration twice; returns { getBackend, getBackendName, reset }). Each store keeps its own makeFile/makePg factories + public surface. createRecordStoreBackendSelector({ label, loadFileBackend, loadDbBackend, requireDbMessage?, isTestMode?, onDbReady? }) wraps the same backbone for the stores whose backends are whole MODULES rather than built objects (Creative Director, Music Video, Sprites) → { selectBackend, getBackendName } where the name is 'file'/'postgres'; isTestMode lets a store use the stronger isTestRunner() signal (Sprites).
multipart.js Streaming multipart/form-data parser.
safetensors.js readSafetensorsHeader(path) reads only the JSON header of a .safetensors file (never the tensor payload). detectFlux2VariantFromHeader(header) / detectFlux2Variant(path) classify a LoRA as FLUX.2 Klein '4b' (hidden dim 3072) vs '9b' (4096) by transformer-block tensor shapes, so the LoRA picker can hide off-variant weights that would silently fail to load. classifyLoraKeyLayoutFromHeader(header) / classifyLoraKeyLayout(path) classify the key layout as LORA_KEY_LAYOUTS (bare / comfyui / diffusers / kohya / not_a_lora, null = unreadable), isKnownLoraKeyLayout(layout) validates a layout read back out of persisted state, and videoLoraLayoutIssue(layout) returns the user-facing reason a layout can't fuse into the LTX-2 video transformer (or null when it can).
loraEffect.js LoRA adapter-effect report rules — the JS half of the scripts/lora_effect_probe.py diagnostic (#4872), mirrored to the client by client/src/lib/loraEffect.js and pinned by loraEffect.parity.test.js (which also holds LORA_EFFECT_PROBE_VERSION in lockstep with the probes PROBE_VERSION— drift silently disables the cache).LORA_EFFECT_STATUSES (ok/zero/nonfinite/unreadable/unmeasurable) + isKnownLoraEffectStatus; normalizeLoraEffectReport(raw,{sizeBytes,mtimeMs,measuredAt})coerces every non-finite number tonull, drops statistics when nothing was measured so "no data" can never read as "measured 0.0", and downgrades a zerostatus that no measurement backs;readCachedLoraEffectReport(raw,{sizeBytes,mtimeMs})returns a stored report only while its probe version, file size AND mtime all still match, which is what letslistLoras()surface one without ever spawning a probe;loraEffectIssue(report)is the user-facing refusal phrase for a measured entirely-zero adapter andnullfor EVERY other status;formatLoraEffect(report)` is the one-line log/UI summary.
pdfImageEmbed.js PDF image embed helpers for comic / volume PDFs.
zipStream.js Streaming ZIP parser (parseZip, unzipper-style); collectZipEntry(entry, maxBytes?) buffers one parseZip entry into a Buffer (size-capped); collectZipEntries(path, { match, onMatch, maxBytes? }) owns the multi-entry import lifecycle (teardown, autodrain, per-entry await) leaving callers only match/parse; isZipUpload(file) predicate for an uploaded ZIP; extractZipEntryToBuffer(path, match) cracks one member out to a Buffer.
zipWriter.js Minimal ZIP writer — createZip(entries) builds a stored (uncompressed) archive Buffer that round-trips through parseZip; crc32(buf) is the dependency-free checksum it uses.
assetHash.js Cross-transport SHA-256 cache for data/images/* — persists hashes in the asset's .metadata.json sidecar so the share-bucket exporter and the federated peer-sync push pipeline reuse the same value. sidecarGenParamsHash canonically hashes a sidecar's gen-params (excludes the machine-local sha256 cache block) for cross-machine sidecar-convergence comparisons.

Process execution

Module Purpose
agentGuard/ agentGuardEnv(baseEnv?) + AGENT_GUARD_BIN — env patch that prepends a guarded pm2 shim (bin/pm2) to a spawned AI agent's PATH so a confused --dangerously-skip-permissions agent can't pm2 kill / pm2 delete all the shared daemon (which would down every app, incl. PortOS). Blocked-subcommand list mirrors validatePm2Command in commandSecurity.js. POSIX-only (no-op on Windows).
bashResolver.js resolveBashBinary() — resolves the POSIX bash for running bundled *.sh scripts (e.g. scripts/db.sh). On Windows a bare bash often resolves (via PM2's PATH) to WSL, which mounts drives at /mnt/h and can't see a H:/... drive path (exit 127); this prefers Git Bash (PORTOS_BASH override → standard install dirs → derived from git on PATH → bare bash). No-op (bash) on non-Windows. toBashPath(p) — the companion path rule: bash reads backslashes as escapes, so a Windows path must reach it with forward slashes.
interactiveShellResolver.js resolveInteractiveShell() — picks the shell binary a PTY session runs (Shell page, agent TUI shells). On Windows the old COMSPEC default meant cmd.exe, where no command a user would type reaches another drive: cd I: silently PRINTS that drive's cwd and stays put, a bare I:\ is "not recognized as a command", and cd 'I:\path' is a syntax error (no single-quote quoting) — so a Windows install with its repos on a second drive was stuck on C:. Resolves PORTOS_SHELL → newest pwsh.exe under %ProgramFiles%\PowerShell\<major> (majors enumerated and sorted numerically, so a future 8 needs no code change) → any pwsh.exe on PATH via findCommandOnPath (scoop/choco/Store shim) → powershell.exe 5.1 (ships with Windows) → cmd.exe last. PowerShell crosses drives with every form. Unchanged on POSIX (SHELL → zsh). resolveInteractiveShellWith({platform, env, exists, readdir, findOnPath}) is the un-memoized injectable form for tests.
openFolder.js openFolderInSystemExplorer(localPath) — cross-platform "open in Finder/Explorer/Nautilus" via detached spawn; child error handler prevents spawn failures from crashing the process.
childProcess.js Drop-in child_process replacement that defaults every spawn to windowsHide: truespawn / spawnSync / fork / exec / execSync / execFile / execFileSync, plus a ChildProcess re-export. Server runtime code must import from here, never from child_process directly (enforced by childProcess.guards.test.js): a console-less PM2 fork spawning a console child without CREATE_NO_WINDOW makes Windows hand the new console to Windows Terminal, which flashes a focus-stealing window. exec/execFile carry util.promisify.custom so promisify(execFile) still resolves to { stdout, stderr }. An explicit windowsHide: false is respected. Background: docs/WINDOWS_CONSOLE.md.
bufferedSpawn.js bufferedSpawn(cmd, args, opts) (structured non-throwing result) + bufferedSpawnOrThrow (throwing adapter), plus killProcessTree, resolveWindowsExecutable, prepareWindowsSafeSpawn, prepareCliSpawn(command, args, env) (composed resolve+wrap for a spawn()-safe pair), needsShell, IS_WIN32, WIN_CMD_SHIMS, MAX_OUTPUT_BYTES, guardChildStdin(child) (attach the no-op stdin 'error' listener BEFORE any stdin.write/stdin.end — a child that dies before reading stdin makes the pipe emit EPIPE, and an unlistened stream 'error' outside the Express request lifecycle takes the whole server process down; call it at every spawn that writes to a child's stdin) + deliverChildStdin(child, payload, label) (its other half: write-then-end() with a synchronously-throwing write caught, the pipe destroyed so a reading child sees EOF rather than hanging, and the failure logged so an empty-prompt run that exits 0 isn't filed as clean), spawnFailureDetail(result, fallback) (the most useful sentence from a failed result — prefers the spawn error, then a stderr line, then a stdout line that isn't bare JSON punctuation, because a --json CLI prints its payload to stdout even when it exits non-zero) — shared buffered-spawn machinery with capped stdout/stderr, timeout SIGTERM plus fire-and-forget SIGKILL escalation (killGraceMs, default 8s), Windows .cmd/.bat shim resolution, and taskkill /T /F tree-kill. killProcessTree(child, signal, { processGroup }) takes the POSIX group down too when the child was spawned detached (Windows always tree-kills). A killable that is NOT a ChildProcess — a node-pty IPty TUI session — is killed through its own .kill(), with no signal on Windows: node-pty throws Signals not supported on windows. for any signal argument, so a signalled kill there killed nothing and threw past the caller. Used by appBuilder.js, appUpdater.js, the CoS agent spawners, and setupScriptRunner.js.
setupScriptRunner.js spawnSetupScript(envVars) / stopSetupScript(child) / SETUP_IMAGE_VIDEO_SCRIPT — the one way to run scripts/setup-image-video.sh (shared by the Video Gen BYOV runtimes, the music engines and the MuScriptor venv). Runs it under resolveBashBinary() with a toBashPath script path, and on Windows presets the PYTHON_BIN the script would otherwise default to python3 for. Cancel via stopSetupScript, which tree-kills so uv / pip / git die with bash.
commandExists.js commandExists(cmd, args = ['--version'], { timeoutMs = 5_000, env, cwd }) — does running cmd args succeed? A capability probe (execFile-based), not a PATH lookup like processEnv.js's whichFirst; env/cwd let a caller check the exact child process configuration. Consolidates the two previously-private copies in localLlm.js/ollamaManager.js; callers probing a heavier CLI (e.g. codeReview.js's reviewer-binary probe) pass a longer timeoutMs. Sibling commandOutput(cmd, args, opts) runs the same probe but returns the trimmed stdout (or null when it could not run / exited non-zero), so a caller can read a --version banner or a models listing without spawning the same child twice.
spawnCwd.js resolveSpawnCwd(workspacePath, fallbackRoot, label) — resolves and logs the working directory a run/agent spawns into (expanding ~), and throws when a workspace was requested but is missing / not a directory. Behind services/runner.js#resolveRunCwd, which turns that throw into a normal failed-run record for the two spawning runners. Stops a bad app repoPath from silently spawning in the PortOS checkout (#3180). usesCreativeDirectorScratchCwd(task) / creativeDirectorScratchCwd(agentId) / removeCreativeDirectorScratchCwd(agentId) / resolveAgentCliCwd({ workspacePath, fallbackRoot, task, agentId }) — Creative Director no-worktree tasks get a per-agent scratch cwd under os.tmpdir()/portos-cd-cwd/<id> (outside the PortOS git tree) instead of the PortOS root, so native CLI AGENTS.md / CLAUDE.md discovery cannot walk up into the repo (#4650). removeCreativeDirectorScratchCwd is the matching finalize cleanup. withSpawnCwdEnv(env, cwd) — returns a copy of env with PWD pinned to cwd (dropping stale case-variant keys), because spawn({ cwd }) doesn't rewrite the inherited PWD and OpenCode resolves its project root as process.env.PWD ?? process.cwd() (#3193). Apply it at every spawn that names its own cwd — the shared wrappers (bufferedSpawn, spawnDetached) already do, so their callers inherit it. spawnCwd.test.js discovers cwd-passing spawns across server/ and fails on any that neither pins nor is listed exempt.
commandSecurity.js Two allowlists, one parser. validateCommand(cmd) gates the OPERATOR-driven runner against ALLOWED_COMMANDS (+ validatePm2Command(args), which rejects daemon-wide pm2 kill/startup/unstartup and <verb> all). validateUnattendedCommand(cmd) gates the UNATTENDED lane (Layered Intelligence cmd sources) against the far narrower UNATTENDED_READONLY_COMMANDS — read-only inspection binaries only, no npx/node/python/pip/curl/wget/brew, since those execute network code with no shell metacharacter — then applies a per-binary SUBCOMMAND gate to the multi-purpose survivors, so git reset --hard / git commit, find -delete / -exec, and gh/glab writes (api -X POST, pr merge) are rejected while git log, find -name and gh pr list pass. Both share one parse + DANGEROUS_SHELL_CHARS body. Mirrored by the agentGuard/ PATH shim for agentic paths.
detachedSpawn.js spawnDetached(bin, args, {controlDir,env,cwd,killProcessGroup?}) → ChildProcess-like handle for a long media job that SURVIVES pm2 restart portos-server. A pure-sh double-fork reparents the job to init (escaping pm2's PPID-based TreeKill — detached:true alone doesn't, since it only changes the process group); the server tails on-disk log files for stdout/stderr/close. Group-kill mode persists a marker so cancel, reattach, and orphan reaping terminate a group-leader wrapper plus every runtime child together. Windows reaches the same place through a powershell supervisor started by a launcher that exits (never detached:true, which there means DETACHED_PROCESS and leaves a console host no console to run in), writing the same control files — so both platforms survive the restart AND take the runner's children down on cancel (taskkill /T /F there, the process group on POSIX). Used by loraTraining + videoGen. Also exports reattachDetached(controlDir) / isReattachable(controlDir) to RE-ATTACH a survivor after a restart, isDetachedRunning(controlDir, expectedProcess?) with optional executable/argument validation for fixed-command control dirs, and reapDetached to checkpoint-kill one when re-attach isn't possible.
hostShutdown.js Tells "PortOS was restarted out from under a running agent" apart from "the agent failed" (#3202). markHostShuttingDown() / isHostShuttingDown() are the in-process latch the SIGTERM/SIGINT handler sets first thing; shouldAbandonForHostShutdown({sentinelPresent,terminatedByUser,paused}) keeps every spawn path on the same preserve-vs-finalize policy. writeHostShutdownMarker({agentIds,signal}) / readHostShutdownMarker() / clearHostShutdownMarker() persist that verdict to data/cos/host-shutdown.json so the NEXT boot's orphan sweep can requeue those agents as interrupted — no orphan-retry charge, no 30-minute cooldown. All non-throwing: a missing marker degrades to the ordinary orphan path.
execGit.js execGit(args, cwd, options) utility imported by git.js + worktree manager. cwd is REQUIRED — it rejects on a missing/blank one rather than letting spawn fall back to process.cwd() and run git against PortOS's own checkout (#4554).
ffmpeg.js Shared ffmpeg helpers (videoGen + videoTimeline). Includes probeFrameCount(videoPath) (metadata nb_frames, falling back to a real -count_frames pass — expensive, so call it once per file) and trimVideoFromFrame(videoPath, outPath, {startFrame, fps}) — a frame-EXACT head cut via the trim filter (an -ss seek can drift a frame, which reads as a stutter at a stitch seam), keeping audio in sync with atrim when the clip has a soundtrack and taking -an when it doesn't. Re-encodes by necessity, so a later concat must re-encode too; outPath may equal the input (temp-file + rename install). Used by the chained-render context window — see videoContinuity.js. buildTrimConcatArgs({inputs, outPath, width, height, fps, withAudio}) builds the argv for the other half of that job: a concat that drops leading frames from some of its inputs inside a filter_complex graph, so the cuts ride along with the timeline encode instead of costing one pre-encode per clip (pass withAudio only when EVERY input has an audio stream — check with hasAudioStream). H264_ENCODE_ARGS / AAC_ENCODE_ARGS are the shared encode profile: clips produced by different paths here get concatenated together, so a mismatch shows up as one segment graded differently from its neighbours — spread these rather than re-typing the flags. Every re-encode here also pins BT.709: BT709_CONTAINER_ARGS (the colr atom, always emitted) plus bt709TagFilter() → the BT709_TAG_FILTER setparams=… string, or null on an ffmpeg without that filter (supportsSetparamsFilter() probes -filters once per process; null = not probed, and a probe that couldn't run stays uncached). Both halves are required — from ffmpeg 8 the encoder reads color properties off the FRAMES, silently overriding the container flags, so a flags-only output decodes washed-out. buildTrimConcatArgs takes the filter as its colorTagFilter option rather than probing, to stay pure.
forkHead.js normalizeForkHead(value) / forkRemoteName(ownerLogin) / resolveTaskForkHead(metadata) — the validated {remoteUrl, ownerLogin} address of a cross-repository PR's head branch, which has no origin/<branch> to attach to. Fail-closed: anything that isn't a usable pair (or that starts with -, which git would read as an option) is null, so every caller falls back to origin-only behavior instead of guessing. forkRemoteName is the deterministic fork-<owner> remote name that makes a re-attach reuse the remote it already added. Shared by appPullRequests.js (produces), agentWorktreeCleanup.js/prRemediationFollowUp.js (persist in task metadata), agentWorkspacePrep.js (threads), and worktreeManager.js (consumes — it has no forge client of its own). resolveTaskForkHead is the single reader of the generic forkHead task-metadata key, the fork-side counterpart to taskTargetBranch.js.
frameQuality.js Scores decoded video frames so a chained render can CHOOSE its continuation anchor instead of taking whatever an end-seek lands on. scoreFrame({width,height,data},{recency}) combines three terms over a raw single-channel buffer: log-compressed gradientVariance (focus), distance of meanLuma from mid-grey (exposure penalty, which rejects a fade-to-black or a blown highlight), and a small linear recency bonus that keeps the anchor near the cut when candidates are comparably clean. Usability and ranking are deliberately separate: usable gates on raw gradient variance against MIN_SIGNAL_VARIANCE alone, so only a mathematically degenerate frame is rejected and a legitimately dark low-key tail still qualifies — the same contract imageFrameStats.js keeps. Gating on the composite score instead would reject every night scene on the exposure term. TAIL_WINDOW_SECONDS is capped at the reach of the single -sseof -1.0 seek this replaces: focus is systematically highest at the OLDEST candidate, so a wider window would widen the backward jump at each chain seam rather than tightening it. pickBestFrame(paths) decodes each candidate through sharp and returns the winner (or null when nothing decodes or every candidate is degenerate, so the caller degrades rather than failing a render); its index is the position in the array AS PASSED, because the caller turns that into the anchor's time offset. MAX_CANDIDATES is derived from the window, never set independently — the ffmpeg-side -frames:v cap truncates from the NEWEST end, exactly the frames recency prefers. TAIL_WINDOW_SECONDS / CANDIDATE_FPS / MAX_CANDIDATES define the window the caller decodes from. Consumer: services/videoGen/local.js#extractLastFrame.
ffmpegRenderGuard.js attachFfmpegRenderGuard(proc, {label, onSpawnError, onProcessError, onClose}) — shared spawn-state tracking + exactly-once terminal guard + pre-vs-post-spawn dispatch for the SSE ffmpeg render runners (musicVideo/render + videoTimeline/local). Owns the 'spawn'/'error'/'close' wiring (only the pre-spawn 'error' or 'close' finalizes; a post-spawn 'error' records only) and takes the service-specific finalize bodies as callbacks so each renderer keeps its own project-status/history behavior.
gitArgs.js PROTECTED_BRANCHES, validateFilePaths(files), isGitStageableFilePath(file) — pure command-arg builders/validators for git.js (reject injection/traversal in staged paths). isGitStageableFilePath is validateFilePaths' non-throwing twin, for callers that must refuse an unstageable path BEFORE writing the file rather than 500 on the commit.
gitCommitProbe.js commitsSince(workspacePath, sinceMs) / committedDuringRun(workspacePath, sinceMs) / runWindowDiff(workspacePath, sinceMs, {maxChars}) — the run-window git probes: how many commits landed with a COMMITTER date inside a run's window (so a rebase/commit by the agent counts, a merely-pulled remote commit does not). The single machine-checkable "did this run commit anything?" primitive shared by finalize's success-criteria evaluation, run completion, runner completion, and orphan recovery — it replaced the unsatisfiable task-id commit-marker grep (#3637). Non-throwing: a non-repo, empty repo, or git timeout is 0. runWindowDiff is the diff half — the accumulated <base>..HEAD text for everything the run committed, base resolved with the same committer-date window so the two probes can't disagree about which commits are the run's. Every failure is a reason string with a null diff, never '': a git that could not answer must not read as a run that changed nothing.
gitForge.js parseGitRemote, parseGitHubOwnerFromRemote, pickGhAccountForOwner, detectForgeCli, parsePullRequestUrl — pure GitHub/GitLab remote + PR/MR URL parsers and forge/account selectors used by git.js.
gitOutputParsers.js parseStatus, parseDiffStat, parseBranchVerboseLine, parseSubmoduleStatusLine/SUBMODULE_STATUS_RE, extractAgentSummary — pure parsers turning git command output into structured data for git.js. extractAgentSummary anchors on agentOutputMarkers' completion marker so a TUI agent's PR body carries its sentinel summary, not the lifecycle telemetry above it. isBenignConcurrentFetchRefRace(stderr) reads a non-zero git fetch as a SUCCESS when its only failure is a lost compare-and-swap whose refs already hold the fetched commits — the routine outcome when the Git tab, getRemoteBranches, and CoS agent worktrees fetch one .git at once.
gitRemote.js getOriginInfo, classifyOriginRemote, parseGitRemoteUrl, readRemoteUrl, UPSTREAM_OWNER/UPSTREAM_REPO — safely reads and classifies checkout remotes against PortOS or a caller-supplied canonical upstream. Used by self-update and managed integrations to detect forks.
repoLinkFields.js deriveRepoLinkFields(url) / normalizeRepoLinkFields(link) / linkIsRepo(link) / repoLinkLabel(link) — the repository metadata a Brain link carries, plus the dual-write/tolerant-read shim that keeps the pre-multi-host isGitHubRepo field names readable across federated peers.
repoUrl.js parseRepoUrl(url){ host, provider, owner, repo } / isRepoUrl(url) / repoCloneUrl(parsed) / repoBrowseUrl(parsed) / parseGitHubUrl(url) / isGitHubRepoUrl(url) — authoritative "is this a clonable repo URL?" rule, with per-host behavior (subgroup nesting, clone layout) in the REPO_HOSTS table. Mirrored to client/src/lib/repoUrl.js (parity pinned by repoUrl.mirror.test.js) so the Brain capture boxes reveal the post-clone agent options for exactly the URLs the server will clone.
glabArgs.js GLAB_JSON_ARGS, withGlabJson(args) — pure glab argv conventions. The JSON output flag is --output json, NOT -F json: on glab issue list (and only there) -F is --output-format (details/ids/urls), so -F json is accepted, ignored, and answers with the human table at exit 0. Shared by all three glab runners so the spelling has one definition; guarded tree-wide by services/gitlab.glabFlags.test.js.
killWithEscalation.js killWithEscalation(proc, {label, stillRunning, delayMs=8000}) — shared SIGTERM→grace→SIGKILL cancel-escalation for spawn-based media jobs. Sends SIGTERM, then escalates to SIGKILL after delayMs only when stillRunning() holds and the child hasn't exited (exitCode===null && signalCode===null). The timer is unref'd and the callback is try/catch-wrapped (runs outside the request lifecycle). Converges musicVideo/render, videoTimeline, imageGen local+codex, videoGen, loraTraining, and the yt-dlp track import cancel paths.
npmGlobalBin.js adoptNpmGlobalBinDir() — puts the directory npm install --global actually writes to onto process.env.PATH, from one cached npm prefix -g. npm resolves its prefix through a config cascade (cli flags, npm_config_*, project/user/global npmrc, a builtin npmrc that interpolates env vars), so guessing it from %APPDATA%/$HOME reproduces the bug on the next host — only npm can answer. Exists because a host whose npm prefix is NOT the directory its Node installer put on PATH (a machine-wide Windows prefix vs the per-user `%APPDATA%
pmdefault,NPM_CONFIG_PREFIX, nvm/Volta) installed codex successfully and then reported it unrunnable, advising a restart that inherits the same PATH. Called at boot in BOTH processes that spawn provider CLIs (services/bootstrap.js, cos-runner/index.js) and again from providerRuntimeInstaller.js`'s probe, because on a first install the prefix directory did not exist when boot looked.
processEnv.js stripDebugMallocEnv(env) / safeChildProcessEnv(extra) — drop macOS Malloc* debug env vars before spawning a child. safeChildProcessOptions(options) adds that sanitized environment plus windowsHide: true, preventing detached PM2 subprocesses from opening transient Windows console UI; buildSafeCliBaseEnv(env, provider) allowlists runtime/delivery essentials and only the selected CLI's ambient provider auth before an AI CLI inherits the server environment. Route Node→Python and other background CLI spawns through the process helpers. Also whichFirst(name) — first-hit which/where PATH probe (safe options, 5s timeout) returning the absolute binary path or null; whichFirstSync(name) provides the same contract without the await; findCommandOnPath(name, { env, cwd }) resolves an executable from the exact child environment without needing which itself on that PATH. adoptPathDirs(dirs) appends the ones that exist and are not already there to THIS process's process.env.PATH (case-insensitively on Windows), which fixes this process AND every child, since the env builders above derive from process.env — the only fix that reaches a CLI launched by BARE NAME through node-pty. Shared by npmGlobalBin.js and services/llamaServerManager.js's winget-shim adoption.
branchUpstreamGuard.js enforceSafeBranchUpstream(repo, branch) / readBranchUpstream / isSafeBranchUpstream — the agent-branch upstream invariant (#4172): a branch handed to a CoS agent tracks either NOTHING or its OWN ref, never refs/heads/main. git worktree add -b <b> <path> origin/main does not leave the branch untracked — branch.autoSetupMerge records merge=refs/heads/main — and /do:pr derives its push destination from that config (git push <remote> HEAD:<merge>), so the agent's work lands straight on the default branch with no PR. Prevention is --no-track at the worktreeManager.js creation sites; this is the backstop that also REPAIRS branches created before the fix (drops the bogus upstream, logs it) and throws only if the repair doesn't take. Fails CLOSED: readBranchUpstream returns null for could-not-read (distinct from '' = genuinely unset), and an unverifiable upstream is refused rather than waved through — worktreeManager.js undoes the worktree add on refusal so the throw can't strand a tree. Pairs with primaryCheckoutGuard.js, which catches the other way agent work reaches main.
primaryCheckoutGuard.js capturePrimaryCheckoutState(path) / detectPrimaryCheckoutDrift(baseline, {agentBranch}) + PRIMARY_CHECKOUT_MUTATED_REASON/_CATEGORY — the branch-jack detector (#3680): stamps the PRIMARY checkout's branch + HEAD onto a worktree agent's metadata at spawn (agentLifecycle.js) and re-reads it in the shared finalize path (agentFinalization.js), so a worktree-isolated agent that commits to the primary is recorded as a FAILURE naming the drifted branch, the commit count, and the git reset --hard recovery — instead of a silent "completed". Detect-and-report only: the reset discards commits, so it stays a human decision. Non-throwing (runs outside the request lifecycle); an unreadable checkout reports no drift rather than inventing one.
pythonSetup.js Python venv / runner setup helpers.
vttTranscript.js WebVTT/SRT → readable prose. vttToPlainText(vtt) (paragraph-joined transcript), vttToLines(vtt) (cleaned caption lines), cleanCaptionLine(line). Collapses YouTube auto-captions' rolling repetition and strips inline <c>/timestamp markup. Used by the brain YouTube ingest.
youtubeIngestFormat.js Pure data transformations for the brain's YouTube ingest (#6015): parseVideoMetadata(json) (yt-dlp --dump-single-json → the stored metadata shape, incl. the subtitles-vs-automatic_captions manual-caption signal), buildIngestNote({meta,url,transcript,tags,agentPrompt,capturedAt}) (the Obsidian note, whose YAML frontmatter the user's own vault queries key on — every interpolated scalar goes through yamlString), buildAgentTaskContext(...) (the CoS follow-up prompt, including the untrusted-transcript boundary notice), resolveObsidianPointer({written,vaultId,notePath,prior}) (keeps the prior note pointer when an ATTEMPTED mirror failed, so an evicted note can't be orphaned — #3706), plus sanitizeFilename, formatDuration (seconds → h:mm:ss) and yamlString. No fs/db/childProcess/SSE imports; orchestration and storage stay in services/youtubeIngest.js. Surfaced through the barrel as a NAMESPACE export (youtubeIngestFormat.*) because formatDuration collides with fileCore.js and sanitizeFilename with mimeTypes.js.
youtubeUrl.js Canonical YouTube single-video URL rule (#6014). YOUTUBE_VIDEO_URL_RE (accepts watch/shorts/live/embed plus the www./m./music. hosts, rejects playlists, channels, and /@handle feeds), youtubeVideoIdFromUrl(url) (alias youtubeVideoId), isYoutubeVideoUrl(url), assertYoutubeVideoUrl(url) (returns the id, else throws 400 YOUTUBE_URL_INVALID), and the shared YOUTUBE_URL_INVALID_MESSAGE. Single source for the brain ingest, the Takeout importer, the history scrape, and the Music Video track import; mirrored in client/src/lib/youtubeUrl.js and pinned by youtubeUrl.mirror.test.js.
ytdlp.js findYtDlp() — cached discovery of the yt-dlp binary on PATH, mirrors findFfmpeg() in ffmpeg.js. Used by the track YouTube-import job.

Networking

Module Purpose
httpClient.js Fetch-based HTTP client factory (axios.create replacement). insecureFetch size-cap rejections carry code: RESPONSE_TOO_LARGE.
abortTimeout.js withAbortTimeout(timeoutMs, fn) — runs fn(signal) under an AbortController that aborts after timeoutMs and always clears the timer on settle. Generic lifecycle helper for callers that need the insecure-agent peerFetch (so can't use fetchWithTimeout) or one signal across parallel fetches.
fetchWithTimeout.js fetch wrapper with AbortController timeout.
tailnetPeer.js isTailnetPeer(peer) — fail-closed security predicate for "is this peer reachable only over the tailnet". Deliberately separate from instances.js's peerRequiresTailscale() probe-deferral heuristic so a polling-noise tweak can't widen a privacy boundary; required by the unattended-routing gate in ADR 2026-08-20-federated-visual-prompts.
federatedMediaRequest.js Builds and validates the versioned federated-media submission body for a visual kind, so every call site that persists a remote-job marker projects local params onto the wire identically.
federatedMediaWire.js Versioned federated-media status schema/constants plus fail-closed consumer freshness checks (stale and clock-skewed snapshots are never assignable). FEDERATED_MEDIA_FEATURES + federatedMediaSupports(status, feature, capability) answer "does the peer BUILD speak this wire feature" from the status-root features list — the one place the "absent reads as the wire-v1 baseline" rule lives; a published list wins outright, with the inputAssets capability block retained as its only legacy overlap tell because it is genuinely per-model. federatedMediaDeclaresFeatures(status) and federatedMediaDeniesFeature(status, feature, capability) separate "positively denied" from "could not establish" for MESSAGE selection only — both gate identically, and which missing signal indicts the peer’s build is recorded per feature rather than at each call site.
connectivity.js isMachineOnline({timeoutMs?, hosts?}) — internet-reachability probe: bare TCP connect to public anycast resolvers on :443 (no DNS, no HTTP), resolves true on the first connect and false only after all fail; never rejects. Reuse when a caller needs a best-effort local reachability signal.
safeUrlFetch.js SSRF-guarded public-URL fetch: isPublicHttpUrlSafe/assertPublicHttpUrl (scheme + blocked-host-literal via catalogValidation.isBlockedIngestHost + DNS-resolve), exported strict isPrivateAddress, plus fetchPublicText/fetchPublicBinary (timeout, redirect revalidation, size cap) and buildPinnedLookup/buildPinnedDispatcher (the connect-time IP pin that closes the DNS-rebinding TOCTOU). Reuse instead of copying the SSRF guard for any "fetch this remote thing the user pointed us at" flow. Also readBodyCapped(response, maxBytes) bounds streamed bodies without choosing a network policy.
pinterestFeed.js Pure Pinterest board RSS helpers: normalizePinterestFeedUrl(input) (board URL or .rss{ feedUrl, boardUrl }, host-gated) + parsePinterestRss(xml) (per-pin pinUrl/imageUrl/title/description, 736x size upgrade). Feeds the mood-board Pinterest importer.
requestAbort.js abortSignalFromResponse(res) — AbortSignal that fires only when an Express client disconnects before the response finishes (keyed off res close + writableEnded). Plus anyAbortSignal(signals) — combine several signals into one (native AbortSignal.any with a Node-18 fallback).
readResponseJson.js Read a Response body as JSON, tolerating a non-JSON/HTML error page (no Unexpected token < crash). Object callers need no opts; pass { fallback, emptyValue } for arrays or to surface the raw error text.
peerHttpClient.js Federation HTTP/Socket.IO client (TLS validation off — Tailnet is the trust boundary).
peerSelfHost.js Tailscale-issued hostname this PortOS sends in federation.
peerUrl.js Build the base URL for a peer.
sharingOrigin.js Origin metadata for records imported from share buckets.
syncIntegrity.js Pure diff of local vs remote manifest lists. INTEGRITY_STATUS constants + computeRecordIntegrity(localList, remoteList) — classifies each record as in-parity, local-only, peer-only, diverged, or assets-missing. No I/O.
syncWire.js Single source of truth for what fields cross the federated-peer wire (snapshot loop + per-record push agree).
tailscale.js Locate the Tailscale CLI binary, flag the sandboxed macOS App-bundle build, and return a normalized backend/MagicDNS/peer snapshot (getTailscaleStatus / isTailscaleUp).
httpsState.js Captures whether PortOS booted with HTTPS active.
bareUrl.js parseBareUrl(text) — returns the normalized URL when a captured string is nothing but a URL (bare host gets https://), else null. Drives the brain-capture short-circuit that files a pasted URL straight to Links instead of running the classifier. Stricter than the client's urlNormalize.js isUrl (needs a plausible TLD; http/https/git@ only) because it picks a storage destination rather than a hint.
isSafeHref.js Pure http(s)-only scheme check (isSafeHref) for user-supplied URL fields that get rendered as a clickable <a href> — rejects javascript:/data:/etc. stored-XSS payloads. Mirrors client urlNormalize.js's isHttpUrl.
networkExposure.js Runtime scheme/bind/cert snapshot plus the shared ordered Tailscale, MagicDNS, certificate, and trusted-launch setup guide used by CLI and UI; localApiBaseUrl() resolves the plain-HTTP loopback origin (mirror port under HTTPS, API port otherwise) for local scripts and agent-facing curl snippets.

Search & indexing

Module Purpose
bm25.js BM25 ranking + inverted-index helpers.
vectorMath.js Vector math utilities (cosine, etc.).
memoryQuery.js Pure memory-index helpers: meta projection, filter/sort, search/hybrid meta filters, RRF fusion.
memoryStats.js macOS-correct memory accounting (handles "Pages free" quirk).
rrfRanking.js Pure reciprocalRankFusion(textResults, vectorResults, options) — merges two ranked lists via RRF scoring (Cormack 2009). Used by catalogDB.hybridSearchIngredients.

Extraction & parsing

Module Purpose
clientApiPaths.js Static scan of the paths client/src/services/api*.js requests, for the client↔server route-parity guard (apiRouteParity.test.js). `scanClientApiPaths({ repoRoot
htmlToText.js Shared HTML → plain-text converter. htmlToText(html, { extraEntities?, paragraphBreak?, collapseSpaces? }) — strips script/style/head/noscript blocks, converts <br>/block closes to newlines, strips remaining tags, decodes entities via decodeXmlEntities, collapses 3+ newlines, trims. Options preserve caller-specific output (Gmail: paragraphBreak: '\n\n' + collapseSpaces; SongBook import: defaults — space runs preserved for tab alignment).
jsonExtract.js Pull JSON blocks out of LLM responses. findBalancedBlocks walks top-level blocks and stops at the first unbalanced one; findAllBalancedBlocks is the stack-based variant that scans past stray braces and returns nested blocks in closing order (reverse it for outermost-newest-first).
taskParser.js Parse TASKS.md format.
cosTaskPrompt.js The CoS task prompt/note split (#4153) — metadata.prompt is the full agent-facing payload, metadata.context the one-line human note. isPromptPayload(value) is the single discriminator (a newline means it's a prompt, not a note), shared by the store's write path and the on-disk migration so they can't classify the same task differently. getTaskPrompt(task) prefers metadata.prompt and falls back to a legacy metadata.context; getTaskContextNote(task) returns the note only on an already-split task; taskContextBlock(task) renders both as one block so prompt templates (including customized ones) never see the split; splitTaskPromptFields(metadata) routes a multi-line context to prompt at CREATE time only. Pure, dependency-free.
taskPauseHold.js The user-PAUSE hold — pure metadata helpers shared by the writer (pauseAgent), the reader (resumeAgent), and the clearer (updateTask). AGENT_PAUSED_CATEGORY is the blockedCategory a pause stamps; PAUSE_METADATA_KEYS names every key it writes; pauseMetadata({agentId, pausedAt, workspacePath, runId}) arms it and clearedPauseMetadata() releases it (undefined-valued, so updateTask deletes rather than serializing "null"); isAgentPausedTask(task) / isResumablePausedTask(task, agentId) answer whether a pause is still live and whether it is THIS agent's. updateTask clears the whole set whenever the task leaves blocked, so a revive by any path (dedupe, cooldown expiry, manual unblock) can't leave a task running under a stale pause. Also carries the cycle-safe RELEASE adapter (#3730) agentManagement.js registers at load — resolvePausedTaskResume(task) hands updateTask the paused run's resume pointer before the write (so any un-block resumes on the preserved worktree, not just the Resume dialog) and retirePausedAgent(agentId, taskId, branchName) retires the paused record after it.
taskBlockCategories.js The blockedCategory vocabulary — which blocks are the system's to clear and which are a person's, read by the pause logic, the failure reaper, and the investigation auto-retry so they can't drift into three literal sets. PAUSED_BLOCKED_CATEGORIES (paused until something outside the task changes — keeps the resume pointer), USER_DECISION_BLOCKED_CATEGORIES (user intent / open decision — the reaper's exemption), NON_AUTO_RETRY_BLOCK_CATEGORIES (their union — a completed investigation must never revive these), TIMED_COOLDOWN_BLOCKED_CATEGORIES (a timer clears these — the cooldown sweeper revives them, so block reporters stay quiet), PROVIDER_CONFIG_BLOCKED_CATEGORY (the shared literal the agent-spawn stamp site uses, so the stamp cannot drift from the two sets it belongs to). Pure.
taskRequeue.js The REQUEUE stamp (#3376) — pure metadata helpers for the one BACKWARD lifecycle step (in_progress → pending, performed by the orphan sweep and the retry-hold release). REQUEUED_AT_KEY / LAST_SPAWNED_AT_KEY name the two stamps; isPostSpawnRequeue(pendingTask, inProgressTask) answers whether the requeue happened strictly AFTER that spawn, which is how the federated merge tells a real requeue apart from an ordinary edit landing on a peer's stale pending copy. Returns false when either stamp is missing, so callers fall back to the lifecycle rank.
taskRetryHold.js The failed-task RETRY HOLD state (#3373) — pure metadata helpers shared by the failure verdict, the post-cleanup release, the spawn guard, and the orphan sweep. retryHoldMetadata(agentId, now) arms it (task stays in_progress, so no dequeue tier can claim the retry before its resume pointer is resolved); clearedRetryHoldMetadata() releases it in the same write that flips the task to pending; isRetryHeld(metadata) / isRetryHoldOwner(metadata, agentId) gate the spawn and the owner-scoped release; isStaleRetryHold(metadata, now, graceMs) + RETRY_HOLD_GRACE_MS let the orphan sweep finish a transition whose process died.
taskTargetBranch.js Pure task-branch contract: resolveTaskTargetBranch(metadata) reads a retry's legacy existingBranch or a review-loop follow-up's canonical reviewLoopPRBranch; shouldStripTaskTargetBranch(metadata) identifies only retry-owned pointers for terminal cleanup.
taxonomyTally.js Generic taxonomy tally + top-N-line render engine shared by the two Layered Intelligence leaf taxonomies (services/layeredIntelligenceRejections.js, layeredIntelligenceExecutionFailures.js). createTaxonomyTally({predicate, select, field, vocabulary, sentinel, glossFn, gapWording}) is the single composed seam — it binds a taxonomy config into {summarize, format}, where summarize(records) yields the three-bucket {entries, unknown, unclassified, diagnosed, total} tally (commonest-first + taxonomy-order tie-break) and format(records, limit) renders one prompt line naming every non-zero gap. Also exports the two leaf utilities the classifiers use directly: normalizeToken(value) (lowercase + separator-collapse for label/category matching) and formatTaxonomyToken(token, labels) (gloss-map render, nullish→'', unglossed passthrough). Pure leaf — imports nothing from the LI graph.
worktreeOwnership.js Pure ownership gate for destructive worktree operations. worktreeOwnershipReason() applies root, agent-id, lock, active-agent, liveness and claim policies IN THAT ORDER, so an unconditional hold always outranks a claim and callers never re-derive the precedence from the slug; the claim hold has two opt-outs (allowStaleClaim for reapers, allowLiveClaim for the dispatch side). worktreeAgentId() is separator-safe; isHumanClaimWorktree() and isAgentWorktreeId() make the protected namespaces explicit; worktreeHoldExpiresAt() names when a hold lapses on its own (the stale-claim window) so callers can wait exactly that long.
xmlEntities.js Shared dependency-free XML/HTML entity decoder. decodeXmlEntities(str, extraEntities?) — single-pass (double-decode-safe) decode of the five predefined named entities + decimal/hex numeric refs, with an optional caller-supplied extra-entity map (e.g. { nbsp: ' ', zwnj: '' }). Unknown/out-of-range refs left untouched. Used by the Apple Health XML parser, Claude changelog feed, Pinterest RSS, generic feeds, and Gmail HTML-to-text.

Curated static data

Module Purpose
curatedGenomeMarkers.js SNP classification logic (classifyGenotype, formatGenotype, resolveApoeHaplotype) + MARKER_CATEGORIES; loads the ~116-marker dataset from the co-located curatedGenomeMarkers.json at module init.
songCraftRef.js Server-side mirror of the a cappella rhythm-shape + voice-layer vocabulary (RHYTHM_SHAPES, VOICE_LAYERS, DIRGE_RHYTHM_SHAPES) injected into the song generate/evaluate prompts so the model returns ids the editor pickers understand. Mirrors client/src/lib/songCraft.js.

Domain utilities

Module Purpose
appIdentity.js The baseline managed-app id (PORTOS_APP_ID) — importable without pulling in the services/apps.js graph (pm2, scheduler, settings) behind it. Re-exported by apps.js.
appResolver.js Fuzzy-match a spoken/typed phrase to a managed app ({ id, name }). Tiered exact → prefix → substring, used by voice tools that target a specific app.
capabilityMap.js Pure row builders for Setup & Capabilities, including strict network/provider first-run readiness and optional-integration health rollups; fed by routes/capabilities.js.
chiptuneRender.js Deterministic chiptune score → mono PCM → 16-bit WAV buffer (pure Node, no audio deps); renderScoreToPcm / pcmToWavBuffer / renderScoreToWav.
chiptuneScore.js Chiptune score contract (#2911): chiptuneScoreSchema (Zod) + sanitizeChiptuneScore, pitch math (pitchToMidi/midiToFreq), and buildScoreEvents — the pattern/order → absolute-time flatten mirrored by client/src/lib/chiptunePlayback.js.
civitai.js Civitai URL parsing + API client.
huggingfaceLora.js HuggingFace LoRA import helpers: parse HF ref → {repo,revision,file}, fetch /api/models metadata, select an exact or family-matching .safetensors, detect the image or video LoRA family (flux2 / ltx-video / …), build the sidecar + resolve download URL. The HF analogue of civitai.js. Pure.
huggingfaceModel.js HuggingFace base-model (image/video) classifier for the self-service "add a model" flow (#2124): inspect repo siblings + card → decide the loadable runtime/runner, STRICTLY refuse GGUF-only / wan / hunyuan / unclassifiable repos (so a bad add can't wedge the picker), build the media-models.json entry (source:'user'), + a searchHuggingfaceModels Hub-search helper. Pure.
localLlmCatalog.js Curated cross-backend (Ollama↔LM Studio) local-LLM catalog + install-id mapping for the migrate flow. Pure.
modelAbuseGuard.js Pinned model-abuse boundary contract: Prompt Guard metadata, deterministic abuse signals, complete classifier-window coverage validation, chunk/timeout limits, fixed dependency versions (MODEL_ABUSE_GUARD_PYTHON_PACKAGES), and MODEL_ABUSE_GUARD_STAGES / modelAbuseGuardStageReadiness for the operator-facing install checklist. Pure.
localLlmDisk.js Pure on-disk reasoning for the migrate "copy GGUF locally instead of re-downloading" fast-path (Ollama manifest/blob parsing, LM Studio path layout, MLX/projector/shard detection) plus the Hugging Face registry addressing used to finish an abandoned Ollama pull.
specDecodePresets.js Curated llama-server speculative-decoding presets (target + drafter GGUF paths, --spec-type, and the Hugging Face repo/quant each file comes from) plus findSpecDecodePreset / specDecodeSource / hfSearchUrl. Also owns the --spec-type vocabulary: SPEC_TYPE_SUGGESTIONS (published to the launcher card), parseSpecTypes (the flag is a comma-separated list) and isDraftSpecType (the draft- prefix is what needs a drafter GGUF — every ngram-* type runs without one). Server-owned so the launcher card can offer a Download button per file. Pure.
llamaCppInstall.js Where a llama.cpp install comes from on this host, for services/llamaServerManager.js. llamaCppInstallPlan(platform) → the frozen descriptor for that platform's package manager — Homebrew on macOS/Linux (brew install llama.cpp), winget on Windows (winget install ggml.llamacpp) — carrying manager, managerLabel, packageId, installCommand, the install/upgrade (and, for winget, list/upgrade-check) argv, and the three refusal strings a caller would otherwise hardcode: missingManagerError, notInstalledError, pathRepairHint. The LLMs page renders installCommand out of the llama-server status payload, which is what stopped a Windows install prompt from telling the user to run Homebrew. Also the winget-side readers Homebrew needs no equivalent for: parseWingetPackageFields(stdout, id) (winget has NO machine-readable output mode and LOCALIZED table headers, so fields are read positionally from the tokens after the id token — Version [Available] [Source]; null = not installed), wingetLinkDirs(env) (the portable-shim directories winget adds to the USER PATH, which an already-running server has not inherited) and isWingetManagedPath (counterpart of the manager's isHomebrewLlamaServer: a source build earlier on PATH must not be offered a winget upgrade). Every WinGet path is reasoned about with path.win32 regardless of host, so both branches are coverable from a macOS/Linux checkout. Pure.
ollamaContext.js Ollama runtime context-window reasoning. resolveOllamaContextLength(provider, env) → the window PortOS should hold the daemon at (provider.numCtx, then OLLAMA_CONTEXT_LENGTH, then null = leave Ollama's VRAM-based auto-pick alone); withOllamaContextEnv(env, n) builds the ollama serve child env; parseOllamaContextOverflow(text) recognizes the exceed_context_size_error rejection and pulls { promptTokens, contextLength } out of either the JSON body or the human message; describeOllamaContextOverflow / describeOllamaContextTooSmall render the actionable one-liners; isSameOllamaDaemon(providerBase, managedBase) compares host+port so a provider pointed at a remote Ollama never triggers a local-daemon reload; OLLAMA_AGENT_MIN_CONTEXT is the window below which an agent harness is warned. Pure — the daemon side lives in services/ollamaManager.js (ensureContextWindow), the pre-spawn enforcement in services/ollamaAgentContext.js.
localModelHeuristics.js Capability heuristics for untyped local (Ollama/LM Studio) models. isEmbeddingModel/isGenerationModel (so a generation/fallback run never picks an embedding model like nomic-embed-text); isVisionModel(model) (string id or model card — prefers explicit type:'vlm'/capabilities:['vision'] metadata, falls back to id regex; used by the LoRA captioner); recommendEditorialModel(models, { measured }) ranks installed models for editorial review/editing, dropping any a fresh measurement proved cannot run here. Pure. Mirror isEmbeddingModel/isVisionModel in client/src/utils/providers.js.
localModelAssessment.js Scoring for MEASURED local-model assessments (recorded by services/localModelAssessments.js): classifyFitVerdict (fits/does-not-fit/incompatible/unknown), summarizePerformance (mean/peak chars-per-second AND tokens-per-second, prefill rate, TTFT, max working context, cross-context degradation), scoreAssessment + scoreForIntent + rankByIntent for the balanced/smartest/fastest/lightweight pickers, explainAssessment, compareEnvironments/describeStaleness (is a stored reading still valid for THIS machine?), buildThroughputReport (every measurement as one tokens/s table, fastest first, per-context readings intact), selectSweepTargets/summarizeSweepScopes/SWEEP_SCOPES (which measurements a "measure everything" run covers, and how many), and measuredFitVerdict/reconcileFit (fold a measurement into the catalog's size-estimate fit badge, keeping the disagreement). Pure. null strictly means NOT MEASURED — never 0, never "failed".
localModelTuning.js Launch/runtime tuning knobs for the measurable local runtimes — ONLY knobs PortOS can actually apply. A knob is defined by its transport, and applies + the user-facing note are DERIVED from it: config (llama.cpp's -b/-ub/-t/--parallel/--flash-attn/--cache-type-k|v/--spec-draft-n-max, via launchConfig), env (Ollama's OLLAMA_CONTEXT_LENGTH/_FLASH_ATTENTION/_KV_CACHE_TYPE/_NUM_PARALLEL, via launchEnv), cli (a flag on the launch line of a daemon PortOS re-runs — LM Studio's lms load --context-length/--gpu/--parallel, and MTPLX's mtplx serve --context-window/--depth/--generation-mode/--kv-quant/--batching-preset/--profile — via launchArgs), or wire (a request-body field, via requestBody — currently no members). vLLM declares none: PortOS does not start it, so there is no launch line to put a flag on. Read the MTPLX verification note in the module before adding an mtplx serve flag — it exits before it binds on one it does not recognize. Also normalizeTuning (coerce + clamp + drop unknown keys), tuningSignature (stable identity — '' for backend defaults, so pre-tuning store keys keep resolving), describeTuning, launchTuning, and compareTunings (which tuning won per model using exact tokens/s when all variants have tokenizer counts and chars/s otherwise, labelled from each record's persisted tuningLabel, with a deltaPercent against the winner), and tuningGridFor (the candidate grid a tuning sweep runs — backend defaults plus one variant per knob declaring a sweep value, capped by maxVariants; sweepWith carries a knob's documented prerequisite). Pure.
loraTriggers.js Pure trigger-word weaving for renders that load a LoRA (#4665): weaveLoraTriggers(prompt, triggerWordLists){ prompt, added } appends each selected LoRA's FIRST activation token to the prompt when it is not already there, in selection order, as a trailing comma clause so the user's own phrasing keeps its position and weight. promptHasTriggerWord is the whole-token, case-insensitive presence test (aria_tok does not match inside aria_token); firstTriggerWord picks the canonical token out of a Civitai trainedWords list. Idempotent, so a re-render of an already-woven prompt is a no-op. Consumed by services/imageGen/local.js and services/videoGen/local.js (paired with services/loras.js#readTriggerWordsByFilename for the sidecar reads). The comic pipeline shares it rather than opting out — its own " ()" clause uses the same token, so the weave adds nothing there except for the characters that clause drops.
issueLength.js Per-issue size targets fed into text stages.
musicDuration.js Lyric-aware MiniMax Music 3 duration analysis and ending-cushioned auto-duration recommendation; mirrors client/src/lib/musicDuration.js.
learningVerdict.js The three-way success-criteria verdict a completed agent run carries on result.validationPassed (#4107). true/false = a declared criterion was met/missed; null = none declared (record the run, fall back to the exit code); SKIP_LEARNING_VERDICT = nothing ever evaluated the run, so task-learning must not record it at all (a programmatic-I/O output hook that bailed on no-app/app-not-found). isSkipLearningVerdict(v) gates the skip; toValidationVerdict(v) narrows anything non-boolean — including the sentinel — back to null for downstream telemetry. JSON-safe string (not a Symbol) because the verdict is persisted and read back by the learning backfill, and older readers already narrow on typeof v === 'boolean'. Pure.
investigationTasks.js Investigation-task identity, approval, auto-retry, and PR-backed delivery policy — shared by the producers (services/investigationTaskProducer.js), the reaper (cosTaskStore.js, which used to hand-copy the predicate to dodge an import cycle) and the retry (services/investigationRetry.js). isInvestigationTask(task) (durable isInvestigation marker, falling back to the INVESTIGATION_HEADLINE_PREFIX headline for pre-#2615 / peer-synced tasks); INVESTIGATION_TASK_DELIVERY keeps unattended investigations in an isolated worktree and routes them through a PR merged on green, while CLIENT_INVESTIGATION_DELIVERY + clientInvestigationFingerprint({description, app}) give a UI-queued investigation (#6043) the same isolation with a review-then-merge PR and a server-derived ui-investigation dedup key the client cannot hand-craft; buildInvestigationFingerprint(task, analysis) / investigationFingerprint({category, kind, scope}) → the category:kind:scope dedup key; resolveInvestigationApproval({fingerprint, tasks, recentCreations}) → unattended by default (#3714), held only on a repeat-fingerprint or failure-storm loop, with approvalReason + loopProse for the queue UI; couldReleaseBlockedTasks(investigation) is the pure pre-read gate for resolveInvestigationRetryTargets({investigation, tasksById}), which returns the failure-blocked tasks a just-completed investigation releases plus every skip and its RETRY_SKIP_REASONS reason (an auto-expired completion, a non-blocked task, a NON_AUTO_RETRY_BLOCK_CATEGORIES block, or a task past MAX_AUTO_RETRIES_PER_TASK); autoRetryMetadata(task, investigationId, now) stamps the budget that survives the revive's own failureCount reset. Pure.
mediaItemKey.js <kind>:<ref> key vocabulary for media items.
assetProvenance.js Stamp-time model/LoRA license provenance (buildProvenance / provenanceForRender / rollupProvenance). Unknown stays null (displayed as "unknown") — never a permissive default. Mirrored byte-for-byte to client/src/lib/assetProvenance.js.
avatarVariants.js Rigged-record avatar variant spelling (RIGGED_VARIANT_PREFIX, AVATAR_VARIANT_PATTERN, parseRiggedVariant, riggedVariantForId, isAnimatedRecordReady) — the rigged-<modelId> namespace over ?variant=, sharing the route's strict traversal guard.
migrationMarker.js Shared marker-file helpers for one-time migration/repair/reconcile scripts — markerExists(filename) (boolean gate), readMarker(filename) (parsed payload or null), writeMarker(filename, payload) (atomic write). All anchor filename under PATHS.data and use tryReadFile/atomicWrite so a crash can't leave a truncated marker.
goalFeatureMap.js Deterministic goal category → PortOS feature-area map (deep-links sourced from NAV_COMMANDS). getGoalFeatureAreas(goal) honors the per-goal featureAreas override, else the category default. Mirrored byte-for-byte to client/src/lib/.
goalFidelity.js Goal-fidelity review contract (#5994) — the value half of "does this diff deliver what was asked?", the question the quality-review chain structurally cannot answer because it never sees the request. GOAL_FIDELITY_VERDICTS (ship / fix-first / rethink, only rethink gating a run via goalFidelityHoldsRun), taskObjective(task) (the trusted operator-authored objective — the TASK's description + prompt block, never the agent's transcript, since a reviewer handed the transcript inherits the assumptions that produced the drift), resolveGoalFidelityConfig(codeReview, chain) (enabled/backend/model/effort, restricted to the local-LLM reviewers PortOS can call server-side and falling back to the quality chain's own local reviewer + its <backend>Model/Effort scalars), normalizeGoalFidelityVerdict(parsed) (null = nothing judged the run, never collapsed into a ship pass or a rethink hold) and formatGoalFidelitySummary(review). MAX_OBJECTIVE_CHARS / MAX_FIDELITY_DIFF_CHARS bound what crosses into a fixed-window local model. Pure.
navManifest.js Single source of truth for nav (⌘K palette + voice). Add an entry when you add a page.
noReplaceMove.js moveWithoutReplace(from, to) — publish a staged file into its final name WITHOUT ever clobbering an existing one. fs.rename silently replaces its destination, which is the wrong default for a derived artifact; this uses link(2) + unlink(2), so an existing destination fails atomically with MOVE_DEST_EXISTS and both files survive. Refuses rather than degrading when the filesystem cannot express it (MOVE_CROSS_DEVICE, MOVE_NO_REPLACE_UNSUPPORTED) — a stat-then-rename fallback would be a race. Used by the rigging publication contract (services/rigging/autoSkin.js).
personaTraitBlend.js Digital-twin persona trait-blending (M34 P7). Blends a persona's traitAdjustments against the base twin's communication profile + Big-Five into a "Communication Calibration" directive. Mirrored to client/src/lib/.
textUtils.js Pure dependency-free prose helpers. countWords(text) is the canonical whitespace-token count (\S+); trimTo(value, max) trims and bounds strings without coercing non-strings, and is safe for shared modules consumed by the browser; escapeRegExp(value) is the one to import instead of re-inlining the escape (a guard in textUtils.test.js fails the suite when a copy reappears in any non-test source under server/, or in ANY source under client/src/, tests and .jsx included — the escape half is mirrored on the client at client/src/lib/textUtils.js, which the browser imports since it cannot reach server/lib); kebabCase(text) is the canonical ASCII slug transform (PLAN.md [slug] ids and planner:<model> labels).
pipelineIssueOrder.js Pure renumber algorithm for pipeline issues.
postAdaptive.js Pure POST adaptive-difficulty policy — nudges a math drill's primary knob (steps/maxDigits/maxExponent/tolerancePct) up/down within clamped bounds from recent scored performance. Opt-in via the config Adaptive toggle.
postAppliedNumeracy.js Pure seeded Applied Numeracy pack — everyday percentage, ratio, unit, rate, and estimation scenarios plus server-authoritative numeric/fraction/unit scoring with explicit tolerance handling.
postMultiplicationLadder.js Pure progressive multiplication ladder — mastery-gated difficulty rungs ([1,1][1,2][1,1,1] → …). Resolves the user's current level from per-level speed+accuracy stats so the plain multiplication drill ramps up instead of starting at a fixed hard difficulty. On by default. Built on postProgression.js.
postPowersLadder.js Pure technique-anchored Powers ladder — cumulative named-method pools, full supported-pair registry, and speed+accuracy mastery progression built on postProgression.js.
postProgression.js Generic mastery-gated progression ladder (extracted from postMultiplicationLadder.js) — createProgression({ levels, describeLevel, speedTargetForLevel? }) resolves a user's current rung from exact-level sample, accuracy, completion, and optional speed evidence with an anti-demotion floor. Also defines meaningful cognitive-drill ladders (including task switching, Go/No-Go, and Flanker) and their level→generator-config mapping.
spacedRepetition.js The shared SM-2-inspired review scheduler, extracted from services/meatspacePostMemory.js when SongBook practice became its second consumer (#4102). One four-field schedule shape ({ ease, intervalDays, nextReview, lastReviewed }, no repetitions counter — the 0 → 1 → 6 → round(prev * ease) ladder derives from the previous interval, so a schedule round-trips through import/export/federation on those four fields alone). advanceSchedule(schedule, ratio, now) is the core (ease clamped to MIN_EASE..MAX_EASE, interval capped at MAX_INTERVAL_DAYS so new Date(now + interval*DAY) can't overflow into an Invalid Date; quality < 3 zeroes the interval to resurface the record but still applies the ease penalty). mergeScheduleAdvance(prev, advanced, now) gates interval GROWTH to once per review day (a shrink always applies) for UIs that submit per chunk/section; isSameReviewDay is that gate's own predicate, reusable by callers gating their own once-a-day progression. scheduleOrDefault(record, schedule?) is the read-path fallback — a record with no schedule derives one anchored to its updatedAt/createdAt (stable and in the past → due now), so "due" can't flap between two reads a millisecond apart. ratioToQuality / qualityToRatio are exact inverses over the integers, so a self-graded 0..5 review lands on the quality the user picked. isScheduleDue treats an absent/unparseable nextReview as due — a record we can't schedule is one to surface, never one to hide forever. Pure.
songPractice.js SongBook repertoire practice scheduling (#4102) — the pure core behind POST /api/brain/songbook/:id/practice. applySongPractice(song, quality, now){ stage, practice }, the exact partial to hand brainStorage.updateWith: it advances the shared spacedRepetition schedule from a 0..5 self-grade and moves the song's stage along SONG_STAGE_ORDER (≥ SONG_PROMOTE_MIN_QUALITY promotes, ≤ SONG_REGRESS_MAX_QUALITY regresses, a 3 holds). Promotion is gated to once per practice day (regression never is), and a practiced song floors at learningnew means "never picked up", which stops being true after one session. songPracticeOrDefault(song) derives the schedule on READ for every song predating the feature (nothing is backfilled to disk: a migration would restamp updatedAt on every record and spray federation churn, and would break the data.reference/ seeds' byte-identity). nextSongStage no-ops on a stage this install doesn't recognize, so a practice log can't rewrite a value synced from a newer peer. isSongDue(song, now) mirrors the client's songDueAt in client/src/components/songbook/constants.js. Pure.
postTopics.js Pure POST practice-topic registry — POST_TOPICS ({ id, label, module, surface, drillTypes }) is the single source of truth for "what am I studying?", plus resolveTopicForDrillType / isTopicEnabled / isMemoryItemEnabled. Gates session composition and recommendations, including Memory's composed and dedicated practice routes plus standalone Morse. Mirrored to the client's post constants.js (parity test).
postRotation.js Pure deterministic day-based rotation for POST practice selection — orderByRecencyRotation sorts candidates fresh-before-recently-practiced, then by priority, and rotates equivalent ones by local day so a tier never pins to one drill. Mirrored at client/src/lib/postRotation.js.
postStreak.js Pure DST-safe POST practice-streak math — the single computePostStreaks implementation shared by scored sessions and the training log, plus computeUnifiedStreak (a day is active with EITHER a session or a practice entry), normalizeYmd (day-key prefix for a date that may be a full ISO timestamp), and recordDayKey / withDerivedDayKeys (re-derive a record's day key from its startedAt/completedAt/timestamp instant, so readers ignore a date frozen in a previously-configured timezone).
activeDays.js Cross-domain "days active" set math (#4120) — unionActiveDayKeys(sources, timezone) unions several domains' stored date values into one sorted array of user-local YYYY-MM-DD keys (.length is the honest day count; summing per-domain counts would double-count any day logged in two domains), and toUserDayKey(value, timezone) is its per-value normalizer. Owns the day-boundary reconciliation between POST (stamps userLocalToday()) and the health logs (stamp the server-local getDateString()): a value carrying an INSTANT (the pre-#2681 full-ISO shape some legacy training entries still store) is re-keyed into the user's timezone rather than split('T')[0]'d to the UTC day, while a value that is already a bare day LABEL is taken as authored — there is no instant left to re-derive from, so retro-normalizing stored health keys is out of scope by construction, not by omission. Non-day values are dropped rather than coerced. Pure.
planIds.js Utilities for PLAN.md [slug] IDs.
markdownText.js stripMarkdownEmphasis(text) — unwrap **bold** / ~~struck~~ / `code` / [text](url) and drop HTML comments, keeping the words. For strings handed to something that can't read markdown (a model's text encoder, a slug builder, TTS); leftover lone *_~ become spaces so an unbalanced marker can't fuse two words. Does not collapse whitespace — callers that need that normalize themselves.
renderSlot.js Render-slot helpers for (proof|final)Image per stage.
renderTargets.js Render-target alphabet (#3231): RENDER_TARGET/RENDER_TARGETS name every creative surface that enqueues renders (universe-bible, sprite-reference, music-video, …) — the keys into settings.renderDefaults — plus the RENDER_TARGET_BACKEND_AUTO fall-through sentinel. Dependency-free leaf; resolved per surface by services/imageGen/cloudProviderConfig.js#resolveRenderTargetConfig.
renderTiming.js renderTimingFields(startedAtMs, nowMs?) → the { renderMs, renderStartedAt, renderCompletedAt } spread every image/video backend stamps on the record it persists, measuring ingestion → finished artifact (not queue wait). Returns {} when no start instant was observed, so absence stays the explicit unknown sentinel for the history cards and services/videoGen/eta.js. omitRenderTiming(record) is the inverse, for a DERIVED record built by spreading its source (an image variant) that must not inherit a duration it never took.
telegramClient.js Telegram bot client.
telegramMessage.js Pure builder for the Telegram notification wire message, shared by both transports (services/telegram.js and services/telegramBridge.js, which drifted apart while each kept a copy — #5688). buildNotificationMessage(notification, { approvalBody }){ text, options }: emoji + escaped title, the body truncated to TELEGRAM_MAX_RAW_CHARS (2800) BEFORE escaping so the escaped result stays under Telegram's 4096 cap and a slice can't split an entity, the priority line, and the memory approve/reject reply_markup as a plain OBJECT (both transports post JSON, so a pre-serialized string would arrive as a literal string). approvalBody is resolved by the caller because the memory lookup is I/O. Also exports escapeHtml, truncateForTelegram, isMemoryApprovalNotification, the NOTIFICATION_EMOJI/PRIORITY_EMOJI maps (keyed by literal NOTIFICATION_TYPES values to stay a dependency-free leaf; pinned to the real enum by a parity test), and the CALLBACK_APPROVE/CALLBACK_REJECT prefixes the bot's callback_query handler parses back out.
telegramRateLimit.js createTokenBucket({ max = 30, refillMs = 60_000 }){ consume() } — the coarse full-refill-per-window bucket both Telegram transports use against Telegram's ~30 msg/min throttle. Each transport creates its OWN instance: they are never both active, and one shared bucket would let a transport inherit the other's drained budget. Pure (reads Date.now(), owns no timer).
tempPathGuard.js Throwaway-path guard for destructive test fixtures. isTempPath(target) — true only for an absolute path that is a STRICT descendant of os.tmpdir() after symlinks are resolved (os.tmpdir() itself is refused, or destroyGitSandbox(tmpdir()) would wipe every process's scratch; a .. segment is refused rather than lexically collapsed; macOS /var/folders/... and /private/var/folders/... both pass). assertTempPath(target, operation) throws otherwise and returns target so it can wrap an argument inline. Use it before any fixture git init / git config / rm -rf: spawn silently substitutes process.cwd() for a missing cwd, which is how a test run once set core.bare = true on a real checkout (#4554).
vaultCrypto.js Privacy Center PII Vault field-level encryption (issue #2140). AES-256-GCM encryptValue/decryptValue (v1:<iv>:<tag>:<ct> format, per-value 12-byte IV), ensureVaultKey() self-heal (generates PRIVACY_VAULT_KEY into the install root's .env on first write, replacing any invalid line; never logs the value), key resolution that falls back to reading .env so decrypt/status survive a server restart, isVaultKeyConfigured(), and the per-type maskValue(type, plaintext) display masking (last-4 / domain-visible / street-masked). Plaintext must never be logged by callers.

Model & config

Module Purpose
browserConfig.js Shared custom browser path helpers for deriving macOS app bundles, detecting configured browser choices, normalizing browser config, and validating Chrome-compatible binary paths.
condaEnv.js Resolves a NAMED conda environment's interpreter: condaEnvPythonCandidates(envName) builds the ordered candidate list (CONDA_PREFIX — walking up two levels when it points at an envs/<name> rather than a root — then CONDA_ROOT, ~/miniconda3, ~/anaconda3, ~/miniforge3, ~/mambaforge, /opt/conda), and resolveCondaEnvPython(envName, { exists }) returns the first that exists or null. Separate from pythonSetup.js (which probes venv layouts and computes candidates from PATHS at module load) so a conda lookup pulls in no eager path work. Used by the image-to-3D CUDA lanes, which each own a distinct env (trellis2, pixal3d) so one lane's pinned deps can't disturb the other's.
cudaCapability.js NVIDIA CUDA host probe — the one place that shells to nvidia-smi. detectCudaGpus() / cached getCudaCapability() return { available, status, gpus, maxVramGb } where status is three-way: 'available', 'absent' (no driver, or driver present with zero GPUs), or 'unknown' (nvidia-smi exists but wouldn't answer — available is null, never false, so callers can say "couldn't detect" instead of lying about the hardware). unknown is not memoized so a transient driver hiccup retries. parseNvidiaSmiGpus(stdout) is the pure CSV parser (a [N/A] VRAM column yields vramGb: null, not a dropped GPU). Gates the image-to-3D local-cuda lane and the Windows FLUX.2 CUDA-torch wheel choice (pythonSetup.js#hasNvidiaGpu). detectCudaComputeCapability() / cached getCudaComputeCapability() are a SEPARATE nvidia-smi query (--query-gpu=name,compute_cap,memory.total, parsed by parseNvidiaSmiComputeCaps) returning primaryComputeCap — the arch of the LARGEST card, since a render uses one GPU — for build flags like NATTEN's NATTEN_CUDA_ARCH and SGLang provider filtering; kept separate because an older driver rejects compute_cap and would fail the whole VRAM query with it. detectCudaUtilization() / getCudaUtilization() add live per-GPU utilization on a short TTL.
systemCapabilities.js Machine-local capability snapshot plus the shared three-state hardware requirement evaluator. Captures coarse platform, architecture, Apple Silicon, memory, CPU, and cached CUDA facts; derives requirements for media models, local-LLM catalog entries, and provider runtimes; hides only known-incompatible choices while preserving unknown probe results.
db.js PostgreSQL connection pool.
db/ Boot DDL for the PostgreSQL schema, split per domain (#2832). db/schema/index.js re-exports each module's statement array and composes the two ordered lists ensureSchemaImpl() runs on every boot (buildUpgradeDdl() then buildCatalogDdl()). Statement order is load-bearing — append inside the domain module and leave the composer order alone. See db/schema/README.md for the module catalog.
pgTimestamp.js mirrorTimestamp(value, fallback) — coerce a hand-editable timestamp into a value Postgres TIMESTAMPTZ always accepts (or fall back), guarding boot-time binds against Date.parse rollover + out-of-range years.
pgTools.js pg_dump binary resolution shared by the backup snapshot path and the native↔Docker export path: resolvePgDumpBinary(serverMajor) (PORTOS_PGDUMP override → version-aware auto-select → bare pg_dump), plus the lower-level pickPgDump / discoverPgDumpCandidates / resolvePgDump. Picks the closest installed pg_dump whose major is ≥ the running server's.
ports.js Canonical PORTS object (re-exported from ecosystem.config.cjs).
platform.js Platform/OS detection helpers — listening-port probes plus isAppleSilicon() (arm64 darwin; gates MLX model features, detect at the route boundary).
signalCrypto.js Pure, dependency-free crypto for reading Signal Desktop's encrypted chat DB (#2154): SQLCipher-4 page decryption (decryptSqlcipherDatabase, deriveSqlcipherKeys, sqlcipherPageHmac — PBKDF2-SHA512 HMAC key + AES-256-CBC per page + HMAC-SHA512 verify → plaintext SQLite buffer the built-in node:sqlite can open) and Chromium/Electron safeStorage unwrap (decryptSafeStorageValue, deriveSafeStorageKey — macOS AES-128-CBC + PBKDF2-SHA1 over the keychain password). All functions return { ok, ... } reports (never throw) for graceful degradation. Consumed by services/signalSync.js.
timezone.js Timezone utilities for scheduling. getLocalParts(utcDate, timezone) / getUtcOffsetMs(utcDate, timezone) are the primitives; nextLocalTime(afterMs, hours, minutes, timezone) finds the next UTC instant matching a local HH:MM. anchorLocalMidnightUtc(dayStr, tz) resolves the first UTC instant belonging to a local date, including zones whose DST transition skips 00:00; localDayWindowUtc(timezone, atDate?) exposes an inclusive ISO-string window, while localDayRangeUtc(dateStr, timezone) returns a validated half-open { start, end } Date pair ending at the next local-date boundary so 23h/25h transition days remain exact. Also owns HHMM_RE/HHMM_STRICT_RE, parseHHMM, and isWithinTimeWindow (mirrored client-side in client/src/utils/timeWindow.js).
tribeCadence.js Authoritative, pure Tribe care-cadence rules (single source of truth, mirrored to client/src/lib/tribeCadence.js): cadenceStatus(entity){ state: external/missing/overdue/soon/steady, daysRemaining, daysOverdue }, daysSinceDate(dateStr), DEFAULT_CADENCE_DAYS (45), SOON_WINDOW_DAYS (7). Consumed by personCadenceStatus / getCareSummary in services/tribe.js (proactive alert + Care widget) and by the client Tribe page/map.
tribeMatch.js Pure, deterministic matcher mapping a calendar attendee / message counterpart ({ email, phone, name }) to a tracked Tribe person for auto-logged touchpoints (#2033, #2151): buildPersonMatchIndex(people){ byIdentifier, byPhone, byName }, matchPerson(identity, index) (email/handle authoritative, then E.164 phone, then exact unique name fallback — no fuzzy matching), matchPeople(identities, index) → de-duplicated Set of personIds, normalizeIdentifier(value), normalizePhone(value) (E.164 normalization for iMessage/Signal handles), identityFromHandle(handle) (classify a raw chat.db handle into email-or-phone). Consumed by autoLogTouchpoints in services/tribe.js from the calendar, message, and iMessage sync producers.
viteAllowedHosts.js Detect and remediate a managed app's Vite server.allowedHosts. findViteConfig(repoPath) locates the config; parseAllowedHosts(src) / hostIsAllowed(parsed, host) decide whether a Tailscale/IP host would be accepted (mirrors Vite's localhost+IP-always-allowed and leading-dot-suffix rules); rewriteAllowedHosts(src) deterministically injects allowedHosts: true (or bails ok:false on ambiguous shapes so the caller can fall back to an LLM fix); checkViteHost(repoPath, host) is the one-shot status used by GET /api/apps/:id/vite-host-check.
buildId.js Build-ID derived from the built client bundle.
buildIdentity.js getBuildIdentity() / getCachedBuildIdentity() / formatBuildIdentity() / parsePorcelainV2() — which git commit the RUNNING server process was started from (#4694): { commit, shortCommit, branch, dirty } from ONE git status --porcelain=v2 --branch spawn, cached per process (the promise, so concurrent first callers share it). Answers "is this the code I am testing?" on a machine where one PM2 server serves :5555 while many worktrees hold different code — version cannot, since package.json's version is identical across every development commit. Served on its own GET /api/system/build, NOT on /health/details: peers scrape that payload and persist it verbatim, and this stays machine-local. Complements buildId.js (bundle hash, not commit), which travels separately on the build:id socket frame — the socket path reaches peer relays, so the commit does not use it. Non-throwing, every field independently nullable (no .gitcommit: null, never '').

General utilities

Module Purpose
apiAccessPolicy.js Shared always-public path and gated non-/api prefix policy consumed by both authGate and API discovery.
apiCatalog.js Searchable projection of the generated Express route manifest: domain, access, side-effect, contract coverage, summaries, and Express-to-OpenAPI path conversion.
socketEventCatalog.js Searchable projection of the cached Socket.IO inventory: direction, domain, and runtime-schema coverage.
sourceScan.js Lexer-assisted primitives shared by the whole-tree source-scan guard suites, so the timer rule and the socket rule cannot drift on what "owns its rejection" means. blankLiterals(src) blanks comment/string/template/regex CONTENT to spaces while preserving length, so a brace inside a literal cannot skew a bracket walk and a caller can still read a literal (a socket event name) out of the original string at the same offset; matchBracket(src, open) returns the index past the matching )/]/}; parseCallbackAt(blanked, from, limit) parses the function expression at from (async/function/either arrow spelling, skipping the parameter list as a unit so a = {} default is not mistaken for the body) and returns {isAsync, start, text}; unguardedAwaits(body) returns the awaited chains that neither sit inside a try/catch nor END in .catch(…). blankComments(src) is the weaker LINE-based stripper the per-line child_process rule needs. Callers: childProcess.guards.test.js, server/timerCallbackConventions.test.js, server/sockets/asyncHandlerGuard.test.js, server/process-safety-net.test.js.
apiOperationContracts.js Detailed operation metadata for intentionally public APIs. It consumes the canonical route Zod contracts and feeds both public and internal OpenAPI documents.
apiRegistry.js Single source of truth for which PortOS services are externally-callable HTTP APIs (voice, sdapi). API_REGISTRY declares each API's publicPrefixes (read/compute-safe surface only) + defaults; isRegistryPublic(settings, path) tells authGate when an exposed && !requireAuth API re-opens its prefix; resolveApiAccess(settings) merges persisted apiAccess flags for the Settings UI + OpenAPI docs.
arrayUtils.js shuffle(arr) — Fisher-Yates shuffle (new array, never mutates). The canonical uniform shuffle — never arr.sort(() => Math.random() - 0.5), which is biased. Shared by meatspacePostCognitive.js (Schulte table / mental rotation) and meatspacePostMemory.js (memory drill generators). dedupeByKey(items, keyOf, pick?) — one survivor per key, first-seen order. Required before any multi-row INSERT … ON CONFLICT (key) DO UPDATE: Postgres refuses the whole statement ("ON CONFLICT DO UPDATE command cannot affect row a second time") when its VALUES list names one conflict key twice, and the rows a batcher joins usually come from something that promises no uniqueness (a disk scan, a peer payload). DO NOTHING upserts are exempt. pick(held, candidate) defaults to last-seen-wins (what a sequential one-row upsert loop leaves); pass a comparator when the table's conflict rule isn't "latest write" — memorySync.applyRemoteChanges keeps the newest updatedAt so a peer's payload ordering can't flip a last-writer-wins outcome. Used by services/mediaAssetIndex/db.js and services/memorySync.js.
assetRoutePrefixes.js Import-free leaf holding the URL prefixes the server owns: ASSET_ROUTE_PREFIXES (every /data/** static mount) and SERVER_OWNED_PREFIXES (what must never reach the SPA fallback, each with the exact spaPaths that ARE client routes). scripts/dev-proxy-drift.test.js checks the dev proxy's ^/data/ wildcard against the mounts, pins the route-registration order in server/index.js (a router added below the terminators is shadowed), and fails if a client route — from NAV_COMMANDS or App.jsx's nested <Route> tree — is ever added under a server-owned prefix without being declared.
asyncMutex.js Promise-based async mutex.
concurrencyGate.js createConcurrencyGate(limit)run(fn) — cap on simultaneous async work for ONE module-scoped budget, released FIFO. Sibling to mapWithConcurrency.js, which caps in-flight work within one array map; a gate is shared state, so several call sites fanning out at the same remote respect one budget instead of each respecting its own while the host sees the sum. createMutex (asyncMutex.js) is this with limit fixed at 1 — prefer it for mutual exclusion. Note the budget is per-MODULE, not per-host: two modules calling one host each get their own gate. Used by huggingFaceCatalog.js (4) and ollamaRegistryCatalog.js (16), whose cold catalog-enrichment bursts otherwise arrive at a free public API as a thundering herd — which the Hub answers with an HTTP/2 GOAWAY that surfaces as a bare fetch failed.
dispatchLabels.js slashdo dispatch-hint contract: model:light/medium/heavy + effort:low/medium/high/xhigh/max vocabulary, prescribed forge colors, validation (normalizeDispatchModel / normalizeDispatchEffort), GitHub/GitLab vs Jira label formatting, optional contributor labels (good first issue / help wanted, never implied by model:light, and released at claim time by formatContributorLabelReleaseCommands — one best-effort command per label, since a forge fails the whole edit when a named label is absent), the one shared volunteer-claim policy (volunteerClaimLabels / formatVolunteerClaimCommands — a human comment claiming an unassigned issue is resolved by BOTH issueWatcher.js's deterministic pass and the claim prompt's Phase 1 handoff, so both stamp in-progress and retire the invitations rather than writing opposite state), the open-ended planner-attribution axis (planner:<model>, normalizePlannerId / resolvePlannerId / formatPlannerLabelGuidance — records WHICH model wrote the plan, prefix-matched by dispatchLabelSpec so it lazily creates like the fixed labels; a filing agent takes the value from its prompt, never from self-identification), the workflow-state markers (EPIC_LABEL/EPIC_DECOMPOSED_LABEL and IN_PROGRESS_LABEL — state, not hints: shared with perpetualWork.js#isActionableIssue, issueReconcile.js's zombie scan, issueWatcher.js's volunteer assignment, and the claim prompts), lazy-create command text, the optional --label slots a rendered issue create example offers (OPTIONAL_ISSUE_LABEL_FLAG_SLOTS / formatOptionalIssueLabelFlags — one list so a new axis reaches every prompt template's copy-pasteable command, not just its prose), and shared dispatch plus issue-quality guidance (ISSUE_QUALITY_GUIDANCE, DISPATCH_HINT_GUIDANCE, JIRA_DISPATCH_HINT_GUIDANCE). Omit an unjustified axis; never invent medium; reject future-only/speculative work while keeping useful current refactors claimable. Consumed by work-tracker instructions, quota-burn audits, Layered Intelligence filing, and claim follow-up prompts.
domainAutonomy.js Per-domain autonomy guardrails (pure). AUTONOMY_DOMAINS/DOMAIN_IDS/DOMAIN_MODES (off/dry-run/execute), getDomainMode(config, id), and normalizeDomainAutonomy(raw) to coerce a hand-edited/partial map. Default per domain is execute (reproduces pre-#711 behavior, so no migration needed). Also CREATIVE_DOMAIN/getCreativeAutonomyMode(config) (#2183) — the Creative Director orchestrator domain, kept out of DOMAIN_IDS and defaulting to mirror the cos mode.
domainBudgets.js Per-domain daily autonomy budgets (pure). BUDGET_LIMIT_FIELDS (maxActionsPerDay/maxMinutesPerDay), getDomainBudget(config, id), normalizeDomainBudgets(raw), hasBudget(budget), and evaluateBudget(budget, usage){ withinBudget, exceeded }. A null/non-positive cap means unlimited (default per domain, so no migration needed). Token/$ caps are intentionally absent — CLI subscription providers expose no per-run metering. Usage ledger + gate wiring live in services/domainUsage.js.
eidoverseWorldDesign.js Immutable Eidoverse World Design V1/V2 registry, legacy override migration, semantic district contract, 48-signal ceiling, and deterministic library-only asset-recipe resolution/locking for the PortOS Luminous Systems Garden.
eidoverseWorldLabels.js The comp.label component PortOS attaches to every entity it projects into Eidoverse (eidoverse-worlds#5), so a rendered building says what it represents instead of only naming its decorative model. buildEidoverseLabel(component) reads one already-built comp.portos payload and returns {name, description?, visibility, offset?} — district and world-identity landmarks always visible, live indicators labelled nearby, path markers inspect-only so a walkway cannot bury the district it leads to — and null for anything not managedBy: 'portos', so a caller cannot label somebody else's entity. Names and descriptions are built from PortOS's own vocabulary (district label, kind label, resource category, coarse status, freshness) plus an opaque hashed resource ref for disambiguation, never from record contents, machine identity, addresses, or filesystem paths — the append-only world log is the strictest privacy boundary PortOS writes to. Also owns safeWorldText, the one control-character/length sanitizer shared with services/eidoverseWorldProjection.js so a component field and the label built from it cannot disagree about what is safe. Pure.
errorHandler.js ServerError + asyncHandler middleware, plus sendErrorResponse/buildErrorEnvelope for the standard { error, code, timestamp } body outside a handler's catch.
extensionErrors.js isExtensionError(payload) — true when a client error report came from a browser extension's injected content script (extension URL scheme in source/stack/message, or a short list of vendor/runtime message signatures) rather than from PortOS. Consumed by services/clientErrors.js to keep un-actionable extension noise out of the Review Hub and out of the 1/sec throttle slot, where it would displace real errors. Authoritative copy — mirrored at client/src/lib/extensionErrors.js, parity enforced by extensionErrors.mirror.test.js.
fetchErrorChain.js describeFetchError(err) flattens a fetch rejection's whole cause chain (depth-bounded, cycle-guarded) into one searchable code: message string — undici reports every network failure as the same opaque TypeError: fetch failed with the real reason nested inside, so a classifier reading only err.message misjudges every one of them. isReplayableConnectionError(err) is the narrow predicate over that string for connection-REUSE artifacts (HTTP/2 GOAWAY, reset, hang-up) that are safe to replay once via fetchWithTimeout's shouldRetry; it deliberately EXCLUDES timeouts, which broader classifiers like ollamaManager's isTransientPullError include.
isoWeek.js ISO-8601 week identity — the single source of the YYYY-Www week id. getWeekId(date) keys on the ISO week-numbering year (the calendar year of that week's Thursday), not date.getFullYear(), so one ISO week is never split across two ids and two weeks never collide on one (#3465). Also isoWeekParts, getIsoWeekNumber, getIsoWeekYear, parseWeekId (null on garbage), and isoWeeksInYear(year) (52, or 53 in a leap-week year). Shared by productivity week aggregates and weekly digest filenames.
snapshotChecksum.js The two snapshot-checksum flavours a sync category can want. snapshotChecksum(data) hashes JSON.stringify — insertion-order SENSITIVE, correct only where the getter already canonicalizes its own ordering (dataSync.js, digital-twin-sync.js). canonicalSnapshotChecksum(data) hashes canonicalStringify, so two converged machines hash identically regardless of the order they learned the data (peerUsage.js, whose payload is a map keyed by wire-supplied instance ids). Picking the wrong one is not a crash — it is two synced peers whose checksums never match, which the sync UI reads as "behind" forever.
lwwTimestamp.js Last-writer-wins timestamp comparison for cross-instance sync merges. parseTsMs(s) (Date.parse → epoch ms or null), compareNewerWins(candidate, incumbent) (true iff candidate strictly newer; unparseable-loses, tie → incumbent — used to decide remote-overwrites-local), compareEarlierWins(a, b) (−1/0/1 earliest-wins tiebreak; unparseable-loses). Single source of the LWW polarity shared by mergeMediaCollectionsFromSync / mergeAuthorsFromSync etc.
syncManifest.js Wire contract for the snapshot-sync MANIFEST leg — the fix for a category that is always dirty AND a map of per-instance slots (usage), where one instance advancing dragged every other instance's digest across the wire. isManifestEnvelope(value) validates a { data: { instances }, checksum } response (a legacy peer that 404s the endpoint fails it, and the puller falls back to the whole snapshot); diffManifestSlots(remoteInstances, localInstances) returns the sorted slot ids whose REMOTE LWW stamp is strictly newer than ours — exactly the slots worth fetching. Comparison goes through lwwTimestamp.js, so a tie breaks to what we already hold. Consumed by syncOrchestrator.syncDataCategoryFromPeer; served by dataSync.getManifest.
mapWithConcurrency.js Generic bounded-concurrency async mapper that preserves input order while capping in-flight work.
markedSection.js Marker-delimited section replacement (pure). buildMarkers(id){ start, end } HTML-comment marker pair; replaceMarkedSection(content, body, markers) splices/replaces/removes an auto-generated region without touching surrounding user content (idempotent); extractMarkedSection / hasMarkedSection read it back. Powers the daily-log activity-digest auto-drafts (#2155) via brainJournal.upsertAutoSection().
objects.js Object utilities — deepMerge (recursive merge w/ array replacement), isPlainObject (non-null, non-array object guard for JSON / LLM payloads), POLLUTING_KEYS (shared __proto__/constructor/prototype denylist for sanitizers), canonicalStringify (recursive sorted-key JSON serialization for cross-machine content hashing), isEmptyScalar (true for null/undefined/whitespace-string/empty-array — merge gap-fill gate).
openapiSpec.js Builds two OpenAPI 3.0.3 documents: the Settings-controlled exposed public surface and the complete internal HTTP inventory. Detailed operations reuse canonical Zod contracts; generated operations are visibly labeled rather than claiming unmodeled schemas.
openapiDowngrade.js OPENAPI_VERSION plus toOpenApi30Schema / toOpenApi30Operation, which rewrite Zod's draft-2020-12 output (null unions, numeric exclusive bounds, const, tuples, propertyNames) into the OpenAPI 3.0.3 dialect. Apply ONLY at the OpenAPI document boundary — the AsyncAPI payloads, CoS provider tool definitions, and tool resource read the same schemas as plain JSON Schema, where these rewrites silently widen bounds and drop null branches.
orchestrationProfile.js Orchestrated CoS execution (#5992) — ORCHESTRATION_MODES / ORCHESTRATION_ROLES (architect, implementer, reviewer), normalizeOrchestrationProfile / normalizeOrchestrationMode, isOrchestratedTask / roleAssignment (both inert on a direct task, so a stored profile stays opt-in), the six-part SPEC_PARTS contract a delegated context-free lane needs, plus parseReasoningDirective (an unsupported rung is an error, never a silent downgrade).
apiToolResource.js Builds the minimized semantic tool resource served at /api/api-docs/tools.min.json — only x-portos-tool-annotated operations, flattened to provider-neutral tool records with an HTTP binding and a shared error vocabulary.
asyncApiSpec.js Builds the AsyncAPI 3 Socket.IO document from the generated event catalog with direction-aware operations and explicit modeled/generated payload status.
mergeGateContract.js mergeGateOwed({taskOpenPR, ownsPrWorkflow, leaveOpen}) decides whether a completing run actually owed its own PR merge; resolveMergeGateVerdict({prProbe, summary, alreadyReprompted}) classifies a run that did (merged / unreadable / leave-open-stated / needs-reprompt / reprompt-exhausted) from the PR's live state and the agent's own sentinel text; summaryStatesLeaveOpen and buildMergeGateReprompt are its text-matching and corrective-prompt helpers. Pure — the PR lookup lives in ../services/prProbe.js, the re-prompt delivery in agentTuiSpawning.js.
prDisposition.js resolvePrCompletion(metadata) resolves the explicit review-then-merge / merge-on-green / leave-open policy, with legacy reviewLoop fallback; leavesPrForHuman(task) + PR_STAYS_OPEN_TASK_TYPES keep JIRA hand-offs open. Shared by the agent prompt builder and agentWorktreeCleanup so both halves agree. resolvePrCreation({taskOpenPR, agentOwnsPr, prClaimVerified}) → a PR_CREATION tri-state (never / if-missing / always) naming who opens the change request for a completing worktree agent, so the runner, TUI, and direct-CLI completion paths cannot drift into double-firing gh pr create.
prHandbackPolicy.js Whose turn it is on a public PR the pr-reviewer coordinator reviewed but did not merge. resolvePullRequestWriteAccess(pr) reads isCrossRepository/maintainerCanModify into a PR_WRITE_ACCESS reason, failing closed on an unknown head-repository relationship; resolveHandbackDisposition({requestedChanges, notMergeReady, downgraded, deferred, canEdit, remediationExhausted}) returns a PR_HANDBACK verdict — remediate (PortOS pushes the fixes and lands it), assign-opener (the PR goes to its author queue), or none. A deferred or unanchorable review never becomes an agent work order. Pure.
prReviewReport.js Owns the structured PR-decision contract end to end: PR_REVIEW_DECISION_CONTRACT is the envelope both review producers (pr-reviewer stage 3, issue-watcher reasoning pass) interpolate into their prompts, normalizeReviewReport bounds what comes back, reviewReportText hands every model-authored string to the abuse scan, and renderReviewBody/renderFinding turn it into the markdown a human reads on the PR page — verdict banner, scope line, blocking/non-blocking index anchored to path:line, test-evidence bullets (TEST_EVIDENCE_STATUSES keeps fail for "the change is broken", with expected-fail and blocked for the non-zero exits that say nothing about it), notes, collapsed verified-claims list, and inline comments with an optional GitHub suggestion block. Bounded by MAX_REVIEW_BODY_CHARS, dropping whole low-priority sections instead of truncating mid-sentence. Pure.
repoStateExpectations.js Post-completion repo-state audit, pure half. resolveRepoStateExpectation({...}) answers whether one finished worktree agent should be audited — naming every not-audited path via REPO_STATE_SKIPS (a failed run is preserved for its retry; a review-loop follow-up or pr-watcher pending merge still owns the branch) — and returns just staysOpen + prExpected, from which classifyRepoStateIssues(expectation, observed) derives every check into REPO_STATE_ISSUES codes. Observations are tri-state: null ("could not ask") never produces an issue. repoStateVerificationEnabled(app) reads the per-app verifyRepoStateOnCompletion switch (unset = on). Probing + remediation live in services/agentRepoStateVerification.js.
shellCd.js buildCdCommand(path, shell) + formatShellCommandLine(command, args, shell) + detectShellFlavor(shell, platform?) + quoteForShell(value, flavor, position?) — build cd and arbitrary command-token lines for the shell a PTY session is ACTUALLY running (cmd.exe → Windows-escaped double quotes, PowerShell → doubled single quotes with & for a quoted command token, everything else → POSIX shellQuote). The Shell page's "cd to app" picker used to hard-code the POSIX form, which on Windows both mis-quoted the path and silently refused to cross drives (a bare cd does not switch drive). Flavor comes from the shell binary name, not the platform, so git-bash on Windows still gets POSIX quoting. formatShellCommandLine joins a command + argv into one quoted line and is shared by agentTuiSpawning.js#buildTuiSpawnConfig and the AI Providers page's "Launch in Shell" deep link, so a hand-launched TUI provider is quoted exactly the way the CoS runner would quote it. Renders the LINE only; the Enter byte that submits it is SUBMIT_KEY in tuiHandshake.js.
shellExit.js buildRunThenExitCommand(commandLine, shell) — "run this CLI, then close the shell with its status", in the dialect the session speaks. An agent TUI shell exists only to host one CLI and must die with it. The POSIX cmd; exit $? was applied everywhere and is actively wrong off-POSIX: in PowerShell $? is a BOOLEAN, so exit $? reports success as 1 and failure as 0 (inverted) — use $LASTEXITCODE, pre-seeded to 1 so a command that never ran still exits non-zero; in cmd.exe ; is an argument separator, so the CLI is handed ;/exit/$? as arguments — use & exit. Verified against node-pty on Windows 11 for pwsh 7, PowerShell 5.1 and cmd.exe.
shellLivenessProbe.js buildLivenessProbeCommand(shellPid, platform?) + parseLivenessProbeOutput(stdout, shellPid) + shellHasLiveChild(shellPid, opts?) — platform-aware process-liveness probe for a launched TUI command in a persistent PTY shell. POSIX (ps -Ao ppid=) / Windows (Get-CimInstance Win32_Process | Select-Object -ExpandProperty ParentProcessId via PowerShell). Resolves true (assume alive) when the probe fails or cannot run.
runnerAgentLiveness.js CoS Runner GET /agents liveness. Presence in the runner's handle map is not proof of life: runnerAgentLivenessFields produces processActive + liveness (pty from TUI onExit bookkeeping, pid from a CLI probe) so Windows ConPTY pid: 0 no longer reports every TUI as dead; runnerEntryShieldsRunningRecord is the corroboration gate both zombie/orphan sweeps use before a listing can keep a durable running record.
shellQuote.js shellQuote(value) — POSIX single-quote escaping for values interpolated into shell command strings (display command lines, copy-paste blocks in agent prompts). Bare-safe tokens pass through; everything else is single-quoted. Canonical escaper — don't hand-roll.
shellReadinessProbe.js buildReadinessProbe(nonce, shell) — the round-trip "can this shell actually run commands yet?" probe createShellSession's waitForPromptReady sends and watches for, in the dialect the session speaks: POSIX printf '%s\n' 'PORTOSRDY''<nonce>' (unchanged), PowerShell Write-Output ('PORTOSRDY' + '<nonce>'), cmd.exenull (no split-literal concatenation operator exists there, so the caller skips straight to the bounded fallback timer instead of risking an always-matching probe). The split-literal property is load-bearing in every dialect: the probe source never contains the assembled marker, so seeing it in the output can only mean the shell executed the probe.
sidecarProcess.js runSidecarProcess({bin,args,env,signal,onStage,onProcess}) + parseSidecarResult(stdout) — the shared Python-sidecar STAGE:/RESULT: wire-protocol runner (spawn, tail-capped stdout/stderr, per-STAGE-line callback, abort/SIGTERM → canceled, non-zero exit → stderr-tail reason). Used by pipeline/musicGen.js (all music backends) and audioMidiTranscription.js (MuScriptor).
slashdoCatalog.js The single catalog of which bundled slashdo workflows PortOS offers as a one-click agent run — SLASHDO_WORKFLOWS ({command, label, description, icon, templateName, templatePrompt?, settings, appTypes, configurable?}), getSlashdoWorkflow() (the allowlist gate for POST /api/cos/tasks/slashdo), SLASHDO_COMMAND_NAMES, slashdoWorkflowsForApp(isSwiftApp), SLASHDO_APP_TYPES, and the two run-shape postures WORKFLOW_OWNS_ITS_OWN_GIT (commit-shaped) / WORKFLOW_REPORTS_NO_CODE (report-shaped — carries worktreeChangesExpected: false so a filed-issue/printed-report run retains its non-code deliverable posture). Backs the Agent Operations buttons, the CoS quick templates (taskTemplates.js), and the route allowlist, replacing two catalogs that had drifted. Mirrored in client/src/lib/slashdoCatalog.js (button styling only), pinned by slashdoCatalog.test.js.
slashdoInvocation.js Resolves how a bundled slashdo workflow is invoked on a given host CLI. resolveSlashdoInvocation({command, args, providerId, providerCommand, leanMode}){command, args, style, invocation, skillName} for the three shapes slashdo's installer produces (slash-namespaced /do:x for Claude Code, slash-flat /do-x for OpenCode, skill — an Agent Skill selected by name — for codex/grok/antigravity and any unidentified provider). Plus buildSlashdoSection(resolved, body, {bodyPath, reviewWith}) (pure renderer; the caller loads the body via loadSlashdoFile. With a staged bodyPath it emits a filesystem pointer for deferred bundles or bodies over SLASHDO_INLINE_BUDGET_CHARS (24,000)), unreachableReviewerIncludes({reviewers, usernames}) → the reviewer-variant lib includes a run can never reach (the skipIncludes set for loadSlashdoFile; defaults to pruning NOTHING for an unresolved/unrecognized reviewer set, since an over-pruned prompt is worse than a fat one), SLASHDO_REVIEWER_INCLUDES/SLASHDO_REVIEWER_INCLUDE_NAMES, slashdoSkillName, isValidSlashdoCommand (the one definition of the safe bare-command shape, also gating the Zod schemas), agentOwnsPrWorkflow({providerType, leanMode}) — a strictly WEAKER question than typing a slash command: any local cli/tui harness that is not a lean --bare session drives its own commit → push → PR → review → merge (#3733), with resolveOwnsPrWorkflow({persisted, …}) reading the value stamped on a completed agent record and falling back to the slash-command gate for pre-#3733 records; oversizedBodyPointer(bodyPath, body) (the shared "it is on disk, go read it" line); and canTypeSlashCommands() — the single predicate behind agentPromptBuilder.js's completion-workflow gates (can this session TYPE /do:pr / /simplify?), which reads resolveSlashdoStyle's assumeClaudeWhenUnknown posture because the spawners resolve a blank command to claude. Provider is only known at spawn time, so a task persists the BARE command name — never a rendered /do:x string.
slashdoLoader.js Shared slashdo renderer adapter: loadSlashdoBundle(cmd, {stripFrontmatter, skipIncludes, defer}) returns an entrypoint and supporting files using the bundled transformer; loadSlashdoFile returns a self-contained command; loadSlashdoLib expands explicit reads for legacy recipes without traversing see-also links. writeResolvedSlashdoBody(cmd, body, {files}) stages immutable content-addressed bundles under PATHS.slashdoResolved, with relative library paths and the entrypoint written last. Missing required references fail dispatch rather than silently removing workflow gates.
singleFlight.js createSingleFlight()run(key, fn) — keyed in-flight coalescer: concurrent calls for the same key share one fn() execution and result; the slot auto-clears on settle. Minimal by design (no TTL/result cache layered on top, doesn't reject concurrent callers). Used by services/promptRunner.js's fallback mark-and-pick.
staleWhileRevalidate.js createStaleWhileRevalidate({ ttlMs, failureBackoffMs?, isComplete?, partialTtlMs? })read(key, produce, { wait }) / clear(key?) — TTL cache that serves a STALE value immediately and revalidates behind the caller, for readings too slow to block on (10-20s CLI/PTY spawns). wait: 'fresh' bypasses and blocks, 'cached' (default) blocks only on a cold cache, 'never' returns the PENDING symbol on a cold cache for UIs that render "still reading" and poll. Failures keep the last good value and back off; a cold cache whose producer failed throws rather than promising a reading that isn't coming. Used by providerUsage.js (TUI scrapes) and claudeCodeUsage.js.
staticImportGraph.js Static ES-module import scanning for structural test guards. staticImportSpecifiers(file) → every specifier a file statically imports (verbatim, source order); staticImportClosure(entry){files, packages} for the whole reachable graph; buildStaticImportGraph(rootDir)Map<relPath, relPath[]> of one directory's internal static edges (recurses into subdirectories, skips .test.js); listModuleFiles(rootDir) → every non-test .js under a directory, keyed by /-separated relative path (the same walk the graph builder uses, shared so a layering guard cannot drift from it); findImportCycles(graph) → each cycle rendered as a.js -> b.js -> a.js (depth-first, so WHICH rings it names depends on where the walk enters a component — fine for an "is this empty?" assertion, unusable as a baseline); findImportCycleComponents(graph) → the cyclic strongly-connected components as sorted member lists, traversal-order invariant and therefore baselineable (#5693); specifierMatchesPackage(spec, pkg) matches a package or any subpath; toModuleKey(relPath) is the one graph-key mint — always /-separated, because the keys are built two ways (entry-name concatenation vs path.relative) and Windows spells the second one with \, which silently dropped every edge into a subdirectory module and made the acyclicity guards pass vacuously there (#5909). Static imports only — await import() is deferred and can't create a load-time cycle or drag a native dep into an init graph. Shared by serviceImportCycles.test.js (the tree-wide cycle ratchet), agentImportCycles.test.js and twinImportCycles.test.js (per-cluster acyclicity) and spriteAnimationTracks.test.js (the request-validation graph reaches no sharp/ffmpeg).
sseUtils.js Per-job SSE stream helpers (imageGen + others) plus createSseRunner — the shared batch-runner lifecycle (runs map, terminal-frame replay, cancel, fire-and-forget coordinator) used by the pipeline completeness/analysis/checks runners.
streamAttachment.js streamAttachment(res,stream,{filename,contentType,failure,label}) — pipe a readable to a response as a file download. Sets the attachment headers plus X-Content-Type-Options:nosniff, and owns the teardown every attachment route needs: a pre-stream failure drops the download headers and returns failure via sendErrorResponse, a mid-stream failure destroys the socket (the envelope no-ops once headers are sent), and a client disconnect calls stream.abort?.() so an upstream child process is torn down. Shared by routes/imageTo3d.js (GLB, full-mesh) and routes/backup.js (snapshot tarball).
streamBackpressure.js awaitWritableDrain(res) — park a streaming-response producer on the socket's next drain (or close) when res.write() returned false, so SSE/NDJSON writes stay bounded for a slow reader. Shared by routes/ask.js (SSE) and routes/localLlm.js (NDJSON).
streamingSpawn.js runStreamingCommand(cmd, args, onLine, {timeoutMs?, cwd?, env?, splitRe?}) — run one command to completion and forward its stdout/stderr LINES to a hook, resolving { success, error? }. Never rejects (spawn error, non-zero exit, and timeout all resolve as success: false) because every caller is an install/setup flow running outside the Express request lifecycle, and the onLine hook is guarded for the same reason. A failure carries the last ~1KB of streamed output, so brew upgrade ollama exiting 1 with "Error: ollama not installed" surfaces that string instead of "exited with code 1". Shared by services/localLlm.js's package-manager installs and services/localRuntimeSetup.js's one-click daemon setup. splitRe is forwarded to the line readers — pass /[\r\n]+/ for a downloader whose progress bar redraws one line with a bare \r, or the stream goes silent for the whole download. isCancelled is polled once a second and SIGKILLs the child when it turns true (resolving {success:false, error:'cancelled'}) — required for a command that can run for hours while the caller holds a lock until it settles; a throwing predicate is logged and read as "not cancelled" rather than crashing the process from a timer callback. bufferedSpawn.js is the sibling for run-and-collect; use this one when live output IS the progress.
repoIntakeActions.js REPO_INTAKE_KEYS + normalizeRepoIntake(input) — the opt-in post-clone agent actions a Brain capture can request for a GitHub repo URL (malwareScan/do:scan, learn → a repo-study review). Pure half of services/repoIntake.js (which pulls the CoS task graph), so the link write path and the Zod schemas can import it freely. Normalizes to null when nothing was ticked, so "no intake" is never persisted onto a link.
tombstones.js Generic timestamped tombstones ({ <keyField>, deletedAt }) that let an otherwise add-only peer merge represent a DELETE, so a record removed on one machine is not resurrected by a peer that still has it (#3530). normalizeTombstones / recordTombstone / clearTombstone / tombstoneTimestamp maintain the list; mergeTombstones unions it in both directions (newest deletion per key wins) so a delete propagates rather than only defending locally; isTombstoned(list, key, createdAt) suppresses a record unless its own creation stamp is strictly NEWER than the deletion; pruneTombstones(list, records) drops tombstones a re-created record has superseded (otherwise a stale peer copy keeps reaping it); supersedingTimestamp(deletedAt) stamps a re-create that lands in the same millisecond (or behind a skewed peer clock). Comparison goes through lwwTimestamp.js, so polarity matches every other sync merge. Key on a field that means the same thing on every machine — locally-minted ids usually do not. DEFAULT_TOMBSTONE_LIMIT (200) caps growth.
untrustedContent.js Shared source policies, strict settings schema, data framing and API-only/local-private provider eligibility for untrusted GitHub and messaging content.
uploadLimits.js Single source of truth for upload size caps — JSON_BODY_LIMIT/JSON_BODY_LIMIT_BYTES (the express.json limit applied in index.js), MAX_BASE64_UPLOAD_BYTES derived from it (base64 ×4/3, so a bigger per-route cap is unreachable), MAX_SCREENSHOT_BYTES. Mirrored client-side as JSON_UPLOAD_MAX_FILE_SIZE.
userActionTypes.js Closed vocabulary for the operator-action ledger (user_action_events, #5594 / #5596): USER_ACTION_TYPES (CoS task/feedback/schedule + settings + instance-feature toggles + event-only creative/Brain pointers), USER_ACTION_ACTORS (user / mind / schedule / system), and the isUserActionType / isUserActionActor predicates. recordUserAction (services/userActions.js) throws on a type absent from the list, so a typo fails a test instead of writing a row nothing can filter on.
uuid.js v4() thin wrapper over crypto.randomUUID().
versionUtils.js compareSemver(a, b) — semver ordering (-1/0/1) with pre-release precedence and build-metadata stripping. Shared by the self-update checker (updateChecker.js) and the local-LLM Ollama update detector (localLlm.js). Inputs must be v-stripped.
workTracker.js WORK_TRACKERS/CONCRETE_WORK_TRACKERS/DEFAULT_WORK_TRACKER, workTrackerLabel, hostToWorkTracker, isGithubHost (GitHub-family host test — github.com + enterprise github.*; enterprise-aware replacement for the github.com-only isGithub gate), githubRepoSpec(origin) (host-qualified HOST/OWNER/REPO selector for gh --repo, or null for a non-GitHub origin — pairs the isGithubHost gate with the selector so prWatcher/branchReconcile/issueReconcile share one "resolvable GitHub repo" definition), forgeCliForTracker, isFileTracker (true when the tracker records work as repo files — PLAN.md — so an agent's proposal necessarily dirties the worktree; false for github/gitlab/jira), trackerToClaimTaskType, hostFromOriginUrl (subgroup-tolerant host parse), pure resolveWorkTracker({configured,host}), async resolveAppWorkTracker(app) — resolves a managed app's autonomous work source (PLAN.md / GitHub / GitLab / JIRA), defaulting 'auto' to the git origin host. Async resolveRepoForgeTarget(repoPath) — the ONE definition of "which forge can we query for this checkout", returning { forge, fullName, repoSpec, apiHost } (enterprise-aware gh --repo selector for GitHub; repoSpec: null for GitLab, which glab resolves from its cwd) or null for a non-forge origin; shared by issueReconcile.js and appIssues.js. Async resolveAppForgeTarget(app, {repoPath}) — the composed resolveAppWorkTracker + resolveRepoForgeTarget for callers holding the managed-app record, returning { tracker, target } with the app's github/gitlab pin threaded in as preferredForge (so a self-hosted forge on a hostname matching neither pattern still resolves); use this instead of re-threading the pin by hand. Also owns the {trackerInstructions} prompt block shared by the TRACKER-FILING task types (types that read the app read-only and deliver findings as tracker items, not a commit): TRACKER_FILING_PRESETS (per-task-type slug prefix / label / body requirements — reference-watch, ux, repo-study), TRACKER_FILING_TASK_TYPES (derived from the presets, so a gated type always has wording), and formatTrackerInstructions(tracker, options) which renders the plan/github/gitlab/jira block (reference-watch is the default option set, so a bare call stays byte-identical for it). Consumed by the claim-work router in cosTaskGenerator.js, referenceRepos.js, and routes/apps.js.
workspaceRoots.js Shared allow-list for routes that take a caller-supplied filesystem path. isWithinAllowedRoots(realPath) is the single complete test — on Windows it also allows any lettered non-system drive (D:\code), which appears in no root, so never render ALLOWED_WORKSPACE_ROOTS as "the directories you may use". outsideAllowedRootsMessage(realPath, { field }) formats a redacted server-only diagnostic with the rejected realpath and every checked root. Also ALLOWED_WORKSPACE_ROOTS (defaults + PORTOS_WORKSPACE_ROOTS, split on the platform path delimiter — ; on Windows — and symlink-resolved), isWithinRoot(resolvedPath, root) (separator-safe containment), and WORKSPACE_ROOTS_CONFIGURED (true when the operator set the env var — lets a permissive-by-default route like routes/detect.js opt into confinement). Defaults cover home plus wherever the platform mounts secondary volumes: /tmp + /Users + /Volumes + /mnt + /media + /opt on POSIX; home + the temp dir plus the non-system-drive rule on Windows, where those POSIX literals would resolve to whatever drive the process happens to be on. Used by routes/commands.js, routes/scaffold.js, and routes/git.js (always scoped) and routes/detect.js (scoped only when configured).
zodCompat.js Zod 4 compatibility helpers. partialWithoutDefaults(objectSchema) — like .partial() but strips inner field defaults first, so a PATCH/update schema doesn't inject (and clobber) the stored values of fields the caller didn't send. Use for any update schema derived from a defaulted base.

Test support

Module Purpose
dbTestGate.js requireDbOrSkip(label, dbReady, reason) keeps a missing local test database as a visible skipped suite, but throws when PORTOS_REQUIRE_DB is set so CI cannot pass after DB-backed suites disappear.
gitTestRepo.js Shared real-git sandbox for integration tests (#4394): one initialized template (working tree + bare origin) per worker, then fs.cp into a fresh temp dir. makeGitSandbox({ origin }), attachBareOrigin(scratch, repo), materializeGitRepo(dest), destroyGitSandbox, plus SKIP_HEAVY_INTEGRATION (VITEST_FAST=1). resetGitSandbox({ scratch, repo, initialHead }) / resetGitWorktreeSandbox(repo, initialHead) restore a sandbox in place (branches, worktrees, remote) so a describe can build one sandbox in beforeAll and reset between tests instead of paying the fs.cp/rm cycle per test (#5902). Every entry point runs assertTempPath first, so a path outside os.tmpdir() throws instead of git init-ing or rm -rf-ing a real checkout (#4554). Still real git — just not rebuilt from init+commit+push in every beforeEach.
mirrorParity.js Source-comparison primitives for the *.mirror.test.js server↔client parity tests: stripCommentsAndNormalize (so per-side commentary may diverge but logic may not), extractDeclaration(src, name) (balanced {}/()/[] walk over function / async function / const), compareDeclaration(serverSrc, clientSrc, name), and compareRegexDeclaration(serverSrc, clientSrc, serverName, clientName?) / regexAlternationSource(declText) (for a regex spelled as a `new RegExp([…].join('
mockPathsDataRoot.js Shared Vitest helpers for PATHS.data → temp dir and no-peer record creation guards.
settingsTestUtil.js bindSettingsFile(dataRoot)writeSettingsFile/mergeSettingsFile: direct settings.json disk writes that also drop the getSettings() read cache (dynamic-import reset) so a stale cache can't survive a bypass-save() write.
runtimeEnv.js isTestRunner() — NODE_ENV=test or the VITEST env var, so a run that dropped NODE_ENV is still armed. Dependency-free and deliberately apart from db.js, which used to own it: the lowest-level file primitives need the same answer and must not pull in pg, and the many suites spelling vi.mock('../lib/db.js', () => ({ query })) used to strip it out of the graph for every other consumer.
testDataIsolation.js Runtime backstop against a test WRITING into the install's real data/ tree — the filesystem analogue of db.js's row-write guard. isInsideRealDataRoot(path) canonicalizes a target through symlinked ancestors (it need not exist yet) and tests containment with pathSafety.js#isPathAtOrInsideDir, so a .. climb, a relative path, a data-archive sibling, or a differently-cased spelling on a case-insensitive filesystem can't walk in sideways; the real root is re-derived through dataRoot.js rather than read from PATHS, so a suite that redirects PATHS.data to a temp root can't also redirect the guard. assertNotRealDataWrite(path, operation) throws under the test runner from atomicWrite, the guarded wrappers in fileCore.js (writeFileGuarded, appendFileGuarded, copyFileGuarded, rmGuarded, unlinkGuarded, createWriteStreamGuarded), and collectionStore's record delete; assertNotNewRealDataDir(dir) is the create-only variant ensureDir uses, since mkdir -p on an existing directory mutates nothing. Inert outside the runner — the isTestRunner() check precedes every syscall. Services mutating files under data/ route through these guarded wrappers. Closes the write half of the bug class testDataIsolation.guards.test.js covers statically and the two-run probe covers for reads (#6176, after #6171, #6203).
testHelper.js Test helpers: request() (supertest-style HTTP) + mockJsonResponse/mockTextResponse (fetch Response mocks with .text(), .json(), and a headers.get content-type), startLoopbackServer(app)/closeLoopbackServer(server)/waitForAbort(signal) for tests that need a real socket (raw disconnects, SSE streaming) that request()'s run-to-completion fetch harness can't model, plus the source-scan pair collectServerSources() / readServerSource(rel) (and SERVER_DIR) used by the whole-tree guard suites — spawnCwd.test.js (#3193) and cliChildEnv.test.js (#3194). Those guards overlap deliberately, so they share one definition of "a source file"; change the ignore rules here and both move together. Cross-platform trio: posixPath(v) normalizes a RECEIVED path before comparing it to a POSIX-spelled literal (no-op on POSIX — never normalize the expectation, which would hide a genuinely wrong path), and resolveTestPython() returns an interpreter that actually runs, probing by execution because Windows ships a python Store-alias stub that exists but fails; null when there is none, for describe.skipIf; pinPlatform(value) pins process.platform and returns a restore that reinstates the ORIGINAL descriptor (deleting the pin when there was none) — it carries the one hazard every hand-rolled pin had to rediscover: never pin above an import that loads a native addon, which picks its prebuilt binary off the platform at load time (#4085). Python-shelling suites also take their two nested budgets from here: PY_TEST_TIMEOUT_MS (vitest per-test, passed as it()'s third argument — a real interpreter's wall time tracks machine load, not the assertion, so a ~4s case crosses the tight global 10s testTimeout on a contended full-suite worker) and the strictly smaller PY_SUBPROCESS_TIMEOUT_MS (every execFileSync spawn's own timeout, so a hung interpreter trips the spawn guard first and names the command instead of producing a bare vitest timeout; a subprocess allowance ABOVE the vitest budget is dead intent — vitest always wins).