I just had to resolve this issue, but upon re-reading your question, I don't think my answer will work as well for you.
First - cron + CSV chicanery SHOULD work. The issue is that when users are added to a smart group, it doesn't fire the civicrm_post
hook (it's not really feasible performance-wise). However, they ARE fired on import.
I'd use the command-line export tool, something like:
php <civiroot>/bin/csv/export -e GroupContact group_id=<smart group ID> --file /tmp/export.csv
php <civiroot>/bin/csv/import -e GroupContact --file /temp/export/csv
In my solution, all the smart groups were created based on the value of a single custom field. So I wrote a quick extension that added people to groups based on the value of the custom field. You may be able to use CiviRules for this, I'm not 100% sure. Here's that code:
// Fire when the "Role Info" group is edited.
function primaryrolesync_civicrm_custom($op, $customGroupID, $entityID, &$params) {
// Hard-coded: The Role Info group ID is 30. The custom field ID is 152.
if ($customGroupID == 30) {
// Get the role name from the custom field value.
$result = civicrm_api3('Contact', 'getoptions', ['field' => "custom_152"]);
$roleName = $result['values'][$params[0]['value']];
// Get the group ID that corresponds to this primary role.
$result = civicrm_api3('Group', 'get', [
'title' => $roleName,
'sequential' => 1,
'return' => 'id',
]);
$groupId = $result['id'];
// Add this contact to the appropriate group.
if ($groupId) {
$result = civicrm_api3('GroupContact', 'create', [
'group_id' => $groupId,
'contact_id' => $entityID,
]);
}
}
}