CLI Generation Commands
The CLI provides four commands that cover the full content lifecycle: generating work content, regenerating markdown, syncing the website repository, and deploying to production. Each command is a subcommand of work.
Source: apps/cli/src/commands/work/
Command Overview
| Command | Description | Source File |
|---|---|---|
work generate | Generate items and create/update the data repository | generate.ts |
work regenerate-markdown | Regenerate the README.md from existing data | regenerate-markdown.ts |
work update-website | Sync data repository content to the website repository | update-website.ts |
work deploy | Deploy the website to the configured provider | deploy.ts |
Generate Content
ever-works work generate
The most complex CLI command. It guides the user through a multi-step configuration wizard, validates provider setup, and starts the generation pipeline.
Prerequisites
- User must be authenticated.
- User must have
editorrole or higher on the selected work. - A git provider (GitHub) must be connected.
- No generation may already be in progress.
Interactive Flow
Step 1: Work Selection
Prompts the user to select from their works. Checks that generation is not already running:
if (work.generateStatus?.status === GenerateStatusType.GENERATING) {
// Already in progress — show current step and exit
}
Step 2: Git Provider Check
Iterates over all enabled git providers and tests their connection. If none is connected, directs the user to the web dashboard to authenticate.
Step 3: Pipeline Selection
Loads the generator form schema and prompts the user to select a generation pipeline. The schema defines available pipelines and their provider requirements.
When a pipeline is selected, the schema is re-fetched with the pipeline ID to get filtered provider categories specific to that pipeline.
Step 4: Provider Selection
For each provider category in the schema (e.g. ai-provider, search, screenshot), the user selects which plugin to use:
const individualProviders = await generatePrompt.promptIndividualProviders(schema, lastRequestData?.providers);
Previous selections from the last generation run are used as defaults.
Step 5: Required Fields
Two fields are always collected:
| Field | Description |
|---|---|
name | The work name (read-only, pre-filled) |
prompt | The generation prompt (pre-filled from last generation if available) |
Step 6: Dynamic Plugin Fields
If the selected pipeline defines pluginFields, the CLI prompts for each one. Default values come from the schema's defaultValues merged with the last run's pluginConfig (only when the pipeline matches).
Plugin fields are organized into pluginGroups for logical grouping in the prompt interface.
Step 7: Provider Validation
Before proceeding, the CLI validates that all selected providers are properly configured:
const unconfigured = findUnconfiguredProviders(providerSelections, schema);
if (unconfigured.length > 0) {
console.log(`Unconfigured providers: ${unconfigured.join(', ')}`);
// Exit — user must configure in Settings > Plugins
}
Step 8: Generation Options
For previously generated works, the user chooses:
| Option | Values | Description |
|---|---|---|
generation_method | CREATE_UPDATE, RECREATE | Whether to update existing items or start from scratch |
update_with_pull_request | true, false | Whether updates go through a PR workflow |
website_repository_creation_method | CREATE_USING_TEMPLATE, etc. | How the website repository is created |
Selecting RECREATE triggers an extra confirmation since it deletes existing items.
New works always use CREATE_UPDATE without prompting.
Step 9: Confirm and Start
The CLI displays a summary of all selections and asks for final confirmation. On confirmation, it calls apiService.generateContent() and directs the user to check progress with work status.
Plugin Config Sanitization
Before sending to the API, plugin config values are sanitized:
nullandundefinedvalues are removed.- String arrays are trimmed and cleaned of control characters.
- URL arrays are trimmed but not character-cleaned.
Regenerate Markdown
ever-works work regenerate-markdown
Regenerates the README.md file in the data repository without re-running the full generation pipeline. Useful for updating presentation while preserving existing data.
Flow
- Authenticate and select work.
- Check edit permissions.
- Confirm the operation.
- Call
apiService.regenerateMarkdown(workId). - Show status and next steps.
What It Does
- Regenerates the
README.mdfile for the work's data repository. - Preserves all existing item data.
- Updates only the presentation layer (markdown formatting).
Next Steps After Success
The CLI suggests:
- Check your data repository for the updated README.md
- Review the changes and commit if satisfied
- Use "work update-website" to update the website
Update Website
ever-works work update-website
Syncs content from the data repository to the website repository. This prepares the website for deployment without triggering a deploy.
Flow
- Authenticate and select work.
- Check edit permissions.
- Display the target repository (
{owner}/{slug}-website). - Confirm the operation.
- Call
apiService.updateWebsite(workId). - Show status, repository URL, and next steps.
What It Does
- Copies generated content from the data repository to the website repository.
- Updates the website source files to reflect the latest data.
- Does not trigger a deployment.
Next Steps After Success
- Check the website repository for updates
- Use "work deploy" to deploy the website
- Review the changes before deployment
Deploy Website
ever-works work deploy
Deploys the website to the configured deployment provider (e.g. Vercel). Handles provider selection, team scoping, and deployment status polling.
Prerequisites
- Work content must be generated (
generateStatus === GENERATED). - A deployment provider must be configured or selected during the command.
- The deployment provider's API token must be configured.
State Machine
The deploy command implements a state machine with four states:
| State | Condition | Behavior |
|---|---|---|
| A | No deployProvider set | Prompt user to select a provider. If valid, proceed to deploy. |
| B | Has provider, canDeploy=false, shared work | Tell user the owner must configure their token. |
| C | Has provider, canDeploy=false, owned work | Tell user to configure their token. Offer to switch providers. |
| D | Has provider, canDeploy=true | Execute the deployment. |
Deployment Execution
The executeDeploy() function handles the full deployment lifecycle:
- Lookup existing deployment -- Checks if the work already has a live deployment and shows its URL.
- Team selection -- If the user's deployment account has teams, prompts for which team to deploy under.
- Confirmation -- Shows the source repository and what will happen.
- Deploy -- Calls
apiService.deployWebsite(workId, { teamScope }). - Poll for status -- Polls the work's
deploymentStateevery 5 seconds.
Deployment Status Polling
const STOP_STATES = ['READY', 'ERROR', 'CANCELED', 'TIMEOUT'];
while (true) {
const { work } = await apiService.getWork(workId);
if (STOP_STATES.includes(work.deploymentState)) {
// Show final status and website URL
break;
}
// Update spinner text with current state
await new Promise((resolve) => setTimeout(resolve, 5000));
}
The isDeploying() helper prevents false positives by checking that the deployment was started within the last 10 minutes:
function isDeploying(work: Work) {
const hasDeploymentState = ['INITIALIZING', 'QUEUED', 'BUILDING'].includes(work.deploymentState);
const hasStartedAt =
work.deploymentStartedAt && new Date(work.deploymentStartedAt) > new Date(Date.now() - 10 * 60 * 1000);
return Boolean(hasDeploymentState && hasStartedAt);
}