Skip to content

Agent-legible CLI: structured output, real exit codes, dry-run and sync-mode #889

Description

@vinishjail97

Feature Request / Improvement

Make the XTable CLI legible to a program rather than only to a human reading logs. This is the foundation for any agent tooling, but it is worth doing on its own: Airflow, cron, CI and monitoring wrappers all need the same thing.

The defects it starts from

ConversionController.sync() returns Map<String, SyncResult>, and each SyncResult already carries everything a caller needs: mode, lastInstantSynced, syncStartTime, syncDuration, tableFormatSyncStatus (a SyncStatusCode of SUCCESS, ABORTED or ERROR plus ErrorDetails), recommendedSyncMode, and a per-catalog status list.

RunSync.syncTableMetdata discards all of it:

conversionController.sync(conversionConfig, conversionSourceProvider);   // return value dropped
} catch (Exception e) {
  log.error("Error running sync for {}", table.getTableBasePath(), e);   // swallowed, loop continues
}

Consequences today:

  1. The structured result never reaches the caller. Log text is the only interface.
  2. Per-table failures are swallowed and never aggregated, so a run where every table failed is indistinguishable from a clean run.
  3. The exit code is always 0. There is no System.exit in RunSync. The argument-parse failure path prints help and returns, so even a malformed command line exits 0.

Point 3 is a plain bug for any automated caller.

Scope

  • Return the aggregated results from syncTableMetdata instead of void.
  • Real exit codes: 0 all targets succeeded, 1 usage or configuration error, 2 partial failure, 3 all failed. Fix the parse-failure path.
  • --output json|text, defaulting to text so existing behaviour is unchanged. The JSON is close to a direct serialization of SyncResult: one record per table and target, with status, sync mode, last instant synced, duration, recommended sync mode, and error details.
  • --dryRun: validate the config, resolve source and targets, report what would be synced, write nothing. This is also the guardrail the MCP convert tool will need.
  • --syncMode FULL|INCREMENTAL. RunSync currently hardcodes INCREMENTAL, even though SyncResult.recommendedSyncMode already tells the caller when a full sync is needed. There is no way to act on it from the CLI today.
  • Report a no-op explicitly. lastInstantSynced makes it detectable, so callers should not have to infer it. PR feat: add xtable-converter Claude Code skill #829 currently detects no-op syncs heuristically, which is the symptom this fixes.
  • Apply the same treatment to RunCatalogSync.

Out of scope

Anything agent-specific. This issue only changes what the CLI reports and what it returns to the shell.

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions