Sync Payload
codegen_sync_payloadSync payload files with the database to apply schema drift, archiving previous versions of updated files.
Instructions
Apply schema drift to existing payload spec files in a project, archiving the previous version of each updated file, by running restforge-cli payload --sync.
USE WHEN:
The user asks to apply schema drift changes to payload files, sync payload files with the database, or update payload JSON files to match the current schema
The user asks things like "sinkronisasi payload", "update payload sesuai database", "apply schema drift", "sync payload files", "terapkan perubahan schema", "samakan payload dengan database"
After 'codegen_diff_payload' reported column-level differences and the user has reviewed them, wanting to apply the changes
After ALTER TABLE in the database when the user wants to bring all payload files in line with the new schema
The user mentions creating an archive of the previous payload before regenerating endpoints
Before applying changes, strongly consider calling 'codegen_diff_payload' first to confirm what will change in each file (read-before-write per §5.3 — sync overwrites the active payload file and produces an archive that the user may want to inspect later).
DO NOT USE FOR:
Just checking which payload files have drift (without modifying anything) -> use 'codegen_validate_payload'
Looking at the per-column differences without applying them -> use 'codegen_diff_payload'
Generating a payload from scratch for a table that has no payload yet -> use 'codegen_generate_payload'
Cleaning up or deleting old '.archive.NNN' files — this tool does not handle archive cleanup; the user must remove archive files manually if desired
This tool runs: npx restforge-cli payload --sync --config= [--table=] [--output=] in the given cwd. The CLI reads existing payload JSON files from the output directory, connects to the database described in the config file, and rewrites each payload file whose schema has drifted. Before overwriting, the previous file content is renamed to '.archive.NNN' (NNN is a sequential number starting at 001). Files that are already in sync are not touched. The CLI prints a per-file status (typically [SKIP], [ARCHIVE], [SYNCED]) followed by a Summary section with totals.
If the sync run fails partway through (e.g. database connection drops), the CLI restores the archived file back to its original name so the active payload is not left corrupted.
Preconditions:
The project must have restforgejs installed in node_modules.
The config file (default 'db-connection.env') must exist in the project and contain valid database credentials. This tool does not pre-check that — if the CLI fails, the failure response will surface the underlying cause.
PRESENTATION GUIDANCE:
Match the user's language. If the user writes in Indonesian, respond in Indonesian.
Never mention internal tool names in the reply to the user. Describe actions by what they do (e.g. "update the payload files", "see the column-level differences first", "regenerate the endpoint code from the updated payload").
Speak in plain language. Summarise the result; do not paste raw CLI output unless the user explicitly asks.
When a precondition is not met, frame it as a question or next-step suggestion rather than an error.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | Yes | Absolute path of the project folder (must contain node_modules/restforgejs and the config file) | |
| config | No | Config file name (relative to project) used by the CLI to connect to the database | db-connection.env |
| table | No | Specific table name to sync (e.g. supplier or core.supplier). When omitted, all payload files in the output directory are synced. | |
| output | No | Payload directory relative to project (e.g. payload). When omitted, the CLI uses its default (payload/). |
Implementation Reference
- src/tools/codegen/sync-payload.ts:76-177 (handler)The handler function (async callback passed to server.registerTool) that executes the 'codegen_sync_payload' tool logic. It validates the precondition (checks node_modules/restforgejs exists), builds CLI args, runs 'npx restforge-cli payload --sync ...', and returns success/failure responses.
async ({ cwd, config, table, output }) => { const projectCwd = resolve(cwd); // Precondition check: restforgejs must be present in node_modules. // Treated as a non-error precondition per the authoring guide §3.4. try { await access(join(projectCwd, 'node_modules', 'restforgejs')); } catch { return { content: [ { type: 'text', text: `Precondition not met: the RESTForge package is not installed in this project. Project path: ${projectCwd} Expected location: node_modules/restforgejs Requested table: ${table ?? 'all'} Requested config: ${config} Requested output: ${output ?? 'default (payload/)'} For the assistant: - The user needs to install the RESTForge package before payload files can be synced with the database schema. - Use the appropriate package-installation tool to do this, then retry syncing the payload. - When explaining to the user, say something like "the RESTForge package isn't installed yet — should I install it first?". Do not mention internal tool names.`, }, ], isError: false, // per §3.4 }; } // Forward only the arguments the user supplied. Defaults inside restforge-cli // (e.g. payload/ as the default output dir, all files when --table is omitted) // should remain in effect when the user does not specify them. per §3.5 const args = ['restforge-cli', 'payload', '--sync', `--config=${config}`]; if (table) args.push(`--table=${table}`); if (output) args.push(`--output=${output}`); // Timeout raised to 60s (vs 30s for validate/diff): sync writes payload files // and renames each previous version to a sequential archive, which can take // longer than read-only operations on projects with many payload files. const result = await execProcess('npx', args, { cwd: projectCwd, timeout: 60_000 }); // CLI failure: real error per §3.4; structured per §3.5. if (!result.success) { return { content: [ { type: 'text', text: `Failed to sync payload. Project path: ${projectCwd} Config: ${config} Table: ${table ?? 'all'} Output: ${output ?? 'default (payload/)'} Command: ${result.command} Exit code: ${result.exitCode} --- CLI output --- stdout: ${result.stdout} stderr: ${result.stderr} --- end CLI output --- For the assistant: - Tell the user that updating the payload files did not complete successfully. - Summarise the likely cause from the CLI output in plain language (common causes: the config file is missing or has incomplete credentials, the database is unreachable, the requested table does not exist, or the payload directory is empty). Do not paste the raw stdout/stderr unless the user explicitly asks. - Reassure the user: when a sync run fails, the CLI automatically restores any payload file that was just archived back to its original name, so the active payload files are not left in a corrupted state. - Offer to retry once the underlying issue is resolved. Do not mention internal tool names.`, }, ], isError: true, // per §3.4 }; } // Success: one-line summary + labeled facts + fenced raw output per §3.5. // The CLI prints per-file status lines ([SKIP] / [ARCHIVE] / [SYNCED]) and a // Summary section with totals. The model should extract the counts and the // archive filenames from stdout when talking to the user. per §5.2 cross-ref // back to validate/diff. return { content: [ { type: 'text', text: `Payload sync completed. Project path: ${projectCwd} Config: ${config} Table: ${table ?? 'all'} Output: ${output ?? 'default (payload/)'} Command: ${result.command} --- CLI output --- ${result.stdout} --- end CLI output --- For the assistant: - Read the Summary section in the CLI output above and tell the user how many payload files were SYNCED and how many were SKIPPED (already in sync). Do not paste the raw CLI output unless the user explicitly asks. - For each file that was updated, the previous version of the file was renamed to '<filename>.archive.NNN' (NNN is a sequential number, starting at 001) in the same payload directory. Mention this to the user in plain language so they know the old version is still on disk and available for manual rollback if needed. If the CLI output lists specific archive filenames, you may relay them to the user. - Important: warn the user that any module or endpoint that was previously generated from the older payload still reflects the old schema. To bring those endpoints in line with the new schema, the user needs to regenerate the endpoint code from the updated payload as a follow-up step. Describe this in plain language; do not name the internal tool. - If no files were synced (every file was SKIPPED because it was already in sync), confirm in plain language that the payload files already match the database and no changes were applied. - Input schema definition for 'codegen_sync_payload'. Defines four Zod-validated inputs: cwd (string), config (string, default 'db-connection.env'), table (optional string), output (optional string).
inputSchema: { cwd: z .string() .min(1) .describe('Absolute path of the project folder (must contain node_modules/restforgejs and the config file)'), config: z .string() .min(1) .default('db-connection.env') .describe('Config file name (relative to project) used by the CLI to connect to the database'), table: z .string() .min(1) .optional() .describe('Specific table name to sync (e.g. supplier or core.supplier). When omitted, all payload files in the output directory are synced.'), output: z .string() .min(1) .optional() .describe('Payload directory relative to project (e.g. payload). When omitted, the CLI uses its default (payload/).'), }, - src/tools/codegen/sync-payload.ts:7-75 (registration)The registerCodegenSyncPayload function that registers the tool 'codegen_sync_payload' with the MCP server via server.registerTool(), including description, annotations (readOnlyHint: false, idempotentHint: false), and inputSchema.
export function registerCodegenSyncPayload(server: McpServer): void { server.registerTool( 'codegen_sync_payload', { title: 'Sync Payload', description: `Apply schema drift to existing payload spec files in a project, archiving the previous version of each updated file, by running restforge-cli payload --sync. USE WHEN: - The user asks to apply schema drift changes to payload files, sync payload files with the database, or update payload JSON files to match the current schema - The user asks things like "sinkronisasi payload", "update payload sesuai database", "apply schema drift", "sync payload files", "terapkan perubahan schema", "samakan payload dengan database" - After 'codegen_diff_payload' reported column-level differences and the user has reviewed them, wanting to apply the changes - After ALTER TABLE in the database when the user wants to bring all payload files in line with the new schema - The user mentions creating an archive of the previous payload before regenerating endpoints - Before applying changes, strongly consider calling 'codegen_diff_payload' first to confirm what will change in each file (read-before-write per §5.3 — sync overwrites the active payload file and produces an archive that the user may want to inspect later). DO NOT USE FOR: - Just checking which payload files have drift (without modifying anything) -> use 'codegen_validate_payload' - Looking at the per-column differences without applying them -> use 'codegen_diff_payload' - Generating a payload from scratch for a table that has no payload yet -> use 'codegen_generate_payload' - Cleaning up or deleting old '.archive.NNN' files — this tool does not handle archive cleanup; the user must remove archive files manually if desired This tool runs: npx restforge-cli payload --sync --config=<config> [--table=<table>] [--output=<output>] in the given cwd. The CLI reads existing payload JSON files from the output directory, connects to the database described in the config file, and rewrites each payload file whose schema has drifted. Before overwriting, the previous file content is renamed to '<filename>.archive.NNN' (NNN is a sequential number starting at 001). Files that are already in sync are not touched. The CLI prints a per-file status (typically [SKIP], [ARCHIVE], [SYNCED]) followed by a Summary section with totals. If the sync run fails partway through (e.g. database connection drops), the CLI restores the archived file back to its original name so the active payload is not left corrupted. Preconditions: - The project must have restforgejs installed in node_modules. - The config file (default 'db-connection.env') must exist in the project and contain valid database credentials. This tool does not pre-check that — if the CLI fails, the failure response will surface the underlying cause. PRESENTATION GUIDANCE: - Match the user's language. If the user writes in Indonesian, respond in Indonesian. - Never mention internal tool names in the reply to the user. Describe actions by what they do (e.g. "update the payload files", "see the column-level differences first", "regenerate the endpoint code from the updated payload"). - Speak in plain language. Summarise the result; do not paste raw CLI output unless the user explicitly asks. - When a precondition is not met, frame it as a question or next-step suggestion rather than an error.`, inputSchema: { cwd: z .string() .min(1) .describe('Absolute path of the project folder (must contain node_modules/restforgejs and the config file)'), config: z .string() .min(1) .default('db-connection.env') .describe('Config file name (relative to project) used by the CLI to connect to the database'), table: z .string() .min(1) .optional() .describe('Specific table name to sync (e.g. supplier or core.supplier). When omitted, all payload files in the output directory are synced.'), output: z .string() .min(1) .optional() .describe('Payload directory relative to project (e.g. payload). When omitted, the CLI uses its default (payload/).'), }, annotations: { title: 'Sync Payload', readOnlyHint: false, // tool menulis ulang file payload + membuat file archive idempotentHint: false, // memanggil ulang dapat menambah file archive baru jika DB berubah lagi di antara panggilan }, }, - src/tools/codegen/index.ts:20-20 (registration)Registration call site: registerCodegenSyncPayload(server) invoked from the central codegen tools index.
registerCodegenSyncPayload(server); - src/lib/exec.ts:33-69 (helper)The execProcess helper utility used by the handler to run the 'npx restforge-cli payload --sync' CLI command and return a structured ExecResult.
export async function execProcess( command: string, args: string[], options: ExecOptions = {} ): Promise<ExecResult> { const { cwd = process.cwd(), timeout = 60_000, env, stripFinalNewline = true } = options; const fullCommand = `${command} ${args.join(' ')}`; // Merge env: parent env first, custom env overrides const mergedEnv = env ? { ...process.env, ...env } : undefined; try { const result = await execa(command, args, { cwd, timeout, reject: false, stripFinalNewline, ...(mergedEnv ? { env: mergedEnv } : {}), }); return { success: result.exitCode === 0, stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode ?? -1, command: fullCommand, }; } catch (error) { const e = error as ExecaError; return { success: false, stdout: e.stdout?.toString() ?? '', stderr: e.stderr?.toString() ?? e.message, exitCode: e.exitCode ?? -1, command: fullCommand, }; } }