diff --git project.inc project.inc
index 94b5b57..f2b2c2d 100644
--- project.inc
+++ project.inc
@@ -129,6 +129,43 @@ function project_project_form($node, $form_state) {
   // concerned, but the value shows up in the $node->project array for
   // validation and submission as far as FAPI is concerned.
   $form['project_node']['project'] = array('#tree' => TRUE);
+
+  // Check permissions and set sandbox value and form element status
+  if (user_access('create sandbox projects') && !user_access('create full projects')) {
+    // Force sandbox, disable checkbox
+    $is_sandbox = isset($node->project['sandbox']) ? $node->project['sandbox'] : TRUE;
+    $disabled = TRUE;
+  }
+  elseif (!user_access('create sandbox projects') && user_access('create full projects')) {
+    // Force full project, disable checkbox
+    $is_sandbox = isset($node->project['sandbox']) ? $node->project['sandbox'] : FALSE;
+    $disabled = TRUE;
+  }
+  elseif (user_access('create sandbox projects') && user_access('create full projects')) {
+    // User has full permissions, allow checkbox, use default sandbox value
+    $is_sandbox = isset($node->project['sandbox']) ? $node->project['sandbox'] : variable_get('project_sandbox_default', FALSE);
+    $disabled = FALSE;
+  }
+
+  // Do not allow demoting a project to sandbox, so only show this form item if
+  // it is applicable
+  if (!isset($node->nid) || $node->project['sandbox'] == TRUE) {
+    $form['project_node']['project']['sandbox'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Sandbox'),
+      '#default_value' => $is_sandbox,
+      '#description' => filter_xss_admin(variable_get('project_sandbox_form_description', '')),
+      '#disabled' => $disabled,
+    );
+    // Setup a varaible for the URI #required property, since project.js depends
+    // on this form element. This is okay to mark as not required since
+    // project_project_validate() checks that this value is not empty.
+    $uri_required = FALSE;
+  }
+  else {
+    $uri_required = TRUE;
+  }
+
   $form['project_node']['project']['uri'] = array(
     '#type' => 'textfield',
     '#title' => t('Short project name'),
@@ -136,7 +173,7 @@ function project_project_form($node, $form_state) {
     '#size' => 40,
     '#maxlength' => 50,
     '#description' => (variable_get('project_enable_alias', TRUE)) ? t('This will be used to generate a /project/&lt;shortname&gt;/ URL for your project.') : '',
-    '#required' => TRUE,
+    '#required' => $uri_required,
   );
   // Updating of the uri has been disabled.
   if (!variable_get('project_allow_uri_update', TRUE)) {
@@ -155,6 +192,13 @@ function project_project_form($node, $form_state) {
     }
   }
 
+  // Auto generate shortname for sandboxes, so disable the form, or simply list
+  // the value if present
+  if (variable_get('project_sandbox_numeric_shortname', FALSE) && $is_sandbox) {
+    $form['project_node']['project']['uri']['#disabled'] = TRUE;
+  }
+  drupal_add_js(array('project' => array('project_sandbox_numeric_shortname' => variable_get('project_sandbox_numeric_shortname', FALSE))), 'setting');
+
   $form['project_node']['body_field'] = node_body_field($node, t('Full description'), 1);
 
   $form['project'] = array(
@@ -245,7 +289,12 @@ function project_project_validate(&$node) {
 
   // Validate uri.
   if (empty($node->project['uri'])) {
-    form_set_error('project][uri', t('A short project name is required.'));
+    if (variable_get('project_sandbox_numeric_shortname', FALSE) && $node->project['sandbox']) {
+      $node->project['uri'] = '';
+    }
+    else {
+      form_set_error('project][uri', t('A short project name is required.'));
+    }
   }
   else {
     // Make sure uri only includes valid characters
@@ -427,14 +476,20 @@ function project_project_nodeapi(&$node, $op, $arg) {
 }
 
 function project_project_insert($node) {
-  db_query("INSERT INTO {project_projects} (nid, uri, homepage, changelog, cvs, demo, screenshots, documentation, license) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $node->nid, $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license']);
+  if (variable_get('project_sandbox_numeric_shortname', FALSE) && $node->project['sandbox']) {
+    $node->project['uri'] = $node->nid;
+  }
+  db_query("INSERT INTO {project_projects} (nid, uri, homepage, changelog, cvs, demo, screenshots, documentation, license, sandbox) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", $node->nid, $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license'], $node->project['sandbox']);
 //  project_release_scan_directory($node->project['uri']);
   $perms = array_fill_keys(array_keys(project_permission_load()), 1);
   project_maintainer_save($node->nid, $node->uid, $perms);
 }
 
 function project_project_update($node) {
-  db_query("UPDATE {project_projects} SET uri = '%s', homepage = '%s', changelog = '%s', cvs = '%s', demo = '%s', screenshots = '%s', documentation = '%s', license = '%s' WHERE nid = %d", $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license'], $node->nid);
+  if (variable_get('project_sandbox_numeric_shortname', FALSE) && $node->project['sandbox']) {
+    $node->project['uri'] = $node->nid;
+  }
+  db_query("UPDATE {project_projects} SET uri = '%s', homepage = '%s', changelog = '%s', cvs = '%s', demo = '%s', screenshots = '%s', documentation = '%s', license = '%s', sandbox = %d WHERE nid = %d", $node->project['uri'], $node->project['homepage'], $node->project['changelog'], $node->project['cvs'], $node->project['demo'], $node->project['screenshots'], $node->project['documentation'], $node->project['license'], $node->project['sandbox'], $node->nid);
 //  project_release_scan_directory($node->project['uri']);
   $perms = array_fill_keys(array_keys(project_permission_load()), 1);
   project_maintainer_save($node->nid, $node->uid, $perms);
diff --git project.install project.install
index 45c5eaa..8937170 100644
--- project.install
+++ project.install
@@ -98,6 +98,12 @@ function project_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'sandbox' => array(
+        'description' => 'Indicate whether or not this project is sandboxed.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'primary key' => array('nid'),
     'indexes' => array(
@@ -227,3 +233,31 @@ function project_update_6002() {
 
   return $ret;
 }
+
+/**
+ * Add {project_projects}.sandbox column and update permissions.
+ */
+function project_update_6003() {
+  $ret = array();
+
+  // Add the new sandbox column to the project_projects table.
+  $field = array(
+    'description' => 'Indicate whether or not this project is sandboxed.',
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  db_add_field($ret, 'project_projects', 'sandbox', $field);
+
+  // Update permissions from 'maintain projects' to 'create full projects'
+  $results = db_query("SELECT * FROM {permission}");
+  while ($row = db_fetch_object($results)) {
+    if (strpos($row->perm, 'maintain projects') !== FALSE) {
+       db_query('DELETE FROM {permission} WHERE rid = %d', $row->rid);
+      $perms = str_replace('maintain projects', 'create full projects', $row->perm);
+      db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $row->rid, $perms);
+    }
+  }
+
+  return $ret;
+}
diff --git project.js project.js
index 6660a48..864fcd9 100644
--- project.js
+++ project.js
@@ -41,3 +41,33 @@ Drupal.projectSetTaxonomy = function (tid) {
     }
   });
 }
+
+Drupal.behaviors.projectSandboxShortname = function (context) {
+
+  $('div#edit-project-sandbox-wrapper input:not(.projectSandboxShortname-processed)', context).addClass('projectSandboxShortname-processed').each(function() {
+    // Add required markup to field label
+    Drupal.projectMarkUriRequired();
+    // Only toggle the field and required label if numeric short name is turned on
+    if (Drupal.settings.project.project_sandbox_numeric_shortname) {
+      $(this).click(function () {
+        if (this.checked) {
+          $('input#edit-project-uri').attr('disabled', 'disabled');
+          $('div#edit-project-uri-wrapper label span.form-required').hide();
+        }
+        else {
+          $('input#edit-project-uri').attr('disabled', false);
+          $('div#edit-project-uri-wrapper label span.form-required').show();
+        }
+      });
+      // Set the default value when loading the page
+      if (this.checked) {
+        $('div#edit-project-uri-wrapper label span.form-required').hide();
+      }
+    }
+  });
+}
+
+Drupal.projectMarkUriRequired = function() {
+  var required = Drupal.t('This field is required.')
+  $('div#edit-project-uri-wrapper label').append('<span title="' + required + '" class="form-required">*</span>');
+}
diff --git project.module project.module
index c548364..a44c905 100644
--- project.module
+++ project.module
@@ -168,7 +168,8 @@ function project_node_info() {
 function project_perm() {
   $perms = array(
     'administer projects',
-    'maintain projects',
+    'create sandbox projects',
+    'create full projects',
     'access projects',
     'access own projects',
     'delete any projects',
@@ -350,6 +351,26 @@ function project_settings_form() {
       '#default_value' => variable_get('project_solr_project_release_api_tids_alias', 'drupal_core'),
     );
   }
+
+  $form['sandbox'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Sandbox settings'),
+    '#collapsible' => TRUE,
+  );
+  $form['sandbox']['project_sandbox_form_description'] = array(
+    '#title' => t('Project form help text'),
+    '#type' => 'textarea',
+    '#default_value' => variable_get('project_sandbox_form_description', ''),
+    '#description' => t('Enter a message to be displayed on the project form, adjacent to the sandbox checkbox.'),
+  );
+  $form['sandbox']['project_sandbox_numeric_shortname'] = array(
+    '#title' => t('Auto generate short name for sandboxes'),
+    '#type' => 'checkbox',
+    '#default_value' => variable_get('project_sandbox_numeric_shortname', FALSE),
+    '#description' => t('If checked, projects marked as sandboxes will be have their shortname automatically generated using a unique numeric identifier.'),
+  );
+
+
   return system_settings_form($form);
 }
 
@@ -628,7 +649,7 @@ function project_user_access($project, $permission) {
      return TRUE;
   }
 
-  if (user_access('maintain projects')) {
+  if (user_access('create sandbox projects') || user_access('create full projects')) {
     // Project owners are treated as super users and can always access.
     if ($user->uid == $project_obj->uid) {
        return TRUE;
@@ -741,7 +762,7 @@ function project_project_access($op, $node, $account) {
       }
       break;
     case 'create':
-      if ($account->uid && user_access('maintain projects')) {
+      if ($account->uid && (user_access('create sandbox projects') || user_access('create full projects'))) {
         // Since this CVS access checking is non-standard, we need to
         // special-case uid 1 to always allow everything.
         if ($account->uid != 1 && module_exists('cvs') && variable_get('cvs_restrict_project_creation', 1)) {
diff --git views/project.views.inc views/project.views.inc
index b9c6f98..2a466e6 100644
--- views/project.views.inc
+++ views/project.views.inc
@@ -189,6 +189,26 @@ function project_views_data() {
     ),
   );
 
+  // sandbox
+  $data['project_projects']['sandbox'] = array(
+    'title' => t('Sandbox'),
+    'help' => t('Indicate whether or not this project is a sandbox.'),
+    'field' => array(
+      'group' => t('Project'),
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+     ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator ',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
+  );
+
   return $data;
 }
 
