@takazudo/app-scaffold
Computes the initial content files a brand-new workspace is seeded with, and writes the per-app-instance config.json v2 workspace binding.
Epic #4204 pivoted the app off local-workspace directories (D14: "the workspace model is the single source of truth post-pivot"). S24 (#4228) repurposed this package accordingly: the disk scaffolder (scaffoldApp, scaffoldWorkspace, and the on-disk presets/<name>/template/ tree it copied) is gone. What remains is computeScaffold() — a PURE, filesystem-free function that returns the content files consumed by the cloud-first genesis flow (runGenesisScaffold in @takazudo/backend-bridge) — plus writeAppConfig(), unaffected by the pivot.
Main Exports
import { presetPins, getPresetPins, isPresetName } from "@takazudo/app-scaffold";
import { computeScaffold } from "@takazudo/app-scaffold";
import {
writeAppConfig,
validateAppName,
APP_NAME_PATTERN,
} from "@takazudo/app-scaffold";
import type {
PresetName,
PresetPin,
StepStatus,
StepResult,
WriteAppConfigOptions,
} from "@takazudo/app-scaffold";computeScaffold()
Computes the content-file map (Record<workspaceRelativePath, content>) a fresh workspace is seeded with for a given preset — pure, synchronous, and filesystem-free so a browser / iOS client can call it with no local storage.
function computeScaffold(presetName?: PresetName): Record<string, string>;import { computeScaffold } from "@takazudo/app-scaffold";
const files = computeScaffold("standard");
// { ".zudotext.settings.json": "...", "CLAUDE.md": "...", "inbox/1.md": "..." }Preset content tiers
| Preset | Adds |
|---|---|
minimal | .zudotext.settings.json (synced settings document) + CLAUDE.md |
standard | minimal + an inbox seed note (inbox/) |
full | standard + a sample inline-AI skill (.) + a sample pin note (pins/) |
.zudotext.settings.json is defaultSettings reified via validateSettings() with local bootstrap identity blanked (stripLocalBootstrapIdentity()) — the same document shape every writer of the synced settings document must produce (epic #4204 D3).
.gitignore is deliberately absent from the map — it is a machine-local skeleton file each device recreates itself; there is no synced counterpart.
presetPins / getPresetPins()
Access preset pin configurations (the sidebar directory pins a preset's workspace ships with) without loading a full preset:
// Record mapping preset name → PresetPin[]
const presetPins: Record<PresetName, PresetPin[]>;
// Type-safe accessor with runtime check
function getPresetPins(name: PresetName): PresetPin[];
function isPresetName(value: string): value is PresetName;writeAppConfig()
Writes the per-app-instance runtime config — ~/, schema v2 ({"workspace":{"id":…}}, epic #4204 D2). One app instance binds to exactly one cloud workspace; the schema carries no local content-directory path.
function writeAppConfig(options: WriteAppConfigOptions): StepResult;interface WriteAppConfigOptions {
/** App-instance name (e.g. `ztoffice`). */
appName: string;
/** Cloud workspace this app instance binds to. */
workspaceId: string;
/** Overwrite an existing config.json instead of skipping. */
force?: boolean;
/** Override the home directory used to compute the config path. */
homedir?: string;
}The Rust mirror is write_app_config in tauri-, which also owns the read side (read_app_binding) used at startup.
validateAppName()
Returns true if an app name matches APP_NAME_PATTERN (lowercase alphanumeric + hyphens).
function validateAppName(name: string): boolean;
const APP_NAME_PATTERN: RegExp;CLI
See pnpm generate --help (backed by scripts/) for the developer CLI that drives computeScaffold() + writeAppConfig() end to end.
Dependencies
@takazudo/app-defaults— fordefaultSettings,validateSettings(), andstripLocalBootstrapIdentity()