diff --git a/sites/all/modules/drupalorg/drupalorg_handbook/drupalorg_handbook.module b/sites/all/modules/drupalorg/drupalorg_handbook/drupalorg_handbook.module
index 9aa2745..b061577 100644
--- a/sites/all/modules/drupalorg/drupalorg_handbook/drupalorg_handbook.module
+++ b/sites/all/modules/drupalorg/drupalorg_handbook/drupalorg_handbook.module
@@ -532,7 +532,7 @@ function theme_drupalorg_handbook_footer_line() {
 function drupalorg_handbook_form_comment_form_alter(&$form, $form_state) {
   // Make sure we are on a form to add a new comment (not edit existing),
   // and that the node is a book node.
-  if(isset($form['#node']->book['bid']) && !isset($form_state['comment']->cid) && $form['#node']->type != 'project_issue') {
+  if(!empty($form['#node']->book['bid']) && !isset($form_state['comment']->cid)) {
     // This is a node in a book. Display disclaimer.
     $form['drupalorg-disclaimer'] = array(
       '#weight' => -2,
diff --git a/sites/all/modules/drupalorg/drupalorg_project/drupalorg_project.module b/sites/all/modules/drupalorg/drupalorg_project/drupalorg_project.module
index b93da83..ad3be4e 100644
--- a/sites/all/modules/drupalorg/drupalorg_project/drupalorg_project.module
+++ b/sites/all/modules/drupalorg/drupalorg_project/drupalorg_project.module
@@ -180,6 +180,13 @@ function drupalorg_project_menu_alter(&$items) {
   // own special rules in a few cases.
   $items['node/%project_edit_project/edit/promote']['access callback'] = 'drupalorg_project_promote_project_access';
   $items['node/%project_edit_project/edit/promote/confirm']['access callback'] = 'drupalorg_project_promote_project_access';
+
+  // In order to support the issue edit form on a non-node/%/edit URL, need to
+  // explicitly spell out where to find validate, form, etc. functions.
+  $items['file/ajax']['file'] = 'node.pages.inc';
+  $items['file/ajax']['file path'] = drupal_get_path('module', 'node');
+  $items['node/%node']['file'] = 'node.pages.inc';
+  $items['node/%node']['file path'] = drupal_get_path('module', 'node');
 }
 
 /**
@@ -358,6 +365,81 @@ function drupalorg_project_form_project_issue_node_form_alter(&$form, $form_stat
       $form['field_issue_related'][LANGUAGE_NONE][$key]['target_id']['#size'] = 100;
     }
   }
+
+  // Simplify the look of the issue edit form.
+  // @todo Ideally, all of this code would be in project_issue module "proper."
+  // Re-title the field groups and set them to collapsed by default.
+  // @todo: It looks like we're doing at least some of this in project_issue.field_group.inc
+  // as part of this patch. Do we still need it here?
+  $form['#groups']['group_issue_metadata']->label = t('Issue metadata');
+  $form['#groups']['group_issue_relations']->label = t('Issue summary & relationships');
+  $form['#groups']['group_issue_metadata']->format_settings['formatter'] =
+      isset($form['#node']->embed_issue_form) ? 'collapsed' : 'collapsible';
+  $form['#groups']['group_issue_relations']->format_settings['formatter'] = 'collapsed';
+
+  // Move the title field under the "Issue metadata" group.
+  $form['title']['#group'] = 'group_issue_metadata';
+  $form['#group_children']['title'] = 'group_issue_metadata';
+
+  // Move the body field under the "Issue summary & relationships" group.
+  $form['body']['#group'] = 'group_issue_relations';
+  $form['#group_children']['body'] = 'group_issue_relations';
+
+  // Move file uploads under a collapsed fieldset.
+  $issue = $form['#node'];
+  $form['field_issue_files'][$issue->language]['#collapsible'] = TRUE;
+  $form['field_issue_files'][$issue->language]['#collapsed'] = TRUE;
+  $form['field_issue_files'][$issue->language]['#process'][] = 'form_process_fieldset';
+  $form['field_issue_files'][$issue->language]['#title'] = t('Files');
+
+  if (!empty($form['#node']->embed_issue_form)) {
+    // Hide all existing files from showing up in the node file table.
+    // Do this by temporarily NULLing their default value.
+    foreach (element_children($form['field_issue_files'][$issue->language]) as $key) {
+      if ($form['field_issue_files'][$issue->language][$key]['#default_value']['fid'] != 0) {
+        $form['field_issue_files'][$issue->language][$key]['#default_value'] = NULL;
+      }
+    }
+
+    // Remove vertical tabs and issue comment description.
+    $form['additional_settings']['#access'] = FALSE;
+    unset($form['nodechanges_comment_body']['#description']);
+
+    // Remove buttons on the form other than "Save".
+    // @todo: Preview should come back at some point.
+    $form['actions']['delete']['#access'] = FALSE;
+    $form['actions']['preview_changes']['#access'] = FALSE;
+    $form['actions']['preview']['#access'] = FALSE;
+
+    $form['#submit'][] = 'drupalorg_project_embedded_issue_form_submit';
+  }
+}
+
+/**
+ * Perform special processing on the embedded issue form.
+ */
+function drupalorg_project_embedded_issue_form_submit(&$form, &$form_state) {
+  $node = $form_state['node'];
+
+  // The old $node->status gets lost because the vertical tabs were removed
+  // from view. Restore it from the original node.
+  $form_state['values']['status'] = $form['#node']->status;
+
+  // Now, restore the existing file values from $form_state so they're not
+  // lost when the form is submitted.
+  if (isset($node->field_issue_files[$node->language])) {
+    foreach ($node->field_issue_files[$node->language] as $delta => $value) {
+      if (isset($node->field_issue_files[$node->language][$delta])) {
+        if ($form_state['values']['field_issue_files'][$node->language][$delta]['fid'] != 0) {
+          $form_state['values']['field_issue_files'][$node->language][] = $form_state['values']['field_issue_files'][$node->language][$delta];
+          $form_state['values']['field_issue_files'][$node->language][$delta] = $value;
+        }
+        else {
+          $form_state['values']['field_issue_files'][$node->language][$delta] = $value;
+        }
+      }
+    }
+  }
 }
 
 /**
@@ -542,6 +624,15 @@ function drupalorg_project_node_view($node, $view_mode = 'full') {
           hide($node->content[$element]);
         }
       }
+
+      // Add a property to the issue to tell if we're in an embedded form or not.
+      $node->embed_issue_form = TRUE;
+
+      // Render the issue edit form in place of the comment form.
+      // This works by re-using the same array indexes as the comment form.
+      // Magic! :)
+      $issue_form = drupal_get_form('project_issue_node_form', $node);
+      $node->content['comments']['comment_form'] = $issue_form;
     }
     switch ($node->nid) {
       case 199251: // List projects with commit RSS feeds.
