diff -urpN ..\workflow_old/workflow.admin.inc ./workflow.admin.inc
--- ..\workflow_old/workflow.admin.inc	2010-03-02 19:32:54.000000000 +0100
+++ ./workflow.admin.inc	2010-03-16 09:40:11.181285000 +0100
@@ -122,7 +122,7 @@ function workflow_permissions($wid) {
     $all[$role]['name'] = $value;
   }
   $result = db_query(
-    'SELECT t.roles, s1.state AS state_name, s2.state AS target_state_name ' .
+    'SELECT t.roles, s1.state AS state_name, s1.sid as state_sid, s1.ref AS state_ref, s2.state AS target_state_name, s2.sid AS target_state_sid, s2.ref AS target_state_ref ' .
     'FROM {workflow_transitions} t ' .
     'INNER JOIN {workflow_states} s1 ON s1.sid = t.sid '.
     'INNER JOIN {workflow_states} s2 ON s2.sid = t.target_sid '.
@@ -132,12 +132,14 @@ function workflow_permissions($wid) {
 
   while ($data = db_fetch_object($result)) {
     foreach (explode(',', $data->roles) as $role) {
-      $all[$role]['transitions'][] = array(check_plain(t($data->state_name)), WORKFLOW_ARROW, check_plain(t($data->target_state_name)));
+      $all[$role]['transitions'][] = array(
+        'from' => (object) array('sid' => $data->state_sid, 'name' => $data->state_name, 'ref' => $data->state_ref),
+        'to' => (object) array('sid' => $data->target_state_sid, 'name' => $data->target_state_name, 'ref' => $data->target_state_ref),
+      );
     }
   }
 
-  $header = array(t('From'), '', t('To'));
-  return theme('workflow_permissions', $header, $all);
+  return $all;
 }
 
 /**
@@ -148,7 +150,11 @@ function theme_workflow_permissions($hea
   foreach ($all as $role => $value) {
     $output .= '<h3>'. t("%role may do these transitions:", array('%role' => $value['name'])) .'</h3>';
     if (!empty($value['transitions'])) {
-      $output .= theme('table', $header, $value['transitions']) . '<p></p>';
+      $rows = array();
+      foreach ($value['transitions'] as $t) {
+        $rows[] = array($t['from']->name, WORKFLOW_ARROW, $t['to']->name);
+      }
+      $output .= theme('table', $header, $rows) . '<p></p>';
     }
     else {
       $output .= '<table><tbody><tr class="odd"><td>' . t('None') . '</td><td></tr></tbody></table><p></p>';
@@ -225,7 +231,7 @@ function workflow_edit_form($form_state,
     '#collapsible' => TRUE,
   );
   $form['permissions']['summary'] = array(
-    '#value' => workflow_permissions($workflow->wid),
+    '#value' => theme('workflow_permissions', array(t('From'), '', t('To')), workflow_permissions($workflow->wid)),
   );
 
   return $form;
@@ -378,6 +384,11 @@ function workflow_state_add_form(&$form_
     '#default_value' => $state['weight'],
     '#description' => t('In listings, the heavier states will sink and the lighter states will be positioned nearer the top.'),
   );
+  // Unique identifier for import/exporting.
+  $form['ref'] = array(
+    '#type' => 'hidden',
+    '#value' => time(),
+  );
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save')
diff -urpN ..\workflow_old/workflow.features.inc ./workflow.features.inc
--- ..\workflow_old/workflow.features.inc	1970-01-01 01:00:00.000000000 +0100
+++ ./workflow.features.inc	2010-03-29 15:15:03.468625000 +0200
@@ -0,0 +1,264 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * The inc file which adds features support
+ */
+
+/**
+ * Implementation of hook_features_export().
+ */
+function workflow_features_export($data, &$export, $module_name) {
+  foreach ($data as $machine_name) {
+    $workflow = workflow_load($machine_name);
+    // If the Workflow module created the workflow then the config is only in
+    // the database, so add it as an exportable.
+    if (in_array($workflow->module, array('workflow', $module_name))) {
+      $export['features']['workflow'][$workflow->machine_name] = $workflow->machine_name;
+      continue;
+    }
+    // If the workflow is implemented by a module, then add that module as a
+    // dependancy.
+    else {
+      $export['dependencies'][$workflow->module] = $workflow->module;
+    }
+  }
+}
+
+/**
+ * Implementation of hook_features_options().
+ */
+function workflow_features_export_options() {
+  $options = array();
+  foreach (workflow_get_all() as $wid => $name) {
+    $workflow = workflow_load($wid);
+    $options[$workflow->machine_name] = $workflow->name;
+  }
+  return $options;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function workflow_features_export_render($module_name = '', $data, $module_info = array()) {
+  $code = ' $defaults = array();' . PHP_EOL;
+  module_load_include('inc', 'workflow', 'workflow.admin');
+  foreach ($data as $machine_name) {
+    $workflow = workflow_load($machine_name);
+    // Leave workflows implemented by other modules.
+    if (!in_array($workflow->module, array('workflow', $module_name))) {
+      continue;
+    }
+    $config = array(
+      'name' => $workflow->name,
+      'machine_name' => $machine_name,
+      'tab_roles' => workflow_export_tab_roles($workflow->tab_roles),
+      'options' => $workflow->options,
+      'states' => workflow_export_states($workflow->wid),
+      'roles' => workflow_export_permissions($workflow->wid),
+    );
+    foreach ($config['states'] as &$state) {
+      // Ensure the module reference is correct.
+      $state->module = $module_name;
+      // We don't want to port sid or wid because that may cause unique reference conflict.
+      unset($state->sid);
+      unset($state->wid);
+    }
+    // Clean up the code by removing information we won't use.
+    foreach ($config['roles'] as $idx => &$role) {
+      if (!isset($role['transitions'])) {
+        unset($config['roles'][$idx]);
+        continue;
+      }
+      foreach ($role['transitions'] as &$t) {
+        $t['from'] = $t['from']->ref;
+        $t['to'] = $t['to']->ref;
+      }
+    }
+    $code .= '  $defaults[] = ' . features_var_export($config, '  ') . ";\n";
+  }
+  $code .= '  return $defaults;' . PHP_EOL;
+  return array('workflow_defaults' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ */
+function workflow_features_revert($module) {
+  workflow_features_rebuild($module);
+}
+
+/**
+ * Implementation of hook_features_rebuild().
+ */
+function workflow_features_rebuild($module) {
+  $defaults = module_invoke($module, 'workflow_defaults');
+  foreach ($defaults as $config) {
+    $config['module'] = $module;
+    // Retrieve the existing workflow if it exists.
+    $wid = db_result(db_query("SELECT wid FROM {workflows} WHERE machine_name = '%s'", $config['machine_name']));
+
+    // At this point $wid will either have a value or be FALSE.
+    workflow_revert_default($config, $wid);
+  }
+}
+
+/**
+ * Get workflow roles which can view workflow tab.
+ *
+ * @param $tab_roles list of rid separated by comma
+ *
+ * @return an array of role name
+ */
+function workflow_export_tab_roles($tab_roles) {
+  $roles = user_roles();
+
+  $tab_roles_name = array();
+  $tab_roles_rid = explode(',', $tab_roles);
+  foreach ($tab_roles_rid as $rid) {
+    $tab_roles_name[] = $roles[$rid];
+  }
+
+  return $tab_roles_name;
+}
+
+/**
+ * Get workflow roles which can view workflow tab.
+ *
+ * @param $tab_roles an array of role name
+ *
+ * @return an array of rid
+ */
+function workflow_import_tab_roles($tab_roles) {
+  $roles = user_roles();
+  $roles_flip = array_flip($roles);
+
+  $tab_roles_rid = array();
+  foreach ($tab_roles as $role_name) {
+    $tab_roles_rid[] = $roles_flip[$role_name];
+  }
+
+  return $tab_roles_rid;
+}
+
+/**
+ * Get workflow states keyed by ref rather than sid.
+ *
+ * @param $wid workflow id
+ */
+function workflow_export_states($wid) {
+  $result = db_query("SELECT * FROM {workflow_states} WHERE wid = %d ORDER BY weight, ref", $wid);
+  while ($data = db_fetch_object($result)) {
+    $states[$data->ref] = $data;
+  }
+  return $states;
+}
+
+/**
+ * Get workflow permissions keyed by role name rather than rid.
+ *
+ * @param $wid workflow id
+ */
+function workflow_export_permissions($wid) {
+  $exported_permissions = array();
+
+  $permissions = workflow_permissions($wid);
+  foreach ($permissions as $rid => $role) {
+    $exported_permissions[$role['name']] = $role;
+  }
+
+  return $exported_permissions;
+}
+
+/**
+ * Helper function to revert database config back to code config.
+ */
+function workflow_revert_default($config, $wid = FALSE) {
+  $config = (object) $config;
+  if ($wid) {
+    // Config already exists in database, we're just reverting back to the code.
+    // Use ref as the database reference.
+    db_query("UPDATE {workflows} SET name = '%s', machine_name = '%s', module = '%s' WHERE wid = %d", $config->name, $config->machine_name, $config->module, $wid);
+    db_query("UPDATE {workflow_states} SET module = '%s' WHERE wid = %d", $config->module, $wid);
+    $states = workflow_export_states($wid);
+    foreach ($config->states as $state) {
+      $state['module'] = $config->module;
+      if (isset($states[$state['ref']])) {
+        drupal_write_record('workflow_states', $state, array('ref', 'module'));
+
+        // Remove any states that have been deleted.
+        if (!$state['status']) {
+          workflow_state_delete($state->sid, $new_sid);
+        }
+        unset($states[$state['ref']]);
+      }
+      // Create a new state that doesn't exist.
+      else {
+        $state['wid'] = $wid;
+        drupal_write_record('workflow_states', $state);
+      }
+    }
+    // Delete states that no longer exist.
+    $sids = array();
+    foreach ($states as $state) {
+      // It would be better to move nodes to a different state rather than
+      // orphan them, so lets move them to the next weight.
+      $new_sid = db_result(db_query('SELECT sid FROM {workflow_states} WHERE wid = %d AND weight >= %d AND status = 1 ORDER BY weight, sid', $state->wid, $state->weight));
+      workflow_state_delete($state->sid, $new_sid);
+      $sids[] = $state->sid;
+    }
+    if (!empty($sids)) {
+      db_query('DELETE FROM {workflow_states} WHERE sid IN (' . db_placeholders($sids) . ')', $sids);
+    }
+  }
+  else {
+    $wid = workflow_create($config->name, $config->module, $config->ref);
+    foreach ($config->states as &$state) {
+      $state['wid'] = $wid;
+      $state['module'] = $config->module;
+      // Update the already created (creation) state.
+      if ($state['state'] == '(creation)') {
+        drupal_write_record('workflow_states', $state, 'wid');
+        continue;
+      }
+      // Otherwise create a new state.
+      drupal_write_record('workflow_states', $state);
+    }
+  }
+
+  workflow_update($wid, $config->name, workflow_import_tab_roles($config->tab_roles), $config->options);
+
+  // Rebuild the transition permissions.
+  $transitions = array();
+  $states = array();
+  $rs = db_query('SELECT ref, sid FROM {workflow_states} WHERE wid = %d', $wid);
+  while ($row = db_fetch_object($rs)) {
+    $states[$row->ref] = $row->sid;
+  }
+
+  $user_roles = array('author' => 'author') + user_roles();
+  $roles = array_combine(array_keys($user_roles), array_pad(array(), count($user_roles), 0));
+
+  // used to work with role name instead of rid during import
+  $user_roles_flip = array_flip($user_roles);
+
+  // Build transition table.
+  $targets = $states;
+  foreach ($states as $state) {
+    foreach ($targets as $target) {
+      if ($target == $state) continue;
+      $transitions[$state][$target] = $roles;
+    }
+  }
+  foreach ($config->roles as $role_name => $perms) {
+    if (!isset($perms['transitions'])) continue;
+
+    foreach ($perms['transitions'] as $transition) {
+      $from = $states[$transition['from']];
+      $to = $states[$transition['to']];
+      $transitions[$from][$to][$user_roles_flip[$role_name]] = 1;
+    }
+  }
+  workflow_update_transitions($transitions);
+}
\ No newline at end of file
diff -urpN ..\workflow_old/workflow.install ./workflow.install
--- ..\workflow_old/workflow.install	2009-06-05 23:33:23.000000000 +0200
+++ ./workflow.install	2010-03-29 15:27:35.624875000 +0200
@@ -28,8 +28,14 @@ function workflow_schema() {
     'fields'      => array(
       'wid'       => array('type' => 'serial', 'not null' => TRUE),
       'name'      => array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => ''),
+      'machine_name' => array('type' => 'varchar', 'length' => '255', 'not null' => TRUE),
+      'module'  => array('type' => 'varchar', 'length' => '128', 'not null' => TRUE, 'default' => 'workflow'),
       'tab_roles' => array('type' => 'varchar', 'length' => '60', 'not null' => TRUE, 'default' => ''),
-      'options'   => array('type' => 'text', 'size' => 'big', 'not null' => FALSE)),
+      'options'   => array('type' => 'text', 'size' => 'big', 'not null' => FALSE)
+    ),
+    'unique keys' => array(
+      'machine_name' => array('machine_name'),
+    ),
     'primary key' => array('wid'),
   );
   $schema['workflow_type_map'] = array(
@@ -54,11 +60,16 @@ function workflow_schema() {
     'fields' => array(
       'sid'    => array('type' => 'serial', 'not null' => TRUE),
       'wid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'disp-width' => '10'),
+      'ref'    => array('type' => 'int', 'not null' => TRUE),
+      'module'  => array('type' => 'varchar', 'length' => '128', 'not null' => TRUE, 'default' => 'workflow'),
       'state'  => array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => ''),
       'weight' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0, 'disp-width' => '4'),
       'sysid'  => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0, 'disp-width' => '4'),
       'status' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 1, 'disp-width' => '4')),
     'primary key' => array('sid'),
+    'unique keys' => array(
+      'module_ref' => array('module', 'ref'),
+    ),
     'indexes' => array(
       'sysid' => array('sysid'),
       'wid' => array('wid')),
@@ -421,4 +432,24 @@ function workflow_update_6101() {
     db_change_field($ret, 'workflow_transitions', 'tid', 'tid', array('type' => 'serial', 'not null' => TRUE), array('primary key' => array('tid')));
   }
   return $ret;
+}
+
+// Add features module support (exportables)
+function workflow_update_6102() {
+  $ret = array();
+  db_add_field($ret, 'workflows', 'machine_name', array('type' => 'varchar', 'length' => '255'));
+  db_add_field($ret, 'workflows', 'module', array('type' => 'varchar', 'length' => '128', 'not null' => TRUE, 'default' => 'workflow'));
+  $rs = db_query('SELECT wid, name FROM {workflows}');
+  while ($row = db_fetch_object($rs)) {
+    $machine_name = drupal_strtolower(preg_replace('/[^\w\d]/', '_', $row->name));
+    update_sql("UPDATE {workflows} SET machine_name = '%s' WHERE wid = %d", $machine_name, $row->wid);
+  }
+  db_add_unique_key($ret, 'workflows', 'machine_name', array('machine_name'));
+
+  db_add_field($ret, 'workflow_states', 'module', array('type' => 'varchar', 'length' => '128', 'not null' => TRUE, 'default' => 'workflow'));
+  db_add_field($ret, 'workflow_states', 'ref', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
+  $ret[] = update_sql('UPDATE {workflow_states} SET ref = sid');
+  db_add_unique_key($ret, 'workflow_states', 'module_ref', array('module', 'ref'));
+
+  return $ret;
 }
\ No newline at end of file
diff -urpN ..\workflow_old/workflow.module ./workflow.module
--- ..\workflow_old/workflow.module	2010-03-03 19:17:02.000000000 +0100
+++ ./workflow.module	2010-03-16 09:40:11.181285000 +0100
@@ -195,6 +195,21 @@ function workflow_views_api() {
 }
 
 /**
+ * Implementation of hook_features_api().
+ */
+function workflow_features_api() {
+  return array(
+    'workflow' => array(
+      'name' => 'Workflow',
+      'default_hook' => 'workflow_defaults',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'features_source' => TRUE,
+      'file' => drupal_get_path('module', 'workflow') . '/workflow.features.inc',
+    ),
+  );
+}
+
+/**
  * Implementation of hook_nodeapi().
  */
 function workflow_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
@@ -830,7 +845,13 @@ function workflow_workflow($op, $old_sta
  *   Object representing the workflow.
  */
 function workflow_load($wid) {
-  $workflow = db_fetch_object(db_query('SELECT * FROM {workflows} WHERE wid = %d', $wid));
+  if (!is_numeric($wid)) {
+    $where = "machine_name = '%s'";
+  }
+  else {
+    $where = 'wid = %d';
+  }
+  $workflow = db_fetch_object(db_query('SELECT * FROM {workflows} WHERE ' . $where, $wid));
   $workflow->options = unserialize($workflow->options);
   return $workflow;
 }
@@ -1012,17 +1033,24 @@ function workflow_get_all() {
  * @param $name
  *   The name of the workflow.
  */
-function workflow_create($name) {
+function workflow_create($name, $module = 'workflow', $ref = FALSE) {
   $workflow = array(
     'name' => $name,
     'options' => serialize(array('comment_log_node' => 1, 'comment_log_tab' => 1)),
+    'module' => $module,
+    // machine_name is a unique identifier used for exporting and importing workflow.
+    'machine_name' => strtolower(preg_replace('/[^\w\d]/', '_', $name)),
   );
   drupal_write_record('workflows', $workflow);
   workflow_state_save(array(
     'wid' => $workflow['wid'],
     'state' => t('(creation)'),
     'sysid' => WORKFLOW_CREATION,
-    'weight' => WORKFLOW_CREATION_DEFAULT_WEIGHT));
+    'weight' => WORKFLOW_CREATION_DEFAULT_WEIGHT,
+    // Ref is a unique identifier used for exporting and importing workflow.
+    'ref' => $ref ? $ref : microtime(),
+    'module' => $module,
+  ));
   // Workflow creation affects tabs (local tasks), so force menu rebuild.
   menu_rebuild();
   return $workflow['wid'];
