diff --git a/include/ajax.tasks.php b/include/ajax.tasks.php
index 638f6982d8a1dcf14a3c4686490a347a5c00c086..15a623c4d7d45e324540e9d0426f37b35205ed85 100644
--- a/include/ajax.tasks.php
+++ b/include/ajax.tasks.php
@@ -19,6 +19,7 @@ if(!defined('INCLUDE_DIR')) die('403');
 include_once(INCLUDE_DIR.'class.ticket.php');
 require_once(INCLUDE_DIR.'class.ajax.php');
 require_once(INCLUDE_DIR.'class.task.php');
+include_once INCLUDE_DIR . 'class.thread_actions.php';
 
 class TasksAjaxAPI extends AjaxController {
 
@@ -57,9 +58,35 @@ class TasksAjaxAPI extends AjaxController {
         return $this->json_encode($tasks);
     }
 
-    function add() {
+    function triggerThreadAction($task_id, $thread_id, $action) {
+        $thread = ThreadEntry::lookup($thread_id);
+        if (!$thread)
+            Http::response(404, 'No such task thread entry');
+        if ($thread->getThread()->getObjectId() != $task_id)
+            Http::response(404, 'No such task thread entry');
+
+        $valid = false;
+        foreach ($thread->getActions() as $group=>$list) {
+            foreach ($list as $name=>$A) {
+                if ($A->getId() == $action) {
+                    $valid = true; break;
+                }
+            }
+        }
+
+        if (!$valid)
+          Http::response(400, 'Not a valid action for this thread');
+
+
+        $thread->triggerAction($action);
+    }
+
+    function add($tid=0, $vars=array()) {
         global $thisstaff;
 
+        if ($tid)
+          $originalTask = Task::lookup($tid);
+
         $info=$errors=array();
         if ($_POST) {
             Draft::deleteForNamespace('task.add', $thisstaff->getId());
@@ -86,11 +113,53 @@ class TasksAjaxAPI extends AjaxController {
                 $vars['staffId'] = $thisstaff->getId();
                 $vars['poster'] = $thisstaff;
                 $vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
-                if (($task=Task::create($vars, $errors)))
-                    Http::response(201, $task->getId());
+                if (($task=Task::create($vars, $errors))) {
+                  if ($_SESSION[':form-data']['eid']) {
+                    //add internal note to original task:
+                    $taskLink = sprintf('<a href="tasks.php?id=%d"><b>#%d</b></a>',
+                        $task->getId(),
+                        $task->getId());
+
+                    $entryLink = sprintf('<a href="#entry-%d"><b>%d</b></a> (%s)',
+                        $_SESSION[':form-data']['eid'],
+                        $_SESSION[':form-data']['eid'],
+                        Format::datetime($_SESSION[':form-data']['timestamp']));
+
+                    $note = array(
+                            'title' => __('Task Created From Thread'),
+                            'note' => __('Task ' . $taskLink .
+                            '<br /> Thread Entry ID: ' . $entryLink)
+                            );
+
+                    $originalTask->postNote($note, $errors, $thisstaff);
+
+                    //add internal note to new task:
+                    $taskLink = sprintf('<a href="tasks.php?id=%d"><b>#%s</b></a>',
+                        $originalTask->getId(),
+                        $originalTask->getNumber());
+
+                    $note = array(
+                            'title' => __('Task Created From Thread'),
+                            'note' => __('This Task was created from Task ' . $taskLink));
+
+                    $task->postNote($note, $errors, $thisstaff);
+
+                    unset($_SESSION[':form-data']);
+                  }
+
+                  Http::response(201, $task->getId());
+                }
+              }
+              $info['error'] = sprintf('%s - %s', __('Error adding task'), __('Please try again!'));
             }
 
-            $info['error'] = sprintf('%s - %s', __('Error adding task'), __('Please try again!'));
+        if ($originalTask) {
+          $info['action'] = sprintf('#tasks/%d/add', $originalTask->getId());
+          $info['title'] = sprintf(
+                  __( 'Task #%1$s: %2$s'),
+                  $originalTask->getNumber(),
+                  __('Add New Task')
+                  );
         }
 
         include STAFFINC_DIR . 'templates/task.tmpl.php';
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index 91f12f895d7945e804bbc05ac72e3837bb6f9e64..5377996c628c55c498a78e8d50650dd10815a713 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -1348,8 +1348,42 @@ function refer($tid, $target=null) {
                 $vars['staffId'] = $thisstaff->getId();
                 $vars['poster'] = $thisstaff;
                 $vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
-                if (($task=Task::create($vars, $errors)))
-                    Http::response(201, $task->getId());
+                if (($task=Task::create($vars, $errors))) {
+
+                  if ($_SESSION[':form-data']['eid']) {
+                    //add internal note to ticket:
+                    $taskLink = sprintf('<a href="tasks.php?id=%d"><b>#%d</b></a>',
+                        $task->getId(),
+                        $task->getId());
+
+                    $entryLink = sprintf('<a href="#entry-%d"><b>%d</b></a> (%s)',
+                        $_SESSION[':form-data']['eid'],
+                        $_SESSION[':form-data']['eid'],
+                        Format::datetime($_SESSION[':form-data']['timestamp']));
+
+                    $note = array(
+                            'title' => __('Task Created From Thread'),
+                            'body' => __('Task ' . $taskLink .
+                            '<br /> Thread Entry ID: ' . $entryLink)
+                            );
+
+                  $ticket->logNote($note['title'], $note['body'], $thisstaff);
+
+                    //add internal note to task:
+                    $ticketLink = sprintf('<a href="tickets.php?id=%d"><b>#%s</b></a>',
+                        $ticket->getId(),
+                        $ticket->getNumber());
+
+                    $note = array(
+                            'title' => __('Task Created From Thread'),
+                            'note' => __('This Task was created from Ticket ' . $ticketLink));
+
+                    $task->postNote($note, $errors, $thisstaff);
+                  }
+                    unset($_SESSION[':form-data']);
+                  }
+
+                  Http::response(201, $task->getId());
             }
 
             $info['error'] = sprintf('%s - %s', __('Error adding task'), __('Please try again!'));
diff --git a/include/class.thread.php b/include/class.thread.php
index 017d7db353c3fbd5740935138f2fc26222a03dcb..353ce11b5ed6f38bf7651f974d3aa9b07b1e1c16 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -3007,8 +3007,9 @@ abstract class ThreadEntryAction {
      *      `#` in the url
      */
     function getAjaxUrl($dialog=false) {
-        return sprintf('%stickets/%d/thread/%d/%s',
+        return sprintf('%s%s/%d/thread/%d/%s',
             $dialog ? '#' : 'ajax.php/',
+            $this->entry->getThread()->getObjectType() == 'T' ? 'tickets' : 'tasks',
             $this->entry->getThread()->getObjectId(),
             $this->entry->getId(),
             static::getId()
@@ -3018,6 +3019,10 @@ abstract class ThreadEntryAction {
     function getTicketsAPI() {
         return new TicketsAjaxAPI();
     }
+
+    function getTasksAPI() {
+        return new TasksAjaxAPI();
+    }
 }
 
 interface Threadable {
diff --git a/include/class.thread_actions.php b/include/class.thread_actions.php
index 08e83dccef789b4cfc8aaf1f4ca3a8833b0f21a5..a2c67788c5ba397585a459b42b8ed786a88d4d63 100644
--- a/include/class.thread_actions.php
+++ b/include/class.thread_actions.php
@@ -489,10 +489,11 @@ $.dialog(url, [201], function(xhr, resp) {
     if (!!redirect)
         $.pjax({url: redirect, container: '#pjax-container'});
     else
-        $.pjax({url: 'tickets.php?id=%d#tasks', container: '#pjax-container'});
+        $.pjax({url: '%s.php?id=%d#tasks', container: '#pjax-container'});
 });
 JS
         , $this->getAjaxUrl(),
+        $this->entry->getThread()->getObjectType() == 'T' ? 'tickets' : 'tasks',
         $this->entry->getThread()->getObjectId()
         );
     }
@@ -507,9 +508,14 @@ JS
     }
 
     private function trigger__get() {
-
         $vars = array(
                 'description' => Format::htmlchars($this->entry->getBody()));
+
+        $_SESSION[':form-data']['tid'] = $this->entry->getThread()->getObJectId();
+        $_SESSION[':form-data']['eid'] = $this->entry->getId();
+        $_SESSION[':form-data']['timestamp'] = $this->entry->getCreateDate();
+        $_SESSION[':form-data']['type'] = $this->entry->getThread()->object_type;
+
         if (($f= TaskForm::getInstance()->getField('description'))) {
               $k = 'attach:'.$f->getId();
               unset($_SESSION[':form-data'][$k]);
@@ -519,11 +525,18 @@ JS
                   }
         }
 
-        return $this->getTicketsAPI()->addTask($this->getObjectId(), $vars);
+        if ($this->entry->getThread()->getObjectType()  == 'T')
+          return $this->getTicketsAPI()->addTask($this->getObjectId(), $vars); //TasksAjaxAPI
+        else
+          return $this->getTasksAPI()->add($this->getObjectId(), $vars);
+
     }
 
     private function trigger__post() {
-        return $this->getTicketsAPI()->addTask($this->getObjectId());
+      if ($this->entry->getThread()->getObjectType()  == 'T')
+        return $this->getTicketsAPI()->addTask($this->getObjectId(), $vars);
+      else
+        return $this->getTasksAPI()->add($this->getObjectId(), $vars);
     }
 
 }
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 167703aaf49e2d1ae32d405f33210892b29b548c..f28f4e8e1d670bfec09aeeca9dcea6a2f7a5f9c2 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -3886,6 +3886,56 @@ implements RestrictedAccess, Threadable, Searchable {
             $message->save();
         }
 
+        //check to see if ticket was created from a thread
+        if ($_SESSION[':form-data']['ticket'] || $_SESSION[':form-data']['task']) {
+          $oldTicket = $_SESSION[':form-data']['ticket'];
+          $oldTask = $_SESSION[':form-data']['task'];
+
+          //add internal note to new ticket.
+          //New ticket should have link to old task/ticket:
+          $link = sprintf('<a href="%s.php?id=%d#entry-%d"><b>#%s</b></a>',
+              $oldTicket ? 'tickets' : 'tasks',
+              $oldTicket ? $oldTicket->getId() : $oldTask->getId(),
+              $_SESSION[':form-data']['eid'],
+              $oldTicket ? $oldTicket->getNumber() : $oldTask->getNumber());
+
+          $note = array(
+                  'title' => __('Ticket Created From Thread'),
+                  'body' => sprintf(__('This Ticket was created from %s '. $link),
+                            $oldTicket ? 'Ticket' : 'Task')
+                  );
+
+          $ticket->logNote($note['title'], $note['body'], $thisstaff);
+
+          //add internal note to referenced ticket/task
+          // Old ticket/task should have link to new ticket
+          $ticketLink = sprintf('<a href="tickets.php?id=%d"><b>#%s</b></a>',
+              $ticket->getId(),
+              $ticket->getNumber());
+
+          $entryLink = sprintf('<a href="#entry-%d"><b>%d</b></a> (%s)',
+              $_SESSION[':form-data']['eid'],
+              $_SESSION[':form-data']['eid'],
+              Format::datetime($_SESSION[':form-data']['timestamp']));
+
+          $ticketNote = array(
+              'title' => __('Ticket Created From Thread'),
+              'body' => __('Ticket ' . $ticketLink).
+              '<br /> Thread Entry ID: ' . $entryLink);
+
+          $taskNote = array(
+              'title' => __('Ticket Created From Thread'),
+              'note' => __('Ticket ' . $ticketLink).
+              '<br /> Thread Entry ID: ' . $entryLink);
+
+          if ($oldTicket)
+            $oldTicket->logNote($ticketNote['title'], $ticketNote['body'], $thisstaff);
+          elseif ($oldTask)
+            $oldTask->postNote($taskNote, $errors, $thisstaff);
+
+          unset($_SESSION[':form-data']);
+        }
+
         // Configure service-level-agreement for this ticket
         $ticket->selectSLAId($vars['slaId']);
 
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index 5185c11d7549f4f66e83be8456c42fb877dc22e1..277714d5b701b9bfb22ecc8a83c5a2c5fceceaea 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -9,7 +9,17 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 //  Use thread entry to seed the ticket
 if (!$user && $_GET['tid'] && ($entry = ThreadEntry::lookup($_GET['tid']))) {
+    if ($entry->getThread()->getObjectType() == 'T')
+      $oldTicket = Ticket::lookup($entry->getThread()->getObjectId());
+    if ($entry->getThread()->getObjectType() == 'A')
+      $oldTask = Task::lookup($entry->getThread()->getObjectId());
+
     $_SESSION[':form-data']['message'] = Format::htmlchars($entry->getBody());
+    $_SESSION[':form-data']['ticket'] = $oldTicket;
+    $_SESSION[':form-data']['task'] = $oldTask;
+    $_SESSION[':form-data']['eid'] = $entry->getId();
+    $_SESSION[':form-data']['timestamp'] = $entry->getCreateDate();
+
     if ($entry->user_id)
        $user = User::lookup($entry->user_id);
 
diff --git a/scp/ajax.php b/scp/ajax.php
index 85d010e92b48b47d39643715bd8d9884c4c040c8..7dc4a56a2a9c690add163d05fed948045ad7cd2a 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -203,7 +203,9 @@ $dispatcher = patterns('',
         url('^(?P<tid>\d+)/reopen', 'reopen'),
         url_get('^(?P<tid>\d+)/view$', 'task'),
         url_post('^(?P<tid>\d+)$', 'task'),
+        url('^(?P<tid>\d+)/thread/(?P<thread_id>\d+)/(?P<action>\w+)$', 'triggerThreadAction'),
         url('^add$', 'add'),
+        url('^(?P<tid>\d+)/add', 'add'),
         url('^lookup', 'lookup'),
         url('^mass/(?P<action>\w+)(?:/(?P<what>\w+))?', 'massProcess')
     )),