Skip to content

Latest commit

 

History

History
183 lines (133 loc) · 7.08 KB

File metadata and controls

183 lines (133 loc) · 7.08 KB

synkronus-cli – LLM Context for Adding Commands

This file explains how to add new commands to the synkronus-cli project so future LLM agents can extend the CLI without re-analyzing the codebase.

High-Level Architecture

  • Entry point: cmd/synkronus/main.go
    • Calls cmd.Execute() from internal/cmd/root.go.
  • Command tree (Cobra):
    • Root command synk is defined in internal/cmd/root.go (rootCmd).
    • Subcommands live in internal/cmd/*.go and are registered in each file's init() via rootCmd.AddCommand(...) or group commands' AddCommand(...).
  • HTTP API client: pkg/client/client.go
    • Client wraps an autogenerated oapi-codegen client in pkg/client/generated.
    • The generated transport is configured with a request editor that adds Authorization: Bearer <token> via internal/auth.GetToken().
    • Required x-ode-version headers are passed through generated endpoint params using Viper api.version.
  • ListUsers returns typed generated.UserListItem (includes optional presence for last-seen); synk user list prints columns for last activity and client count.

Configuration & Auth

  • Config handled in internal/cmd/root.go and internal/config using Viper.
    • rootCmd defines persistent flags:
      • --api-urlapi.url
      • --api-versionapi.version
    • Config file: $HOME/.synkronus.yaml (or --config override).
  • Authentication flows through internal/auth:
    • auth.Login() talks to /auth/login, stores tokens in config.
    • auth.GetToken() returns a valid JWT, refreshing if needed.
    • The CLI assumes the user has run synk login before calling authenticated endpoints.

Pattern: Adding a New HTTP Operation

When a new CLI command needs to call the Synkronus API, follow this pattern:

  1. Extend pkg/client.Client (preferred)

    • Add a method on Client that:
      • Calls the matching generated method from pkg/client/generated.
      • Passes x-ode-version through endpoint params where required.
      • Handles HTTP status codes and parses or streams the response.
  2. Use the client method in a Cobra command

    • Inside internal/cmd/*.go, create or reuse a command group.
    • In the command's RunE, construct c := client.NewClient() and call the new client method.

This separation keeps HTTP details in pkg/client and CLI UX in internal/cmd.

Pattern: Adding a New Command Group

Example: the data command group used for data export.

  1. Create a new file in internal/cmd

    • File name convention: <group>.go, e.g. data.go, attachments.go, sync.go.
  2. Define the group command

    var dataCmd = &cobra.Command{
        Use:   "data",
        Short: "Data-related operations",
        Long:  `Commands for working with exported data and statistics.`,
    }
  3. Define one or more subcommands

    var dataExportCmd = &cobra.Command{
        Use:   "export <output_file>",
        Short: "Export data as a Parquet ZIP archive",
        Long: `Download a ZIP archive of Parquet exports from the Synkronus API.

Examples: synk data export exports.zip synk data export ./backups/observations_parquet.zip`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { outputFile := args[0] if outputFile == "" { return fmt.Errorf("output_file is required") }

       c := client.NewClient()
       if err := c.DownloadParquetExport(outputFile); err != nil {
           return fmt.Errorf("data export failed: %w", err)
       }

       fmt.Printf("Parquet export saved to %s\n", outputFile)
       return nil
   },

}


4. **Register the commands in `init()`**

```go
func init() {
    dataCmd.AddCommand(dataExportCmd)
    rootCmd.AddCommand(dataCmd)
}

Once this is done, the new hierarchy appears automatically in:

  • synk --help
  • synk data --help
  • Completion scripts generated by synk completion [bash|zsh|fish|powershell].

Pattern: Downloading/Uploading Files via HTTP

Use existing client methods as templates:

  • Client.DownloadAppBundleFile(...) for binary downloads.
  • Client.UploadAppBundle(...) for multipart uploads.
  • Client.DownloadParquetExport(...) (added for /dataexport/parquet).

Binary Download Pattern (used for Parquet export)

Key steps in Client.DownloadParquetExport(destPath string) error:

  1. Call the generated endpoint method:

    resp, err := c.api.GetParquetExportZipWithResponse(context.Background())
  2. Check resp.StatusCode() and surface error text if non-200.

  3. Ensure destination directory exists (os.MkdirAll).

  4. Create the output file and io.Copy from bytes.NewReader(resp.Body).

Any new file-download-type feature should follow this pattern to keep behavior consistent (auth, error messages, directory creation).

Pattern: Flags and Arguments

  • Positional args: Use Args: cobra.ExactArgs(n) (or RangeArgs) and read from args[index].
  • Flags: Use cmd.Flags().<Type>("name") to read; define in init() with:
    • Flags().String(...), Bool(...), etc.
    • MarkFlagRequired("name") if needed.

Examples elsewhere in the codebase:

  • sync.go:
    • sync pull [output_file] with flags: --client-id, --current-version, --schema-types, --limit, --page-token.
  • attachments.go:
    • attachments upload <file> --id <attachment_id>
    • attachments download <attachment_id> [output_file].

When adding new commands, align with these patterns for a consistent UX.

Completion & Help Text

  • Shell completion is implemented once in internal/cmd/root.go via completionCmd.
  • Any new commands automatically appear in:
    • Root and subcommand --help outputs (Cobra handles this).
    • Generated completion scripts.

LLM agents should not modify completionCmd for normal feature work. Instead, make sure new commands have clear Short and Long descriptions so the autogenerated help is meaningful.

Checklist for Adding a New Command

When extending the CLI, LLM agents should:

  1. Decide if a new group is needed

    • If the feature logically fits an existing group (e.g., sync, attachments, data), add a subcommand there.
    • Otherwise, create a new <group>.go with a top-level *cobra.Command.
  2. Add/extend a client method in pkg/client

    • Encapsulate the HTTP call there, using c.doRequest.
    • Handle response codes carefully and return Go errors with useful messages.
  3. Implement the Cobra command

    • Parse args/flags.
    • Call the client method.
    • Print concise, user-friendly output.
  4. Register the command in init()

    • Attach to the appropriate group and to rootCmd.
  5. Update README (optional but recommended)

    • Add a short feature bullet and a minimal example in the Usage section.

Following this guide should allow LLM agents to add new commands that are consistent with the existing synkronus-cli design and UX.