diff --git a/__tests__/constants/default-processor-options.ts b/__tests__/constants/default-processor-options.ts
index 0265b6446..5d61c1300 100644
--- a/__tests__/constants/default-processor-options.ts
+++ b/__tests__/constants/default-processor-options.ts
@@ -6,18 +6,25 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
   repoToken: 'none',
   staleIssueMessage: 'This issue is stale',
   stalePrMessage: 'This PR is stale',
+  rottenIssueMessage: 'This issue is rotten',
+  rottenPrMessage: 'This PR is rotten',
   closeIssueMessage: 'This issue is being closed',
   closePrMessage: 'This PR is being closed',
   daysBeforeStale: 1,
+  daysBeforeRotten: -1,
   daysBeforeIssueStale: NaN,
   daysBeforePrStale: NaN,
+  daysBeforeIssueRotten: NaN,
+  daysBeforePrRotten: NaN,
   daysBeforeClose: 30,
   daysBeforeIssueClose: NaN,
   daysBeforePrClose: NaN,
   staleIssueLabel: 'Stale',
+  rottenIssueLabel: 'Rotten',
   closeIssueLabel: '',
   exemptIssueLabels: '',
   stalePrLabel: 'Stale',
+  rottenPrLabel: 'Rotten',
   closePrLabel: '',
   exemptPrLabels: '',
   onlyLabels: '',
@@ -31,6 +38,9 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
   removeStaleWhenUpdated: false,
   removeIssueStaleWhenUpdated: undefined,
   removePrStaleWhenUpdated: undefined,
+  removeRottenWhenUpdated: false,
+  removeIssueRottenWhenUpdated: undefined,
+  removePrRottenWhenUpdated: undefined,
   ascending: false,
   deleteBranch: false,
   startDate: '',
@@ -50,6 +60,9 @@ export const DefaultProcessorOptions: IIssuesProcessorOptions = Object.freeze({
   labelsToRemoveWhenStale: '',
   labelsToRemoveWhenUnstale: '',
   labelsToAddWhenUnstale: '',
+  labelsToRemoveWhenRotten: '',
+  labelsToRemoveWhenUnrotten: '',
+  labelsToAddWhenUnrotten: '',
   ignoreUpdates: false,
   ignoreIssueUpdates: undefined,
   ignorePrUpdates: undefined,
diff --git a/__tests__/main.spec.ts b/__tests__/main.spec.ts
index 80d660e88..d540b3e48 100644
--- a/__tests__/main.spec.ts
+++ b/__tests__/main.spec.ts
@@ -159,11 +159,12 @@ test('processing an issue with no label and a start date as ECMAScript epoch in
 });
 
 test('processing an issue with no label and a start date as ISO 8601 being before the issue creation date will make it stale and close it when it is old enough and days-before-close is set to 0', async () => {
-  expect.assertions(2);
+  expect.assertions(3);
   const january2000 = '2000-01-01T00:00:00Z';
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     daysBeforeClose: 0,
+    daysBeforeRotten: 0,
     startDate: january2000.toString()
   };
   const TestIssueList: Issue[] = [
@@ -187,6 +188,7 @@ test('processing an issue with no label and a start date as ISO 8601 being befor
   await processor.processIssues(1);
 
   expect(processor.staleIssues.length).toStrictEqual(1);
+  expect(processor.rottenIssues.length).toStrictEqual(1);
   expect(processor.closedIssues.length).toStrictEqual(1);
 });
 
@@ -222,6 +224,39 @@ test('processing an issue with no label and a start date as ISO 8601 being after
   expect(processor.closedIssues.length).toStrictEqual(0);
 });
 
+test('processing an issue with no label and a start date as ISO 8601 being after the issue creation date will not make it stale , rotten or close it when it is old enough and days-before-close is set to 0', async () => {
+  expect.assertions(3);
+  const january2021 = '2021-01-01T00:00:00Z';
+  const opts: IIssuesProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeClose: 0,
+    startDate: january2021.toString()
+  };
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'An issue with no label',
+      '2020-01-01T17:00:00Z',
+      '2020-01-01T17:00:00Z'
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    opts,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues.length).toStrictEqual(0);
+  expect(processor.rottenIssues.length).toStrictEqual(0);
+  expect(processor.closedIssues.length).toStrictEqual(0);
+});
+
 test('processing an issue with no label and a start date as RFC 2822 being before the issue creation date will make it stale and close it when it is old enough and days-before-close is set to 0', async () => {
   expect.assertions(2);
   const january2000 = 'January 1, 2000 00:00:00';
@@ -290,6 +325,7 @@ test('processing an issue with no label will make it stale and close it, if it i
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     daysBeforeClose: 1,
+    daysBeforeRotten: 0,
     daysBeforeIssueClose: 0
   };
   const TestIssueList: Issue[] = [
@@ -307,6 +343,7 @@ test('processing an issue with no label will make it stale and close it, if it i
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
   expect(processor.closedIssues).toHaveLength(1);
   expect(processor.deletedBranchIssues).toHaveLength(0);
 });
@@ -459,10 +496,11 @@ test('processing an issue with no label will make it stale but not close it', as
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale issue will close it', async () => {
+test('processing a stale issue will rot it but not close it, given days before rotten is > -1', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
-    daysBeforeClose: 30
+    daysBeforeClose: 30,
+    daysBeforeRotten: 0
   };
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -488,13 +526,15 @@ test('processing a stale issue will close it', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale issue containing a space in the label will close it', async () => {
+test('processing a stale issue containing a space in the label will rotten it but not close it, given days before rotten is > -1', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
-    staleIssueLabel: 'state: stale'
+    staleIssueLabel: 'state: stale',
+    daysBeforeRotten: 0
   };
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -520,13 +560,15 @@ test('processing a stale issue containing a space in the label will close it', a
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale issue containing a slash in the label will close it', async () => {
+test('processing a stale issue containing a slash in the label will rotten it but not close it', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
-    staleIssueLabel: 'lifecycle/stale'
+    staleIssueLabel: 'lifecycle/stale',
+    daysBeforeRotten: 0
   };
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -552,20 +594,21 @@ test('processing a stale issue containing a slash in the label will close it', a
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale issue will close it when days-before-issue-stale override days-before-stale', async () => {
+test('processing a stale issue will rotten it but not close it when days-before-issue-rotten override days-before-rotten', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
-    daysBeforeClose: 30,
-    daysBeforeIssueStale: 30
+    daysBeforeRotten: -1,
+    daysBeforeIssueRotten: 30
   };
   const TestIssueList: Issue[] = [
     generateIssue(
       opts,
       1,
-      'A stale issue that should be closed',
+      'A stale issue that should be rotten',
       '2020-01-01T17:00:00Z',
       '2020-01-01T17:00:00Z',
       false,
@@ -585,13 +628,14 @@ test('processing a stale issue will close it when days-before-issue-stale overri
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale PR will close it', async () => {
+test('processing a stale PR will rotten it but not close it', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
-    daysBeforeClose: 30
+    daysBeforePrRotten: 30
   };
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -617,13 +661,49 @@ test('processing a stale PR will close it', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale PR will close it when days-before-pr-stale override days-before-stale', async () => {
+test('processing a stale PR will rotten it it when days-before-pr-rotten override days-before-rotten', async () => {
+  const opts: IIssuesProcessorOptions = {
+    ...DefaultProcessorOptions,
+    daysBeforeRotten: 30,
+    daysBeforePrRotten: 30
+  };
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A stale PR that should be closed',
+      '2020-01-01T17:00:00Z',
+      '2020-01-01T17:00:00Z',
+      false,
+      true,
+      ['Stale']
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    opts,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
+});
+
+test('processing a stale PR will rotten it but not close it when days-before-pr-stale override days-before-stale', async () => {
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     daysBeforeClose: 30,
+    daysBeforeRotten: 0,
     daysBeforePrClose: 30
   };
   const TestIssueList: Issue[] = [
@@ -650,13 +730,15 @@ test('processing a stale PR will close it when days-before-pr-stale override day
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale issue will close it even if configured not to mark as stale', async () => {
+test('processing a stale issue will rotten it even if configured not to mark as stale', async () => {
   const opts = {
     ...DefaultProcessorOptions,
     daysBeforeStale: -1,
+    daysBeforeRotten: 0,
     staleIssueMessage: ''
   };
   const TestIssueList: Issue[] = [
@@ -683,13 +765,16 @@ test('processing a stale issue will close it even if configured not to mark as s
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
 test('processing a stale issue will close it even if configured not to mark as stale when days-before-issue-stale override days-before-stale', async () => {
   const opts = {
     ...DefaultProcessorOptions,
     daysBeforeStale: 0,
+    daysBeforeRotten: 0,
+
     daysBeforeIssueStale: -1,
     staleIssueMessage: ''
   };
@@ -717,13 +802,15 @@ test('processing a stale issue will close it even if configured not to mark as s
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a stale PR will close it even if configured not to mark as stale', async () => {
+test('processing a stale PR will rotten it even if configured not to mark as stale', async () => {
   const opts = {
     ...DefaultProcessorOptions,
     daysBeforeStale: -1,
+    daysBeforeRotten: 0,
     stalePrMessage: ''
   };
   const TestIssueList: Issue[] = [
@@ -750,14 +837,52 @@ test('processing a stale PR will close it even if configured not to mark as stal
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
+});
+
+test('processing a stale PR will close it even if configured not to mark as stale or rotten', async () => {
+  const opts = {
+    ...DefaultProcessorOptions,
+    daysBeforeStale: -1,
+    stalePrMessage: '',
+    daysBeforeRotten: -1
+  };
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'An issue with no label',
+      '2020-01-01T17:00:00Z',
+      '2020-01-01T17:00:00Z',
+      false,
+      true,
+      ['Stale']
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    opts,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(1);
 });
 
-test('processing a stale PR will close it even if configured not to mark as stale when days-before-pr-stale override days-before-stale', async () => {
+test('processing a stale PR will rotten it even if configured not to mark as stale when days-before-pr-stale override days-before-stale', async () => {
   const opts = {
     ...DefaultProcessorOptions,
     daysBeforeStale: 0,
     daysBeforePrStale: -1,
+    daysBeforeRotten: 0,
+
     stalePrMessage: ''
   };
   const TestIssueList: Issue[] = [
@@ -784,10 +909,11 @@ test('processing a stale PR will close it even if configured not to mark as stal
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('closed issues will not be marked stale', async () => {
+test('closed issues will not be marked stale or rotten', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -812,10 +938,41 @@ test('closed issues will not be marked stale', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('stale closed issues will not be closed', async () => {
+test('rotten closed issues will not be closed', async () => {
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      DefaultProcessorOptions,
+      1,
+      'A rotten closed issue',
+      '2020-01-01T17:00:00Z',
+      '2020-01-01T17:00:00Z',
+      false,
+      false,
+      ['Rotten'],
+      true
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    DefaultProcessorOptions,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
+  expect(processor.closedIssues).toHaveLength(0);
+});
+
+test('stale closed issues will not be closed or rotten', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -841,10 +998,11 @@ test('stale closed issues will not be closed', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('closed prs will not be marked stale', async () => {
+test('closed prs will not be marked stale or rotten', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -870,6 +1028,7 @@ test('closed prs will not be marked stale', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
@@ -902,7 +1061,7 @@ test('stale closed prs will not be closed', async () => {
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('locked issues will not be marked stale', async () => {
+test('locked issues will not be marked stale or rotten', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -927,10 +1086,11 @@ test('locked issues will not be marked stale', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('stale locked issues will not be closed', async () => {
+test('stale locked issues will not be rotten or closed', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -957,10 +1117,42 @@ test('stale locked issues will not be closed', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('locked prs will not be marked stale', async () => {
+test('rotten locked issues will not be rotten or closed', async () => {
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      DefaultProcessorOptions,
+      1,
+      'A stale locked issue that will not be closed',
+      '2020-01-01T17:00:00Z',
+      '2020-01-01T17:00:00Z',
+      false,
+      false,
+      ['Rotten'],
+      false,
+      true
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    DefaultProcessorOptions,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
+  expect(processor.closedIssues).toHaveLength(0);
+});
+
+test('locked prs will not be marked stale or rotten', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -985,10 +1177,11 @@ test('locked prs will not be marked stale', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('stale locked prs will not be closed', async () => {
+test('stale locked prs will not be rotten or closed', async () => {
   const TestIssueList: Issue[] = [
     generateIssue(
       DefaultProcessorOptions,
@@ -1015,11 +1208,12 @@ test('stale locked prs will not be closed', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('exempt issue labels will not be marked stale', async () => {
-  expect.assertions(3);
+test('exempt issue labels will not be marked stale or rotten', async () => {
+  expect.assertions(4);
   const opts = {...DefaultProcessorOptions};
   opts.exemptIssueLabels = 'Exempt';
   const TestIssueList: Issue[] = [
@@ -1046,11 +1240,12 @@ test('exempt issue labels will not be marked stale', async () => {
   await processor.processIssues(1);
 
   expect(processor.staleIssues.length).toStrictEqual(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues.length).toStrictEqual(0);
   expect(processor.removedLabelIssues.length).toStrictEqual(0);
 });
 
-test('exempt issue labels will not be marked stale (multi issue label with spaces)', async () => {
+test('exempt issue labels will not be marked stale or rotten (multi issue label with spaces)', async () => {
   const opts = {...DefaultProcessorOptions};
   opts.exemptIssueLabels = 'Exempt, Cool, None';
   const TestIssueList: Issue[] = [
@@ -1077,6 +1272,7 @@ test('exempt issue labels will not be marked stale (multi issue label with space
   await processor.processIssues(1);
 
   expect(processor.staleIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.closedIssues).toHaveLength(0);
 });
 
@@ -1210,7 +1406,11 @@ test('stale issues should not be closed if days is set to -1', async () => {
 });
 
 test('stale label should be removed if a comment was added to a stale issue', async () => {
-  const opts = {...DefaultProcessorOptions, removeStaleWhenUpdated: true};
+  const opts = {
+    ...DefaultProcessorOptions,
+    removeStaleWhenUpdated: true,
+    daysBeforeRotten: 0
+  };
   const TestIssueList: Issue[] = [
     generateIssue(
       opts,
@@ -1337,8 +1537,12 @@ test('when the option "labelsToRemoveWhenStale" is set, the labels should be rem
   expect(processor.removedLabelIssues).toHaveLength(1);
 });
 
-test('stale label should not be removed if a comment was added by the bot (and the issue should be closed)', async () => {
-  const opts = {...DefaultProcessorOptions, removeStaleWhenUpdated: true};
+test('stale label should not be removed if a comment was added by the bot, given that it does not get rotten', async () => {
+  const opts = {
+    ...DefaultProcessorOptions,
+    removeStaleWhenUpdated: true,
+    daysBeforeRotten: -1
+  };
   github.context.actor = 'abot';
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -1372,6 +1576,7 @@ test('stale label should not be removed if a comment was added by the bot (and t
   await processor.processIssues(1);
 
   expect(processor.closedIssues).toHaveLength(1);
+  expect(processor.rottenIssues).toHaveLength(0);
   expect(processor.staleIssues).toHaveLength(0);
   expect(processor.removedLabelIssues).toHaveLength(0);
 });
@@ -1442,10 +1647,10 @@ test('stale issues should not be closed until after the closed number of days',
   expect(processor.staleIssues).toHaveLength(1);
 });
 
-test('stale issues should be closed if the closed nubmer of days (additive) is also passed', async () => {
+test('stale issues should be rotten if the rotten nubmer of days (additive) is also passed', async () => {
   const opts = {...DefaultProcessorOptions};
   opts.daysBeforeStale = 5; // stale after 5 days
-  opts.daysBeforeClose = 1; // closes after 6 days
+  opts.daysBeforeRotten = 1; // rotten after 6 days
   const lastUpdate = new Date();
   lastUpdate.setDate(lastUpdate.getDate() - 7);
   const TestIssueList: Issue[] = [
@@ -1471,8 +1676,9 @@ test('stale issues should be closed if the closed nubmer of days (additive) is a
   // process our fake issue list
   await processor.processIssues(1);
 
-  expect(processor.closedIssues).toHaveLength(1);
-  expect(processor.removedLabelIssues).toHaveLength(0);
+  expect(processor.closedIssues).toHaveLength(0);
+  expect(processor.rottenIssues).toHaveLength(1);
+  expect(processor.removedLabelIssues).toHaveLength(1); // the stale label should be removed on rotten label being added
   expect(processor.staleIssues).toHaveLength(0);
 });
 
@@ -1690,8 +1896,12 @@ test('send stale message on prs when stale-pr-message is not empty', async () =>
   );
 });
 
-test('git branch is deleted when option is enabled', async () => {
-  const opts = {...DefaultProcessorOptions, deleteBranch: true};
+test('git branch is deleted when option is enabled and days before rotten is set to -1', async () => {
+  const opts = {
+    ...DefaultProcessorOptions,
+    deleteBranch: true,
+    daysBeforeRotten: -1
+  };
   const isPullRequest = true;
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -1721,8 +1931,12 @@ test('git branch is deleted when option is enabled', async () => {
   expect(processor.deletedBranchIssues).toHaveLength(1);
 });
 
-test('git branch is not deleted when issue is not pull request', async () => {
-  const opts = {...DefaultProcessorOptions, deleteBranch: true};
+test('git branch is not deleted when issue is not pull request and days before rotten is set to -1', async () => {
+  const opts = {
+    ...DefaultProcessorOptions,
+    deleteBranch: true,
+    daysBeforeRotten: -1
+  };
   const isPullRequest = false;
   const TestIssueList: Issue[] = [
     generateIssue(
@@ -2516,13 +2730,14 @@ test('processing a locked issue with a close label will not remove the close lab
   expect(processor.removedLabelIssues).toHaveLength(0);
 });
 
-test('processing an issue stale since less than the daysBeforeStale with a stale label created after daysBeforeClose should close the issue', async () => {
-  expect.assertions(3);
+test('processing an issue stale since less than the daysBeforeStale with a stale label created after daysBeforeRotten should rotten the issue', async () => {
+  expect.assertions(4);
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     staleIssueLabel: 'stale-label',
     daysBeforeStale: 30,
     daysBeforeClose: 7,
+    daysBeforeRotten: 0,
     closeIssueMessage: 'close message',
     removeStaleWhenUpdated: false
   };
@@ -2554,9 +2769,10 @@ test('processing an issue stale since less than the daysBeforeStale with a stale
   // process our fake issue list
   await processor.processIssues(1);
 
-  expect(processor.removedLabelIssues).toHaveLength(0);
+  expect(processor.removedLabelIssues).toHaveLength(1); // The stale label should be removed on adding the rotten label
+  expect(processor.rottenIssues).toHaveLength(1); // Expected at 0 by the user
   expect(processor.deletedBranchIssues).toHaveLength(0);
-  expect(processor.closedIssues).toHaveLength(1); // Expected at 0 by the user
+  expect(processor.closedIssues).toHaveLength(0);
 });
 
 test('processing an issue stale since less than the daysBeforeStale without a stale label should close the issue', async () => {
@@ -2566,6 +2782,8 @@ test('processing an issue stale since less than the daysBeforeStale without a st
     staleIssueLabel: 'stale-label',
     daysBeforeStale: 30,
     daysBeforeClose: 7,
+    daysBeforeRotten: 0,
+
     closeIssueMessage: 'close message',
     removeStaleWhenUpdated: false
   };
@@ -2601,13 +2819,14 @@ test('processing an issue stale since less than the daysBeforeStale without a st
   expect(processor.closedIssues).toHaveLength(0);
 });
 
-test('processing a pull request to be stale with the "stalePrMessage" option set will send a PR comment', async () => {
+test('processing a pull request to be stale with the "stalePrMessage" option set will send a PR comment, given that days before rotten is set to -1', async () => {
   expect.assertions(3);
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     stalePrMessage: 'This PR is stale',
     daysBeforeStale: 10,
-    daysBeforePrStale: 1
+    daysBeforePrStale: 1,
+    daysBeforeRotten: -1
   };
   const issueDate = new Date();
   issueDate.setDate(issueDate.getDate() - 2);
@@ -2638,12 +2857,52 @@ test('processing a pull request to be stale with the "stalePrMessage" option set
   expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(1);
 });
 
-test('processing a pull request to be stale with the "stalePrMessage" option set to empty will not send a PR comment', async () => {
+test('processing a pull request to be stale with the "stalePrMessage" option set will send two PR comments, given that days before rotten is set to 0', async () => {
+  expect.assertions(3);
+  const opts: IIssuesProcessorOptions = {
+    ...DefaultProcessorOptions,
+    stalePrMessage: 'This PR is stale',
+    daysBeforeStale: 10,
+    daysBeforePrStale: 1,
+    daysBeforeRotten: 0
+  };
+  const issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A pull request with no label and a stale message',
+      issueDate.toDateString(),
+      issueDate.toDateString(),
+      false,
+      true
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    opts,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
+  expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(2);
+});
+
+test('processing a pull request to be stale with the "stalePrMessage" option set to empty will not send a PR comment, given that "rottenPRMessage" is also an empty string and days before rotten is not -1', async () => {
   expect.assertions(3);
   const opts: IIssuesProcessorOptions = {
     ...DefaultProcessorOptions,
     stalePrMessage: '',
+    rottenPrMessage: '',
     daysBeforeStale: 10,
+    daysBeforeRotten: 0,
     daysBeforePrStale: 1
   };
   const issueDate = new Date();
@@ -2675,6 +2934,45 @@ test('processing a pull request to be stale with the "stalePrMessage" option set
   expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(0);
 });
 
+test('processing a pull request to be stale with the "stalePrMessage" option set to empty will send a PR comment from "rottenPRMessage" given that it is also an empty string', async () => {
+  expect.assertions(3);
+  const opts: IIssuesProcessorOptions = {
+    ...DefaultProcessorOptions,
+    stalePrMessage: '',
+    daysBeforeStale: 10,
+    daysBeforeRotten: 0,
+
+    daysBeforePrStale: 1
+  };
+  const issueDate = new Date();
+  issueDate.setDate(issueDate.getDate() - 2);
+  const TestIssueList: Issue[] = [
+    generateIssue(
+      opts,
+      1,
+      'A pull request with no label and a stale message',
+      issueDate.toDateString(),
+      issueDate.toDateString(),
+      false,
+      true
+    )
+  ];
+  const processor = new IssuesProcessorMock(
+    opts,
+    alwaysFalseStateMock,
+    async p => (p === 1 ? TestIssueList : []),
+    async () => [],
+    async () => new Date().toDateString()
+  );
+
+  // process our fake issue list
+  await processor.processIssues(1);
+
+  expect(processor.staleIssues).toHaveLength(1);
+  expect(processor.closedIssues).toHaveLength(0);
+  expect(processor.statistics?.addedPullRequestsCommentsCount).toStrictEqual(1);
+});
+
 test('processing an issue with the "includeOnlyAssigned" option and nonempty assignee list will stale the issue', async () => {
   const issueDate = new Date();
   issueDate.setDate(issueDate.getDate() - 2);
diff --git a/__tests__/operations-per-run.spec.ts b/__tests__/operations-per-run.spec.ts
index 6be0a3632..7b038fe75 100644
--- a/__tests__/operations-per-run.spec.ts
+++ b/__tests__/operations-per-run.spec.ts
@@ -13,7 +13,7 @@ describe('operations-per-run option', (): void => {
     sut = new SUT();
   });
 
-  describe('when one issue should be stale within 10 days and updated 20 days ago', (): void => {
+  describe('when one issue should be stale within 10 days and updated 20 days ago and days before rotten is -1', (): void => {
     beforeEach((): void => {
       sut.staleIn(10).newIssue().updated(20);
     });
diff --git a/__tests__/state.spec.ts b/__tests__/state.spec.ts
index 8c59d8614..af5c9151c 100644
--- a/__tests__/state.spec.ts
+++ b/__tests__/state.spec.ts
@@ -202,7 +202,7 @@ describe('state', (): void => {
 
     await processor.processIssues(1);
     // make sure all issues are proceeded
-    expect(infoSpy.mock.calls[71][0]).toContain(
+    expect(infoSpy.mock.calls[77][0]).toContain(
       'No more issues found to process. Exiting...'
     );
 
diff --git a/action.yml b/action.yml
index d55f8547c..27b3a35aa 100644
--- a/action.yml
+++ b/action.yml
@@ -1,6 +1,6 @@
-name: 'Close Stale Issues'
+name: 'Close, Rotten and Stale Issues'
 description: 'Close issues and pull requests with no recent activity'
-author: 'GitHub'
+author: 'M Viswanath Sai'
 inputs:
   repo-token:
     description: 'Token for the repository. Can be passed in using `{{ secrets.GITHUB_TOKEN }}`.'
@@ -12,6 +12,12 @@ inputs:
   stale-pr-message:
     description: 'The message to post on the pull request when tagging it. If none provided, will not mark pull requests stale.'
     required: false
+  rotten-issue-message:
+    description: 'The message to post on the issue when tagging it. If none provided, will not mark issues rotten.'
+    required: false
+  rotten-pr-message:
+    description: 'The message to post on the pull request when tagging it. If none provided, will not mark pull requests rotten.'
+    required: false
   close-issue-message:
     description: 'The message to post on the issue when closing it. If none provided, will not comment when closing an issue.'
     required: false
@@ -21,17 +27,27 @@ inputs:
   days-before-stale:
     description: 'The number of days old an issue or a pull request can be before marking it stale. Set to -1 to never mark issues or pull requests as stale automatically.'
     required: false
-    default: '60'
+    default: '90'
   days-before-issue-stale:
     description: 'The number of days old an issue can be before marking it stale. Set to -1 to never mark issues as stale automatically. Override "days-before-stale" option regarding only the issues.'
     required: false
   days-before-pr-stale:
     description: 'The number of days old a pull request can be before marking it stale. Set to -1 to never mark pull requests as stale automatically. Override "days-before-stale" option regarding only the pull requests.'
     required: false
+  days-before-rotten:
+    description: 'The number of days old an issue or a pull request can be before marking it rotten. Set to -1 to never mark issues or pull requests as rotten automatically.'
+    required: false
+    default: '30'
+  days-before-issue-rotten:
+    description: 'The number of days old an issue can be before marking it rotten. Set to -1 to never mark issues as rotten automatically. Override "days-before-rotten" option regarding only the issues.'
+    required: false
+  days-before-pr-rotten:
+    description: 'The number of days old a pull request can be before marking it rotten. Set to -1 to never mark pull requests as rotten automatically. Override "days-before-rotten" option regarding only the pull requests.'
+    required: false
   days-before-close:
     description: 'The number of days to wait to close an issue or a pull request after it being marked stale. Set to -1 to never close stale issues or pull requests.'
     required: false
-    default: '7'
+    default: '30'
   days-before-issue-close:
     description: 'The number of days to wait to close an issue after it being marked stale. Set to -1 to never close stale issues. Override "days-before-close" option regarding only the issues.'
     required: false
@@ -42,6 +58,10 @@ inputs:
     description: 'The label to apply when an issue is stale.'
     required: false
     default: 'Stale'
+  rotten-issue-label:
+    description: 'The label to apply when an issue is rotten.'
+    required: false
+    default: 'Rotten'
   close-issue-label:
     description: 'The label to apply when an issue is closed.'
     required: false
@@ -57,6 +77,10 @@ inputs:
     description: 'The label to apply when a pull request is stale.'
     default: 'Stale'
     required: false
+  rotten-pr-label:
+    description: 'The label to apply when a pull request is rotten.'
+    default: 'Rotten'
+    required: false
   close-pr-label:
     description: 'The label to apply when a pull request is closed.'
     required: false
@@ -128,6 +152,18 @@ inputs:
     description: 'Remove stale labels from pull requests when they are updated or commented on. Override "remove-stale-when-updated" option regarding only the pull requests.'
     default: ''
     required: false
+  remove-rotten-when-updated:
+    description: 'Remove rotten labels from issues and pull requests when they are updated or commented on.'
+    default: 'true'
+    required: false
+  remove-issue-rotten-when-updated:
+    description: 'Remove rotten labels from issues when they are updated or commented on. Override "remove-rotten-when-updated" option regarding only the issues.'
+    default: ''
+    required: false
+  remove-pr-rotten-when-updated:
+    description: 'Remove rotten labels from pull requests when they are updated or commented on. Override "remove-rotten-when-updated" option regarding only the pull requests.'
+    default: ''
+    required: false
   debug-only:
     description: 'Run the processor in debug mode without actually performing any operations on live issues.'
     default: 'false'
@@ -188,6 +224,18 @@ inputs:
     description: 'A comma delimited list of labels to remove when an issue or pull request becomes unstale.'
     default: ''
     required: false
+  labels-to-add-when-unrotten:
+    description: 'A comma delimited list of labels to add when an issue or pull request becomes unrotten.'
+    default: ''
+    required: false
+  labels-to-remove-when-rotten:
+    description: 'A comma delimited list of labels to remove when an issue or pull request becomes rotten.'
+    default: ''
+    required: false
+  labels-to-remove-when-unrotten:
+    description: 'A comma delimited list of labels to remove when an issue or pull request becomes unrotten.'
+    default: ''
+    required: false
   ignore-updates:
     description: 'Any update (update/comment) can reset the stale idle time on the issues and pull requests.'
     default: 'false'
diff --git a/dist/index.js b/dist/index.js
index f2786a0f6..6ac1a940a 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -288,7 +288,9 @@ class Issue {
         this.milestone = issue.milestone;
         this.assignees = issue.assignees || [];
         this.isStale = (0, is_labeled_1.isLabeled)(this, this.staleLabel);
+        this.isRotten = (0, is_labeled_1.isLabeled)(this, this.rottenLabel);
         this.markedStaleThisRun = false;
+        this.markedRottenThisRun = false;
     }
     get isPullRequest() {
         return (0, is_pull_request_1.isPullRequest)(this);
@@ -296,6 +298,9 @@ class Issue {
     get staleLabel() {
         return this._getStaleLabel();
     }
+    get rottenLabel() {
+        return this._getRottenLabel();
+    }
     get hasAssignees() {
         return this.assignees.length > 0;
     }
@@ -304,6 +309,11 @@ class Issue {
             ? this._options.stalePrLabel
             : this._options.staleIssueLabel;
     }
+    _getRottenLabel() {
+        return this.isPullRequest
+            ? this._options.rottenPrLabel
+            : this._options.rottenIssueLabel;
+    }
 }
 exports.Issue = Issue;
 function mapLabels(labels) {
@@ -403,6 +413,7 @@ class IssuesProcessor {
     }
     constructor(options, state) {
         this.staleIssues = [];
+        this.rottenIssues = [];
         this.closedIssues = [];
         this.deletedBranchIssues = [];
         this.removedLabelIssues = [];
@@ -439,6 +450,9 @@ class IssuesProcessor {
             const labelsToRemoveWhenStale = (0, words_to_list_1.wordsToList)(this.options.labelsToRemoveWhenStale);
             const labelsToAddWhenUnstale = (0, words_to_list_1.wordsToList)(this.options.labelsToAddWhenUnstale);
             const labelsToRemoveWhenUnstale = (0, words_to_list_1.wordsToList)(this.options.labelsToRemoveWhenUnstale);
+            const labelsToRemoveWhenRotten = (0, words_to_list_1.wordsToList)(this.options.labelsToRemoveWhenRotten);
+            const labelsToAddWhenUnrotten = (0, words_to_list_1.wordsToList)(this.options.labelsToAddWhenUnrotten);
+            const labelsToRemoveWhenUnrotten = (0, words_to_list_1.wordsToList)(this.options.labelsToRemoveWhenUnrotten);
             for (const issue of issues.values()) {
                 // Stop the processing if no more operations remains
                 if (!this.operations.hasRemainingOperations()) {
@@ -450,7 +464,7 @@ class IssuesProcessor {
                     continue;
                 }
                 yield issueLogger.grouping(`$$type #${issue.number}`, () => __awaiter(this, void 0, void 0, function* () {
-                    yield this.processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale);
+                    yield this.processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten);
                 }));
                 this.state.addIssueToProcessed(issue);
             }
@@ -465,7 +479,7 @@ class IssuesProcessor {
             return this.processIssues(page + 1);
         });
     }
-    processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale) {
+    processIssue(issue, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten) {
         var _a;
         return __awaiter(this, void 0, void 0, function* () {
             (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementProcessedItemsCount(issue);
@@ -475,12 +489,21 @@ class IssuesProcessor {
             const staleMessage = issue.isPullRequest
                 ? this.options.stalePrMessage
                 : this.options.staleIssueMessage;
+            const rottenMessage = issue.isPullRequest
+                ? this.options.rottenPrMessage
+                : this.options.rottenIssueMessage;
             const closeMessage = issue.isPullRequest
                 ? this.options.closePrMessage
                 : this.options.closeIssueMessage;
+            const skipRottenMessage = issue.isPullRequest
+                ? this.options.rottenPrMessage.length === 0
+                : this.options.rottenIssueMessage.length === 0;
             const staleLabel = issue.isPullRequest
                 ? this.options.stalePrLabel
                 : this.options.staleIssueLabel;
+            const rottenLabel = issue.isPullRequest
+                ? this.options.rottenPrLabel
+                : this.options.rottenIssueLabel;
             const closeLabel = issue.isPullRequest
                 ? this.options.closePrLabel
                 : this.options.closeIssueLabel;
@@ -546,11 +569,18 @@ class IssuesProcessor {
                     return; // Don't process issues which were created before the start date
                 }
             }
+            // Check if the issue is stale, if not, check if it is rotten and then log the findings.
             if (issue.isStale) {
                 issueLogger.info(`This $$type includes a stale label`);
             }
             else {
                 issueLogger.info(`This $$type does not include a stale label`);
+                if (issue.isRotten) {
+                    issueLogger.info(`This $$type includes a rotten label`);
+                }
+                else {
+                    issueLogger.info(`This $$type does not include a rotten label`);
+                }
             }
             const exemptLabels = (0, words_to_list_1.wordsToList)(issue.isPullRequest
                 ? this.options.exemptPrLabels
@@ -601,51 +631,57 @@ class IssuesProcessor {
                 IssuesProcessor._endIssueProcessing(issue);
                 return; // Don't process draft PR
             }
+            // Here we are looking into if the issue is stale or not, and then adding the label. This same code will also be used for the rotten label.
             // Determine if this issue needs to be marked stale first
             if (!issue.isStale) {
                 issueLogger.info(`This $$type is not stale`);
-                const shouldIgnoreUpdates = new ignore_updates_1.IgnoreUpdates(this.options, issue).shouldIgnoreUpdates();
-                // Should this issue be marked as stale?
-                let shouldBeStale;
-                // Ignore the last update and only use the creation date
-                if (shouldIgnoreUpdates) {
-                    shouldBeStale = !IssuesProcessor._updatedSince(issue.created_at, daysBeforeStale);
+                if (issue.isRotten) {
+                    yield this._processRottenIssue(issue, rottenLabel, rottenMessage, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten, closeMessage, closeLabel);
                 }
-                // Use the last update to check if we need to stale
                 else {
-                    shouldBeStale = !IssuesProcessor._updatedSince(issue.updated_at, daysBeforeStale);
-                }
-                if (shouldBeStale) {
+                    const shouldIgnoreUpdates = new ignore_updates_1.IgnoreUpdates(this.options, issue).shouldIgnoreUpdates();
+                    // Should this issue be marked as stale?
+                    let shouldBeStale;
+                    // Ignore the last update and only use the creation date
                     if (shouldIgnoreUpdates) {
-                        issueLogger.info(`This $$type should be stale based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
-                    }
-                    else {
-                        issueLogger.info(`This $$type should be stale based on the last update date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
-                    }
-                    if (shouldMarkAsStale) {
-                        issueLogger.info(`This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`);
-                        yield this._markStale(issue, staleMessage, staleLabel, skipMessage);
-                        issue.isStale = true; // This issue is now considered stale
-                        issue.markedStaleThisRun = true;
-                        issueLogger.info(`This $$type is now stale`);
+                        shouldBeStale = !IssuesProcessor._updatedSince(issue.created_at, daysBeforeStale);
                     }
+                    // Use the last update to check if we need to stale
                     else {
-                        issueLogger.info(`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`);
+                        shouldBeStale = !IssuesProcessor._updatedSince(issue.updated_at, daysBeforeStale);
                     }
-                }
-                else {
-                    if (shouldIgnoreUpdates) {
-                        issueLogger.info(`This $$type should not be stale based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
+                    if (shouldBeStale) {
+                        if (shouldIgnoreUpdates) {
+                            issueLogger.info(`This $$type should be stale based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
+                        }
+                        else {
+                            issueLogger.info(`This $$type should be stale based on the last update date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
+                        }
+                        if (shouldMarkAsStale) {
+                            issueLogger.info(`This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`);
+                            yield this._markStale(issue, staleMessage, staleLabel, skipMessage);
+                            issue.isStale = true; // This issue is now considered stale
+                            issue.markedStaleThisRun = true;
+                            issueLogger.info(`This $$type is now stale`);
+                        }
+                        else {
+                            issueLogger.info(`This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeStale)})`);
+                        }
                     }
                     else {
-                        issueLogger.info(`This $$type should not be stale based on the last update date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
+                        if (shouldIgnoreUpdates) {
+                            issueLogger.info(`This $$type should not be stale based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
+                        }
+                        else {
+                            issueLogger.info(`This $$type should not be stale based on the last update date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
+                        }
                     }
                 }
             }
             // Process the issue if it was marked stale
             if (issue.isStale) {
                 issueLogger.info(`This $$type is already stale`);
-                yield this._processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, closeMessage, closeLabel);
+                yield this._processStaleIssue(issue, staleLabel, staleMessage, rottenLabel, rottenMessage, closeLabel, closeMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten, skipRottenMessage);
             }
             IssuesProcessor._endIssueProcessing(issue);
         });
@@ -752,17 +788,23 @@ class IssuesProcessor {
         });
     }
     // handle all of the stale issue logic when we find a stale issue
-    _processStaleIssue(issue, staleLabel, staleMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, closeMessage, closeLabel) {
+    // This whole thing needs to be altered, to be calculated based on the days to rotten, rather than days to close or whatever
+    _processStaleIssue(issue, staleLabel, staleMessage, rottenLabel, rottenMessage, closeLabel, closeMessage, labelsToAddWhenUnstale, labelsToRemoveWhenUnstale, labelsToRemoveWhenStale, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten, skipMessage) {
         return __awaiter(this, void 0, void 0, function* () {
             const issueLogger = new issue_logger_1.IssueLogger(issue);
+            let issueHasClosed = false;
+            // We can get the label creation date from the getLableCreationDate function
             const markedStaleOn = (yield this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
             issueLogger.info(`$$type marked stale on: ${logger_service_1.LoggerService.cyan(markedStaleOn)}`);
             const issueHasCommentsSinceStale = yield this._hasCommentsSince(issue, markedStaleOn, staleMessage);
             issueLogger.info(`$$type has been commented on: ${logger_service_1.LoggerService.cyan(issueHasCommentsSinceStale)}`);
+            const daysBeforeRotten = issue.isPullRequest
+                ? this._getDaysBeforePrRotten()
+                : this._getDaysBeforeIssueRotten();
             const daysBeforeClose = issue.isPullRequest
                 ? this._getDaysBeforePrClose()
                 : this._getDaysBeforeIssueClose();
-            issueLogger.info(`Days before $$type close: ${logger_service_1.LoggerService.cyan(daysBeforeClose)}`);
+            issueLogger.info(`Days before $$type rotten: ${logger_service_1.LoggerService.cyan(daysBeforeRotten)}`);
             const shouldRemoveStaleWhenUpdated = this._shouldRemoveStaleWhenUpdated(issue);
             issueLogger.info(`The option ${issueLogger.createOptionLink(this._getRemoveStaleWhenUpdatedUsedOptionName(issue))} is: ${logger_service_1.LoggerService.cyan(shouldRemoveStaleWhenUpdated)}`);
             if (shouldRemoveStaleWhenUpdated) {
@@ -771,6 +813,7 @@ class IssuesProcessor {
             else {
                 issueLogger.info(`The stale label should be removed if all conditions met`);
             }
+            // we will need to use a variation of this for the rotten state
             if (issue.markedStaleThisRun) {
                 issueLogger.info(`marked stale this run, so don't check for updates`);
                 yield this._removeLabelsOnStatusTransition(issue, labelsToRemoveWhenStale, option_1.Option.LabelsToRemoveWhenStale);
@@ -791,13 +834,124 @@ class IssuesProcessor {
                 issueLogger.info(`Skipping the process since the $$type is now un-stale`);
                 return; // Nothing to do because it is no longer stale
             }
+            if (daysBeforeRotten < 0) {
+                if (daysBeforeClose < 0) {
+                    issueLogger.info(`Stale $$type cannot be rotten or closed because days before rotten: ${daysBeforeRotten}, and days before close: ${daysBeforeClose}`);
+                    return;
+                }
+                else {
+                    issueLogger.info(`Closing issue without rottening it because days before $$type rotten: ${logger_service_1.LoggerService.cyan(daysBeforeRotten)}`);
+                    const issueHasUpdateInCloseWindow = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose);
+                    issueLogger.info(`$$type has been updated in the last ${daysBeforeClose} days: ${logger_service_1.LoggerService.cyan(issueHasUpdateInCloseWindow)}`);
+                    if (!issueHasUpdateInCloseWindow && !issueHasCommentsSinceStale) {
+                        issueLogger.info(`Closing $$type because it was last updated on: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`);
+                        yield this._closeIssue(issue, closeMessage, closeLabel);
+                        issueHasClosed = true;
+                        if (this.options.deleteBranch && issue.pull_request) {
+                            issueLogger.info(`Deleting the branch since the option ${issueLogger.createOptionLink(option_1.Option.DeleteBranch)} is enabled`);
+                            yield this._deleteBranch(issue);
+                            this.deletedBranchIssues.push(issue);
+                        }
+                    }
+                    else {
+                        issueLogger.info(`Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`);
+                    }
+                }
+            }
+            // TODO: make a function for shouldMarkWhenRotten
+            const shouldMarkAsRotten = (0, should_mark_when_stale_1.shouldMarkWhenStale)(daysBeforeRotten);
+            if (issueHasClosed) {
+                issueLogger.info(`Issue $$type has been closed, no need to process it further.`);
+                return;
+            }
+            if (!issue.isRotten) {
+                issueLogger.info(`This $$type is not rotten`);
+                const shouldIgnoreUpdates = new ignore_updates_1.IgnoreUpdates(this.options, issue).shouldIgnoreUpdates();
+                const shouldBeRotten = !IssuesProcessor._updatedSince(issue.updated_at, daysBeforeRotten);
+                if (shouldBeRotten) {
+                    if (shouldIgnoreUpdates) {
+                        issueLogger.info(`This $$type should be rotten based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
+                    }
+                    else {
+                        issueLogger.info(`This $$type should be rotten based on the last update date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
+                    }
+                    if (shouldMarkAsRotten) {
+                        issueLogger.info(`This $$type should be marked as rotten based on the option ${issueLogger.createOptionLink(this._getDaysBeforeRottenUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeRotten)})`);
+                        // remove the stale label before marking the issue as rotten
+                        yield this._removeStaleLabel(issue, staleLabel);
+                        yield this._markRotten(issue, rottenMessage, rottenLabel, skipMessage);
+                        issue.isRotten = true; // This issue is now considered rotten
+                        issue.markedRottenThisRun = true;
+                        issueLogger.info(`This $$type is now rotten`);
+                    }
+                    else {
+                        issueLogger.info(`This $$type should not be marked as rotten based on the option ${issueLogger.createOptionLink(this._getDaysBeforeStaleUsedOptionName(issue))} (${logger_service_1.LoggerService.cyan(daysBeforeRotten)})`);
+                    }
+                }
+                else {
+                    if (shouldIgnoreUpdates) {
+                        issueLogger.info(`This $$type is not old enough to be rotten based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.created_at))} (${logger_service_1.LoggerService.cyan(issue.created_at)})`);
+                    }
+                    else {
+                        issueLogger.info(`This $$type is not old enough to be rotten based on the creation date the ${(0, get_humanized_date_1.getHumanizedDate)(new Date(issue.updated_at))} (${logger_service_1.LoggerService.cyan(issue.updated_at)})`);
+                    }
+                }
+            }
+            if (issue.isRotten) {
+                issueLogger.info(`This $$type is already rotten`);
+                // process the rotten issues
+                this._processRottenIssue(issue, rottenLabel, rottenMessage, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten, closeMessage, closeLabel);
+            }
+        });
+    }
+    _processRottenIssue(issue, rottenLabel, rottenMessage, labelsToAddWhenUnrotten, labelsToRemoveWhenUnrotten, labelsToRemoveWhenRotten, closeMessage, closeLabel) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const issueLogger = new issue_logger_1.IssueLogger(issue);
+            // We can get the label creation date from the getLableCreationDate function
+            const markedRottenOn = (yield this.getLabelCreationDate(issue, rottenLabel)) || issue.updated_at;
+            issueLogger.info(`$$type marked rotten on: ${logger_service_1.LoggerService.cyan(markedRottenOn)}`);
+            const issueHasCommentsSinceRotten = yield this._hasCommentsSince(issue, markedRottenOn, rottenMessage);
+            issueLogger.info(`$$type has been commented on: ${logger_service_1.LoggerService.cyan(issueHasCommentsSinceRotten)}`);
+            const daysBeforeClose = issue.isPullRequest
+                ? this._getDaysBeforePrClose()
+                : this._getDaysBeforeIssueClose();
+            issueLogger.info(`Days before $$type close: ${logger_service_1.LoggerService.cyan(daysBeforeClose)}`);
+            const shouldRemoveRottenWhenUpdated = this._shouldRemoveRottenWhenUpdated(issue);
+            issueLogger.info(`The option ${issueLogger.createOptionLink(this._getRemoveRottenWhenUpdatedUsedOptionName(issue))} is: ${logger_service_1.LoggerService.cyan(shouldRemoveRottenWhenUpdated)}`);
+            if (shouldRemoveRottenWhenUpdated) {
+                issueLogger.info(`The rotten label should not be removed`);
+            }
+            else {
+                issueLogger.info(`The rotten label should be removed if all conditions met`);
+            }
+            if (issue.markedRottenThisRun) {
+                issueLogger.info(`marked rotten this run, so don't check for updates`);
+                yield this._removeLabelsOnStatusTransition(issue, labelsToRemoveWhenRotten, option_1.Option.LabelsToRemoveWhenRotten);
+            }
+            // The issue.updated_at and markedRottenOn are not always exactly in sync (they can be off by a second or 2)
+            // isDateMoreRecentThan makes sure they are not the same date within a certain tolerance (15 seconds in this case)
+            const issueHasUpdateSinceRotten = (0, is_date_more_recent_than_1.isDateMoreRecentThan)(new Date(issue.updated_at), new Date(markedRottenOn), 15);
+            issueLogger.info(`$$type has been updated since it was marked rotten: ${logger_service_1.LoggerService.cyan(issueHasUpdateSinceRotten)}`);
+            // Should we un-rotten this issue?
+            if (shouldRemoveRottenWhenUpdated &&
+                (issueHasUpdateSinceRotten || issueHasCommentsSinceRotten) &&
+                !issue.markedRottenThisRun) {
+                issueLogger.info(`Remove the rotten label since the $$type has been updated and the workflow should remove the stale label when updated`);
+                yield this._removeRottenLabel(issue, rottenLabel);
+                // Are there labels to remove or add when an issue is no longer rotten?
+                // This logic takes care of removing labels when unrotten
+                yield this._removeLabelsOnStatusTransition(issue, labelsToRemoveWhenUnrotten, option_1.Option.LabelsToRemoveWhenUnrotten);
+                yield this._addLabelsWhenUnrotten(issue, labelsToAddWhenUnrotten);
+                issueLogger.info(`Skipping the process since the $$type is now un-rotten`);
+                return; // Nothing to do because it is no longer rotten
+            }
             // Now start closing logic
             if (daysBeforeClose < 0) {
-                return; // Nothing to do because we aren't closing stale issues
+                return; // Nothing to do because we aren't closing rotten issues
             }
             const issueHasUpdateInCloseWindow = IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose);
             issueLogger.info(`$$type has been updated in the last ${daysBeforeClose} days: ${logger_service_1.LoggerService.cyan(issueHasUpdateInCloseWindow)}`);
-            if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) {
+            if (!issueHasCommentsSinceRotten && !issueHasUpdateInCloseWindow) {
                 issueLogger.info(`Closing $$type because it was last updated on: ${logger_service_1.LoggerService.cyan(issue.updated_at)}`);
                 yield this._closeIssue(issue, closeMessage, closeLabel);
                 if (this.options.deleteBranch && issue.pull_request) {
@@ -807,7 +961,7 @@ class IssuesProcessor {
                 }
             }
             else {
-                issueLogger.info(`Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`);
+                issueLogger.info(`Rotten $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceRotten}, hasUpdate? ${issueHasUpdateInCloseWindow})`);
             }
         });
     }
@@ -877,12 +1031,57 @@ class IssuesProcessor {
             }
         });
     }
+    _markRotten(issue, rottenMessage, rottenLabel, skipMessage) {
+        var _a, _b, _c;
+        return __awaiter(this, void 0, void 0, function* () {
+            const issueLogger = new issue_logger_1.IssueLogger(issue);
+            issueLogger.info(`Marking this $$type as rotten`);
+            this.rottenIssues.push(issue);
+            // if the issue is being marked rotten, the updated date should be changed to right now
+            // so that close calculations work correctly
+            const newUpdatedAtDate = new Date();
+            issue.updated_at = newUpdatedAtDate.toString();
+            if (!skipMessage) {
+                try {
+                    this._consumeIssueOperation(issue);
+                    (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsComment(issue);
+                    if (!this.options.debugOnly) {
+                        yield this.client.rest.issues.createComment({
+                            owner: github_1.context.repo.owner,
+                            repo: github_1.context.repo.repo,
+                            issue_number: issue.number,
+                            body: rottenMessage
+                        });
+                    }
+                }
+                catch (error) {
+                    issueLogger.error(`Error when creating a comment: ${error.message}`);
+                }
+            }
+            try {
+                this._consumeIssueOperation(issue);
+                (_b = this.statistics) === null || _b === void 0 ? void 0 : _b.incrementAddedItemsLabel(issue);
+                (_c = this.statistics) === null || _c === void 0 ? void 0 : _c.incrementStaleItemsCount(issue);
+                if (!this.options.debugOnly) {
+                    yield this.client.rest.issues.addLabels({
+                        owner: github_1.context.repo.owner,
+                        repo: github_1.context.repo.repo,
+                        issue_number: issue.number,
+                        labels: [rottenLabel]
+                    });
+                }
+            }
+            catch (error) {
+                issueLogger.error(`Error when adding a label: ${error.message}`);
+            }
+        });
+    }
     // Close an issue based on staleness
     _closeIssue(issue, closeMessage, closeLabel) {
         var _a, _b, _c;
         return __awaiter(this, void 0, void 0, function* () {
             const issueLogger = new issue_logger_1.IssueLogger(issue);
-            issueLogger.info(`Closing $$type for being stale`);
+            issueLogger.info(`Closing $$type for being stale/rotten`);
             this.closedIssues.push(issue);
             if (closeMessage) {
                 try {
@@ -1012,6 +1211,16 @@ class IssuesProcessor {
             ? this.options.daysBeforeStale
             : this.options.daysBeforePrStale;
     }
+    _getDaysBeforeIssueRotten() {
+        return isNaN(this.options.daysBeforeIssueRotten)
+            ? this.options.daysBeforeRotten
+            : this.options.daysBeforeIssueRotten;
+    }
+    _getDaysBeforePrRotten() {
+        return isNaN(this.options.daysBeforePrRotten)
+            ? this.options.daysBeforeRotten
+            : this.options.daysBeforePrRotten;
+    }
     _getDaysBeforeIssueClose() {
         return isNaN(this.options.daysBeforeIssueClose)
             ? this.options.daysBeforeClose
@@ -1063,6 +1272,18 @@ class IssuesProcessor {
         }
         return this.options.removeStaleWhenUpdated;
     }
+    _shouldRemoveRottenWhenUpdated(issue) {
+        if (issue.isPullRequest) {
+            if ((0, is_boolean_1.isBoolean)(this.options.removePrRottenWhenUpdated)) {
+                return this.options.removePrRottenWhenUpdated;
+            }
+            return this.options.removeRottenWhenUpdated;
+        }
+        if ((0, is_boolean_1.isBoolean)(this.options.removeIssueRottenWhenUpdated)) {
+            return this.options.removeIssueRottenWhenUpdated;
+        }
+        return this.options.removeRottenWhenUpdated;
+    }
     _removeLabelsOnStatusTransition(issue, removeLabels, staleStatus) {
         return __awaiter(this, void 0, void 0, function* () {
             if (!removeLabels.length) {
@@ -1101,6 +1322,33 @@ class IssuesProcessor {
             }
         });
     }
+    _addLabelsWhenUnrotten(issue, labelsToAdd) {
+        var _a;
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!labelsToAdd.length) {
+                return;
+            }
+            const issueLogger = new issue_logger_1.IssueLogger(issue);
+            issueLogger.info(`Adding all the labels specified via the ${this._logger.createOptionLink(option_1.Option.LabelsToAddWhenUnrotten)} option.`);
+            // TODO: this might need to be changed to a set to avoiod repetition
+            this.addedLabelIssues.push(issue);
+            try {
+                this._consumeIssueOperation(issue);
+                (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementAddedItemsLabel(issue);
+                if (!this.options.debugOnly) {
+                    yield this.client.rest.issues.addLabels({
+                        owner: github_1.context.repo.owner,
+                        repo: github_1.context.repo.repo,
+                        issue_number: issue.number,
+                        labels: labelsToAdd
+                    });
+                }
+            }
+            catch (error) {
+                this._logger.error(`Error when adding labels after updated from rotten: ${error.message}`);
+            }
+        });
+    }
     _removeStaleLabel(issue, staleLabel) {
         var _a;
         return __awaiter(this, void 0, void 0, function* () {
@@ -1110,6 +1358,15 @@ class IssuesProcessor {
             (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementUndoStaleItemsCount(issue);
         });
     }
+    _removeRottenLabel(issue, rottenLabel) {
+        var _a;
+        return __awaiter(this, void 0, void 0, function* () {
+            const issueLogger = new issue_logger_1.IssueLogger(issue);
+            issueLogger.info(`The $$type is no longer rotten. Removing the rotten label...`);
+            yield this._removeLabel(issue, rottenLabel);
+            (_a = this.statistics) === null || _a === void 0 ? void 0 : _a.incrementUndoRottenItemsCount(issue);
+        });
+    }
     _removeCloseLabel(issue, closeLabel) {
         var _a;
         return __awaiter(this, void 0, void 0, function* () {
@@ -1150,6 +1407,21 @@ class IssuesProcessor {
             ? option_1.Option.DaysBeforeStale
             : option_1.Option.DaysBeforePrStale;
     }
+    _getDaysBeforeRottenUsedOptionName(issue) {
+        return issue.isPullRequest
+            ? this._getDaysBeforePrRottenUsedOptionName()
+            : this._getDaysBeforeIssueRottenUsedOptionName();
+    }
+    _getDaysBeforeIssueRottenUsedOptionName() {
+        return isNaN(this.options.daysBeforeIssueRotten)
+            ? option_1.Option.DaysBeforeRotten
+            : option_1.Option.DaysBeforeIssueRotten;
+    }
+    _getDaysBeforePrRottenUsedOptionName() {
+        return isNaN(this.options.daysBeforePrRotten)
+            ? option_1.Option.DaysBeforeRotten
+            : option_1.Option.DaysBeforePrRotten;
+    }
     _getRemoveStaleWhenUpdatedUsedOptionName(issue) {
         if (issue.isPullRequest) {
             if ((0, is_boolean_1.isBoolean)(this.options.removePrStaleWhenUpdated)) {
@@ -1162,6 +1434,18 @@ class IssuesProcessor {
         }
         return option_1.Option.RemoveStaleWhenUpdated;
     }
+    _getRemoveRottenWhenUpdatedUsedOptionName(issue) {
+        if (issue.isPullRequest) {
+            if ((0, is_boolean_1.isBoolean)(this.options.removePrRottenWhenUpdated)) {
+                return option_1.Option.RemovePrRottenWhenUpdated;
+            }
+            return option_1.Option.RemoveRottenWhenUpdated;
+        }
+        if ((0, is_boolean_1.isBoolean)(this.options.removeIssueRottenWhenUpdated)) {
+            return option_1.Option.RemoveIssueRottenWhenUpdated;
+        }
+        return option_1.Option.RemoveRottenWhenUpdated;
+    }
 }
 exports.IssuesProcessor = IssuesProcessor;
 
@@ -1815,6 +2099,10 @@ class Statistics {
         this.stalePullRequestsCount = 0;
         this.undoStaleIssuesCount = 0;
         this.undoStalePullRequestsCount = 0;
+        this.rottenIssuesCount = 0;
+        this.rottenPullRequestsCount = 0;
+        this.undoRottenIssuesCount = 0;
+        this.undoRottenPullRequestsCount = 0;
         this.operationsCount = 0;
         this.closedIssuesCount = 0;
         this.closedPullRequestsCount = 0;
@@ -1850,6 +2138,12 @@ class Statistics {
         }
         return this._incrementUndoStaleIssuesCount(increment);
     }
+    incrementUndoRottenItemsCount(issue, increment = 1) {
+        if (issue.isPullRequest) {
+            return this._incrementUndoRottenPullRequestsCount(increment);
+        }
+        return this._incrementUndoRottenIssuesCount(increment);
+    }
     setOperationsCount(operationsCount) {
         this.operationsCount = operationsCount;
         return this;
@@ -1942,6 +2236,14 @@ class Statistics {
         this.undoStaleIssuesCount += increment;
         return this;
     }
+    _incrementUndoRottenPullRequestsCount(increment = 1) {
+        this.undoRottenPullRequestsCount += increment;
+        return this;
+    }
+    _incrementUndoRottenIssuesCount(increment = 1) {
+        this.undoRottenIssuesCount += increment;
+        return this;
+    }
     _incrementUndoStalePullRequestsCount(increment = 1) {
         this.undoStalePullRequestsCount += increment;
         return this;
@@ -2175,18 +2477,25 @@ var Option;
     Option["RepoToken"] = "repo-token";
     Option["StaleIssueMessage"] = "stale-issue-message";
     Option["StalePrMessage"] = "stale-pr-message";
+    Option["RottenIssueMessage"] = "rotten-issue-message";
+    Option["RottenPrMessage"] = "rotten-pr-message";
     Option["CloseIssueMessage"] = "close-issue-message";
     Option["ClosePrMessage"] = "close-pr-message";
     Option["DaysBeforeStale"] = "days-before-stale";
     Option["DaysBeforeIssueStale"] = "days-before-issue-stale";
     Option["DaysBeforePrStale"] = "days-before-pr-stale";
+    Option["DaysBeforeRotten"] = "days-before-rotten";
+    Option["DaysBeforeIssueRotten"] = "days-before-issue-rotten";
+    Option["DaysBeforePrRotten"] = "days-before-pr-rotten";
     Option["DaysBeforeClose"] = "days-before-close";
     Option["DaysBeforeIssueClose"] = "days-before-issue-close";
     Option["DaysBeforePrClose"] = "days-before-pr-close";
     Option["StaleIssueLabel"] = "stale-issue-label";
+    Option["RottenIssueLabel"] = "rotten-issue-label";
     Option["CloseIssueLabel"] = "close-issue-label";
     Option["ExemptIssueLabels"] = "exempt-issue-labels";
     Option["StalePrLabel"] = "stale-pr-label";
+    Option["RottenPrLabel"] = "rotten-pr-label";
     Option["ClosePrLabel"] = "close-pr-label";
     Option["ExemptPrLabels"] = "exempt-pr-labels";
     Option["OnlyLabels"] = "only-labels";
@@ -2197,6 +2506,9 @@ var Option;
     Option["RemoveStaleWhenUpdated"] = "remove-stale-when-updated";
     Option["RemoveIssueStaleWhenUpdated"] = "remove-issue-stale-when-updated";
     Option["RemovePrStaleWhenUpdated"] = "remove-pr-stale-when-updated";
+    Option["RemoveRottenWhenUpdated"] = "remove-rotten-when-updated";
+    Option["RemoveIssueRottenWhenUpdated"] = "remove-issue-rotten-when-updated";
+    Option["RemovePrRottenWhenUpdated"] = "remove-pr-rotten-when-updated";
     Option["DebugOnly"] = "debug-only";
     Option["Ascending"] = "ascending";
     Option["DeleteBranch"] = "delete-branch";
@@ -2217,6 +2529,9 @@ var Option;
     Option["LabelsToRemoveWhenStale"] = "labels-to-remove-when-stale";
     Option["LabelsToRemoveWhenUnstale"] = "labels-to-remove-when-unstale";
     Option["LabelsToAddWhenUnstale"] = "labels-to-add-when-unstale";
+    Option["LabelsToRemoveWhenRotten"] = "labels-to-remove-when-rotten";
+    Option["LabelsToRemoveWhenUnrotten"] = "labels-to-remove-when-unrotten";
+    Option["LabelsToAddWhenUnrotten"] = "labels-to-add-when-unrotten";
     Option["IgnoreUpdates"] = "ignore-updates";
     Option["IgnoreIssueUpdates"] = "ignore-issue-updates";
     Option["IgnorePrUpdates"] = "ignore-pr-updates";
@@ -2503,7 +2818,7 @@ function _run() {
                 core.info(`Github API rate remaining: ${rateLimitAtEnd.remaining}; reset at: ${rateLimitAtEnd.reset}`);
             }
             yield state.persist();
-            yield processOutput(issueProcessor.staleIssues, issueProcessor.closedIssues);
+            yield processOutput(issueProcessor.staleIssues, issueProcessor.rottenIssues, issueProcessor.closedIssues);
         }
         catch (error) {
             core.error(error);
@@ -2516,18 +2831,25 @@ function _getAndValidateArgs() {
         repoToken: core.getInput('repo-token'),
         staleIssueMessage: core.getInput('stale-issue-message'),
         stalePrMessage: core.getInput('stale-pr-message'),
+        rottenIssueMessage: core.getInput('rotten-issue-message'),
+        rottenPrMessage: core.getInput('rotten-pr-message'),
         closeIssueMessage: core.getInput('close-issue-message'),
         closePrMessage: core.getInput('close-pr-message'),
         daysBeforeStale: parseFloat(core.getInput('days-before-stale', { required: true })),
+        daysBeforeRotten: parseFloat(core.getInput('days-before-rotten', { required: true })),
         daysBeforeIssueStale: parseFloat(core.getInput('days-before-issue-stale')),
         daysBeforePrStale: parseFloat(core.getInput('days-before-pr-stale')),
+        daysBeforeIssueRotten: parseFloat(core.getInput('days-before-issue-rotten')),
+        daysBeforePrRotten: parseFloat(core.getInput('days-before-pr-rotten')),
         daysBeforeClose: parseInt(core.getInput('days-before-close', { required: true })),
         daysBeforeIssueClose: parseInt(core.getInput('days-before-issue-close')),
         daysBeforePrClose: parseInt(core.getInput('days-before-pr-close')),
         staleIssueLabel: core.getInput('stale-issue-label', { required: true }),
+        rottenIssueLabel: core.getInput('rotten-issue-label', { required: true }),
         closeIssueLabel: core.getInput('close-issue-label'),
         exemptIssueLabels: core.getInput('exempt-issue-labels'),
         stalePrLabel: core.getInput('stale-pr-label', { required: true }),
+        rottenPrLabel: core.getInput('rotten-pr-label', { required: true }),
         closePrLabel: core.getInput('close-pr-label'),
         exemptPrLabels: core.getInput('exempt-pr-labels'),
         onlyLabels: core.getInput('only-labels'),
@@ -2540,6 +2862,9 @@ function _getAndValidateArgs() {
         removeStaleWhenUpdated: !(core.getInput('remove-stale-when-updated') === 'false'),
         removeIssueStaleWhenUpdated: _toOptionalBoolean('remove-issue-stale-when-updated'),
         removePrStaleWhenUpdated: _toOptionalBoolean('remove-pr-stale-when-updated'),
+        removeRottenWhenUpdated: !(core.getInput('remove-rotten-when-updated') === 'false'),
+        removeIssueRottenWhenUpdated: _toOptionalBoolean('remove-issue-rotten-when-updated'),
+        removePrRottenWhenUpdated: _toOptionalBoolean('remove-pr-rotten-when-updated'),
         debugOnly: core.getInput('debug-only') === 'true',
         ascending: core.getInput('ascending') === 'true',
         deleteBranch: core.getInput('delete-branch') === 'true',
@@ -2562,6 +2887,9 @@ function _getAndValidateArgs() {
         labelsToRemoveWhenStale: core.getInput('labels-to-remove-when-stale'),
         labelsToRemoveWhenUnstale: core.getInput('labels-to-remove-when-unstale'),
         labelsToAddWhenUnstale: core.getInput('labels-to-add-when-unstale'),
+        labelsToRemoveWhenRotten: core.getInput('labels-to-remove-when-rotten'),
+        labelsToRemoveWhenUnrotten: core.getInput('labels-to-remove-when-unrotten'),
+        labelsToAddWhenUnrotten: core.getInput('labels-to-add-when-unrotten'),
         ignoreUpdates: core.getInput('ignore-updates') === 'true',
         ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'),
         ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
@@ -2576,6 +2904,13 @@ function _getAndValidateArgs() {
             throw new Error(errorMessage);
         }
     }
+    for (const numberInput of ['days-before-rotten']) {
+        if (isNaN(parseFloat(core.getInput(numberInput)))) {
+            const errorMessage = `Option "${numberInput}" did not parse to a valid float`;
+            core.setFailed(errorMessage);
+            throw new Error(errorMessage);
+        }
+    }
     for (const numberInput of ['days-before-close', 'operations-per-run']) {
         if (isNaN(parseInt(core.getInput(numberInput)))) {
             const errorMessage = `Option "${numberInput}" did not parse to a valid integer`;
@@ -2601,9 +2936,10 @@ function _getAndValidateArgs() {
     }
     return args;
 }
-function processOutput(staledIssues, closedIssues) {
+function processOutput(staledIssues, rottenIssues, closedIssues) {
     return __awaiter(this, void 0, void 0, function* () {
         core.setOutput('staled-issues-prs', JSON.stringify(staledIssues));
+        core.setOutput('rotten-issues-prs', JSON.stringify(rottenIssues));
         core.setOutput('closed-issues-prs', JSON.stringify(closedIssues));
     });
 }
diff --git a/src/classes/issue.spec.ts b/src/classes/issue.spec.ts
index a2c82e268..2b2af9e93 100644
--- a/src/classes/issue.spec.ts
+++ b/src/classes/issue.spec.ts
@@ -20,9 +20,12 @@ describe('Issue', (): void => {
       daysBeforeClose: 0,
       daysBeforeIssueClose: 0,
       daysBeforeIssueStale: 0,
+      daysBeforeIssueRotten: 0,
       daysBeforePrClose: 0,
       daysBeforePrStale: 0,
+      daysBeforePrRotten: 0,
       daysBeforeStale: 0,
+      daysBeforeRotten: 0,
       debugOnly: false,
       deleteBranch: false,
       exemptIssueLabels: '',
@@ -37,12 +40,19 @@ describe('Issue', (): void => {
       removeStaleWhenUpdated: false,
       removeIssueStaleWhenUpdated: undefined,
       removePrStaleWhenUpdated: undefined,
+      removeRottenWhenUpdated: false,
+      removeIssueRottenWhenUpdated: undefined,
+      removePrRottenWhenUpdated: undefined,
       repoToken: '',
       staleIssueMessage: '',
       stalePrMessage: '',
+      rottenIssueMessage: '',
+      rottenPrMessage: '',
       startDate: undefined,
       stalePrLabel: 'dummy-stale-pr-label',
       staleIssueLabel: 'dummy-stale-issue-label',
+      rottenPrLabel: 'dummy-rotten-pr-label',
+      rottenIssueLabel: 'dummy-rotten-issue-label',
       exemptMilestones: '',
       exemptIssueMilestones: '',
       exemptPrMilestones: '',
@@ -59,6 +69,9 @@ describe('Issue', (): void => {
       labelsToRemoveWhenStale: '',
       labelsToRemoveWhenUnstale: '',
       labelsToAddWhenUnstale: '',
+      labelsToRemoveWhenRotten: '',
+      labelsToRemoveWhenUnrotten: '',
+      labelsToAddWhenUnrotten: '',
       ignoreUpdates: false,
       ignoreIssueUpdates: undefined,
       ignorePrUpdates: undefined,
diff --git a/src/classes/issue.ts b/src/classes/issue.ts
index b90631835..173bb900a 100644
--- a/src/classes/issue.ts
+++ b/src/classes/issue.ts
@@ -21,7 +21,9 @@ export class Issue implements IIssue {
   readonly milestone?: IMilestone | null;
   readonly assignees: Assignee[];
   isStale: boolean;
+  isRotten: boolean;
   markedStaleThisRun: boolean;
+  markedRottenThisRun: boolean;
   operations = new Operations();
   private readonly _options: IIssuesProcessorOptions;
 
@@ -42,7 +44,9 @@ export class Issue implements IIssue {
     this.milestone = issue.milestone;
     this.assignees = issue.assignees || [];
     this.isStale = isLabeled(this, this.staleLabel);
+    this.isRotten = isLabeled(this, this.rottenLabel);
     this.markedStaleThisRun = false;
+    this.markedRottenThisRun = false;
   }
 
   get isPullRequest(): boolean {
@@ -52,6 +56,9 @@ export class Issue implements IIssue {
   get staleLabel(): string {
     return this._getStaleLabel();
   }
+  get rottenLabel(): string {
+    return this._getRottenLabel();
+  }
 
   get hasAssignees(): boolean {
     return this.assignees.length > 0;
@@ -62,6 +69,11 @@ export class Issue implements IIssue {
       ? this._options.stalePrLabel
       : this._options.staleIssueLabel;
   }
+  private _getRottenLabel(): string {
+    return this.isPullRequest
+      ? this._options.rottenPrLabel
+      : this._options.rottenIssueLabel;
+  }
 }
 
 function mapLabels(labels: (string | ILabel)[] | ILabel[]): ILabel[] {
diff --git a/src/classes/issues-processor.ts b/src/classes/issues-processor.ts
index 486c6a78a..b7f31bd9d 100644
--- a/src/classes/issues-processor.ts
+++ b/src/classes/issues-processor.ts
@@ -69,6 +69,7 @@ export class IssuesProcessor {
   readonly client: InstanceType<typeof GitHub>;
   readonly options: IIssuesProcessorOptions;
   readonly staleIssues: Issue[] = [];
+  readonly rottenIssues: Issue[] = [];
   readonly closedIssues: Issue[] = [];
   readonly deletedBranchIssues: Issue[] = [];
   readonly removedLabelIssues: Issue[] = [];
@@ -141,6 +142,16 @@ export class IssuesProcessor {
     const labelsToRemoveWhenUnstale: string[] = wordsToList(
       this.options.labelsToRemoveWhenUnstale
     );
+    const labelsToRemoveWhenRotten: string[] = wordsToList(
+      this.options.labelsToRemoveWhenRotten
+    );
+
+    const labelsToAddWhenUnrotten: string[] = wordsToList(
+      this.options.labelsToAddWhenUnrotten
+    );
+    const labelsToRemoveWhenUnrotten: string[] = wordsToList(
+      this.options.labelsToRemoveWhenUnrotten
+    );
 
     for (const issue of issues.values()) {
       // Stop the processing if no more operations remains
@@ -160,7 +171,10 @@ export class IssuesProcessor {
           issue,
           labelsToAddWhenUnstale,
           labelsToRemoveWhenUnstale,
-          labelsToRemoveWhenStale
+          labelsToRemoveWhenStale,
+          labelsToAddWhenUnrotten,
+          labelsToRemoveWhenUnrotten,
+          labelsToRemoveWhenRotten
         );
       });
       this.state.addIssueToProcessed(issue);
@@ -200,7 +214,10 @@ export class IssuesProcessor {
     issue: Issue,
     labelsToAddWhenUnstale: Readonly<string>[],
     labelsToRemoveWhenUnstale: Readonly<string>[],
-    labelsToRemoveWhenStale: Readonly<string>[]
+    labelsToRemoveWhenStale: Readonly<string>[],
+    labelsToAddWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenRotten: Readonly<string>[]
   ): Promise<void> {
     this.statistics?.incrementProcessedItemsCount(issue);
 
@@ -215,12 +232,21 @@ export class IssuesProcessor {
     const staleMessage: string = issue.isPullRequest
       ? this.options.stalePrMessage
       : this.options.staleIssueMessage;
+    const rottenMessage: string = issue.isPullRequest
+      ? this.options.rottenPrMessage
+      : this.options.rottenIssueMessage;
     const closeMessage: string = issue.isPullRequest
       ? this.options.closePrMessage
       : this.options.closeIssueMessage;
+    const skipRottenMessage = issue.isPullRequest
+      ? this.options.rottenPrMessage.length === 0
+      : this.options.rottenIssueMessage.length === 0;
     const staleLabel: string = issue.isPullRequest
       ? this.options.stalePrLabel
       : this.options.staleIssueLabel;
+    const rottenLabel: string = issue.isPullRequest
+      ? this.options.rottenPrLabel
+      : this.options.rottenIssueLabel;
     const closeLabel: string = issue.isPullRequest
       ? this.options.closePrLabel
       : this.options.closeIssueLabel;
@@ -342,10 +368,16 @@ export class IssuesProcessor {
       }
     }
 
+    // Check if the issue is stale, if not, check if it is rotten and then log the findings.
     if (issue.isStale) {
       issueLogger.info(`This $$type includes a stale label`);
     } else {
       issueLogger.info(`This $$type does not include a stale label`);
+      if (issue.isRotten) {
+        issueLogger.info(`This $$type includes a rotten label`);
+      } else {
+        issueLogger.info(`This $$type does not include a rotten label`);
+      }
     }
 
     const exemptLabels: string[] = wordsToList(
@@ -445,78 +477,92 @@ export class IssuesProcessor {
       return; // Don't process draft PR
     }
 
+    // Here we are looking into if the issue is stale or not, and then adding the label. This same code will also be used for the rotten label.
     // Determine if this issue needs to be marked stale first
     if (!issue.isStale) {
       issueLogger.info(`This $$type is not stale`);
 
-      const shouldIgnoreUpdates: boolean = new IgnoreUpdates(
-        this.options,
-        issue
-      ).shouldIgnoreUpdates();
-
-      // Should this issue be marked as stale?
-      let shouldBeStale: boolean;
-
-      // Ignore the last update and only use the creation date
-      if (shouldIgnoreUpdates) {
-        shouldBeStale = !IssuesProcessor._updatedSince(
-          issue.created_at,
-          daysBeforeStale
-        );
-      }
-      // Use the last update to check if we need to stale
-      else {
-        shouldBeStale = !IssuesProcessor._updatedSince(
-          issue.updated_at,
-          daysBeforeStale
+      if (issue.isRotten) {
+        await this._processRottenIssue(
+          issue,
+          rottenLabel,
+          rottenMessage,
+          labelsToAddWhenUnrotten,
+          labelsToRemoveWhenUnrotten,
+          labelsToRemoveWhenRotten,
+          closeMessage,
+          closeLabel
         );
-      }
+      } else {
+        const shouldIgnoreUpdates: boolean = new IgnoreUpdates(
+          this.options,
+          issue
+        ).shouldIgnoreUpdates();
 
-      if (shouldBeStale) {
+        // Should this issue be marked as stale?
+        let shouldBeStale: boolean;
+
+        // Ignore the last update and only use the creation date
         if (shouldIgnoreUpdates) {
-          issueLogger.info(
-            `This $$type should be stale based on the creation date the ${getHumanizedDate(
-              new Date(issue.created_at)
-            )} (${LoggerService.cyan(issue.created_at)})`
-          );
-        } else {
-          issueLogger.info(
-            `This $$type should be stale based on the last update date the ${getHumanizedDate(
-              new Date(issue.updated_at)
-            )} (${LoggerService.cyan(issue.updated_at)})`
+          shouldBeStale = !IssuesProcessor._updatedSince(
+            issue.created_at,
+            daysBeforeStale
           );
         }
-
-        if (shouldMarkAsStale) {
-          issueLogger.info(
-            `This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(
-              this._getDaysBeforeStaleUsedOptionName(issue)
-            )} (${LoggerService.cyan(daysBeforeStale)})`
-          );
-          await this._markStale(issue, staleMessage, staleLabel, skipMessage);
-          issue.isStale = true; // This issue is now considered stale
-          issue.markedStaleThisRun = true;
-          issueLogger.info(`This $$type is now stale`);
-        } else {
-          issueLogger.info(
-            `This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(
-              this._getDaysBeforeStaleUsedOptionName(issue)
-            )} (${LoggerService.cyan(daysBeforeStale)})`
+        // Use the last update to check if we need to stale
+        else {
+          shouldBeStale = !IssuesProcessor._updatedSince(
+            issue.updated_at,
+            daysBeforeStale
           );
         }
-      } else {
-        if (shouldIgnoreUpdates) {
-          issueLogger.info(
-            `This $$type should not be stale based on the creation date the ${getHumanizedDate(
-              new Date(issue.created_at)
-            )} (${LoggerService.cyan(issue.created_at)})`
-          );
+
+        if (shouldBeStale) {
+          if (shouldIgnoreUpdates) {
+            issueLogger.info(
+              `This $$type should be stale based on the creation date the ${getHumanizedDate(
+                new Date(issue.created_at)
+              )} (${LoggerService.cyan(issue.created_at)})`
+            );
+          } else {
+            issueLogger.info(
+              `This $$type should be stale based on the last update date the ${getHumanizedDate(
+                new Date(issue.updated_at)
+              )} (${LoggerService.cyan(issue.updated_at)})`
+            );
+          }
+
+          if (shouldMarkAsStale) {
+            issueLogger.info(
+              `This $$type should be marked as stale based on the option ${issueLogger.createOptionLink(
+                this._getDaysBeforeStaleUsedOptionName(issue)
+              )} (${LoggerService.cyan(daysBeforeStale)})`
+            );
+            await this._markStale(issue, staleMessage, staleLabel, skipMessage);
+            issue.isStale = true; // This issue is now considered stale
+            issue.markedStaleThisRun = true;
+            issueLogger.info(`This $$type is now stale`);
+          } else {
+            issueLogger.info(
+              `This $$type should not be marked as stale based on the option ${issueLogger.createOptionLink(
+                this._getDaysBeforeStaleUsedOptionName(issue)
+              )} (${LoggerService.cyan(daysBeforeStale)})`
+            );
+          }
         } else {
-          issueLogger.info(
-            `This $$type should not be stale based on the last update date the ${getHumanizedDate(
-              new Date(issue.updated_at)
-            )} (${LoggerService.cyan(issue.updated_at)})`
-          );
+          if (shouldIgnoreUpdates) {
+            issueLogger.info(
+              `This $$type should not be stale based on the creation date the ${getHumanizedDate(
+                new Date(issue.created_at)
+              )} (${LoggerService.cyan(issue.created_at)})`
+            );
+          } else {
+            issueLogger.info(
+              `This $$type should not be stale based on the last update date the ${getHumanizedDate(
+                new Date(issue.updated_at)
+              )} (${LoggerService.cyan(issue.updated_at)})`
+            );
+          }
         }
       }
     }
@@ -528,11 +574,17 @@ export class IssuesProcessor {
         issue,
         staleLabel,
         staleMessage,
+        rottenLabel,
+        rottenMessage,
+        closeLabel,
+        closeMessage,
         labelsToAddWhenUnstale,
         labelsToRemoveWhenUnstale,
         labelsToRemoveWhenStale,
-        closeMessage,
-        closeLabel
+        labelsToAddWhenUnrotten,
+        labelsToRemoveWhenUnrotten,
+        labelsToRemoveWhenRotten,
+        skipRottenMessage
       );
     }
 
@@ -650,17 +702,28 @@ export class IssuesProcessor {
   }
 
   // handle all of the stale issue logic when we find a stale issue
+  // This whole thing needs to be altered, to be calculated based on the days to rotten, rather than days to close or whatever
   private async _processStaleIssue(
     issue: Issue,
     staleLabel: string,
     staleMessage: string,
+    rottenLabel: string,
+    rottenMessage: string,
+    closeLabel: string,
+    closeMessage: string,
     labelsToAddWhenUnstale: Readonly<string>[],
     labelsToRemoveWhenUnstale: Readonly<string>[],
     labelsToRemoveWhenStale: Readonly<string>[],
-    closeMessage?: string,
-    closeLabel?: string
+    labelsToAddWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenRotten: Readonly<string>[],
+    skipMessage: boolean
   ) {
     const issueLogger: IssueLogger = new IssueLogger(issue);
+
+    let issueHasClosed: boolean = false;
+
+    // We can get the label creation date from the getLableCreationDate function
     const markedStaleOn: string =
       (await this.getLabelCreationDate(issue, staleLabel)) || issue.updated_at;
     issueLogger.info(
@@ -678,12 +741,15 @@ export class IssuesProcessor {
       )}`
     );
 
+    const daysBeforeRotten: number = issue.isPullRequest
+      ? this._getDaysBeforePrRotten()
+      : this._getDaysBeforeIssueRotten();
+
     const daysBeforeClose: number = issue.isPullRequest
       ? this._getDaysBeforePrClose()
       : this._getDaysBeforeIssueClose();
-
     issueLogger.info(
-      `Days before $$type close: ${LoggerService.cyan(daysBeforeClose)}`
+      `Days before $$type rotten: ${LoggerService.cyan(daysBeforeRotten)}`
     );
 
     const shouldRemoveStaleWhenUpdated: boolean =
@@ -703,6 +769,7 @@ export class IssuesProcessor {
       );
     }
 
+    // we will need to use a variation of this for the rotten state
     if (issue.markedStaleThisRun) {
       issueLogger.info(`marked stale this run, so don't check for updates`);
       await this._removeLabelsOnStatusTransition(
@@ -750,9 +817,254 @@ export class IssuesProcessor {
       return; // Nothing to do because it is no longer stale
     }
 
+    if (daysBeforeRotten < 0) {
+      if (daysBeforeClose < 0) {
+        issueLogger.info(
+          `Stale $$type cannot be rotten or closed because days before rotten: ${daysBeforeRotten}, and days before close: ${daysBeforeClose}`
+        );
+        return;
+      } else {
+        issueLogger.info(
+          `Closing issue without rottening it because days before $$type rotten: ${LoggerService.cyan(
+            daysBeforeRotten
+          )}`
+        );
+
+        const issueHasUpdateInCloseWindow: boolean =
+          IssuesProcessor._updatedSince(issue.updated_at, daysBeforeClose);
+        issueLogger.info(
+          `$$type has been updated in the last ${daysBeforeClose} days: ${LoggerService.cyan(
+            issueHasUpdateInCloseWindow
+          )}`
+        );
+        if (!issueHasUpdateInCloseWindow && !issueHasCommentsSinceStale) {
+          issueLogger.info(
+            `Closing $$type because it was last updated on: ${LoggerService.cyan(
+              issue.updated_at
+            )}`
+          );
+          await this._closeIssue(issue, closeMessage, closeLabel);
+
+          issueHasClosed = true;
+
+          if (this.options.deleteBranch && issue.pull_request) {
+            issueLogger.info(
+              `Deleting the branch since the option ${issueLogger.createOptionLink(
+                Option.DeleteBranch
+              )} is enabled`
+            );
+            await this._deleteBranch(issue);
+            this.deletedBranchIssues.push(issue);
+          }
+        } else {
+          issueLogger.info(
+            `Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`
+          );
+        }
+      }
+    }
+
+    // TODO: make a function for shouldMarkWhenRotten
+    const shouldMarkAsRotten: boolean = shouldMarkWhenStale(daysBeforeRotten);
+
+    if (issueHasClosed) {
+      issueLogger.info(
+        `Issue $$type has been closed, no need to process it further.`
+      );
+      return;
+    }
+
+    if (!issue.isRotten) {
+      issueLogger.info(`This $$type is not rotten`);
+
+      const shouldIgnoreUpdates: boolean = new IgnoreUpdates(
+        this.options,
+        issue
+      ).shouldIgnoreUpdates();
+
+      const shouldBeRotten: boolean = !IssuesProcessor._updatedSince(
+        issue.updated_at,
+        daysBeforeRotten
+      );
+
+      if (shouldBeRotten) {
+        if (shouldIgnoreUpdates) {
+          issueLogger.info(
+            `This $$type should be rotten based on the creation date the ${getHumanizedDate(
+              new Date(issue.created_at)
+            )} (${LoggerService.cyan(issue.created_at)})`
+          );
+        } else {
+          issueLogger.info(
+            `This $$type should be rotten based on the last update date the ${getHumanizedDate(
+              new Date(issue.updated_at)
+            )} (${LoggerService.cyan(issue.updated_at)})`
+          );
+        }
+
+        if (shouldMarkAsRotten) {
+          issueLogger.info(
+            `This $$type should be marked as rotten based on the option ${issueLogger.createOptionLink(
+              this._getDaysBeforeRottenUsedOptionName(issue)
+            )} (${LoggerService.cyan(daysBeforeRotten)})`
+          );
+          // remove the stale label before marking the issue as rotten
+          await this._removeStaleLabel(issue, staleLabel);
+
+          await this._markRotten(
+            issue,
+            rottenMessage,
+            rottenLabel,
+            skipMessage
+          );
+          issue.isRotten = true; // This issue is now considered rotten
+          issue.markedRottenThisRun = true;
+          issueLogger.info(`This $$type is now rotten`);
+        } else {
+          issueLogger.info(
+            `This $$type should not be marked as rotten based on the option ${issueLogger.createOptionLink(
+              this._getDaysBeforeStaleUsedOptionName(issue)
+            )} (${LoggerService.cyan(daysBeforeRotten)})`
+          );
+        }
+      } else {
+        if (shouldIgnoreUpdates) {
+          issueLogger.info(
+            `This $$type is not old enough to be rotten based on the creation date the ${getHumanizedDate(
+              new Date(issue.created_at)
+            )} (${LoggerService.cyan(issue.created_at)})`
+          );
+        } else {
+          issueLogger.info(
+            `This $$type is not old enough to be rotten based on the creation date the ${getHumanizedDate(
+              new Date(issue.updated_at)
+            )} (${LoggerService.cyan(issue.updated_at)})`
+          );
+        }
+      }
+    }
+    if (issue.isRotten) {
+      issueLogger.info(`This $$type is already rotten`);
+      // process the rotten issues
+      this._processRottenIssue(
+        issue,
+        rottenLabel,
+        rottenMessage,
+        labelsToAddWhenUnrotten,
+        labelsToRemoveWhenUnrotten,
+        labelsToRemoveWhenRotten,
+        closeMessage,
+        closeLabel
+      );
+    }
+  }
+  private async _processRottenIssue(
+    issue: Issue,
+    rottenLabel: string,
+    rottenMessage: string,
+    labelsToAddWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenUnrotten: Readonly<string>[],
+    labelsToRemoveWhenRotten: Readonly<string>[],
+    closeMessage?: string,
+    closeLabel?: string
+  ) {
+    const issueLogger: IssueLogger = new IssueLogger(issue);
+    // We can get the label creation date from the getLableCreationDate function
+    const markedRottenOn: string =
+      (await this.getLabelCreationDate(issue, rottenLabel)) || issue.updated_at;
+    issueLogger.info(
+      `$$type marked rotten on: ${LoggerService.cyan(markedRottenOn)}`
+    );
+
+    const issueHasCommentsSinceRotten: boolean = await this._hasCommentsSince(
+      issue,
+      markedRottenOn,
+      rottenMessage
+    );
+    issueLogger.info(
+      `$$type has been commented on: ${LoggerService.cyan(
+        issueHasCommentsSinceRotten
+      )}`
+    );
+
+    const daysBeforeClose: number = issue.isPullRequest
+      ? this._getDaysBeforePrClose()
+      : this._getDaysBeforeIssueClose();
+
+    issueLogger.info(
+      `Days before $$type close: ${LoggerService.cyan(daysBeforeClose)}`
+    );
+
+    const shouldRemoveRottenWhenUpdated: boolean =
+      this._shouldRemoveRottenWhenUpdated(issue);
+
+    issueLogger.info(
+      `The option ${issueLogger.createOptionLink(
+        this._getRemoveRottenWhenUpdatedUsedOptionName(issue)
+      )} is: ${LoggerService.cyan(shouldRemoveRottenWhenUpdated)}`
+    );
+
+    if (shouldRemoveRottenWhenUpdated) {
+      issueLogger.info(`The rotten label should not be removed`);
+    } else {
+      issueLogger.info(
+        `The rotten label should be removed if all conditions met`
+      );
+    }
+
+    if (issue.markedRottenThisRun) {
+      issueLogger.info(`marked rotten this run, so don't check for updates`);
+      await this._removeLabelsOnStatusTransition(
+        issue,
+        labelsToRemoveWhenRotten,
+        Option.LabelsToRemoveWhenRotten
+      );
+    }
+
+    // The issue.updated_at and markedRottenOn are not always exactly in sync (they can be off by a second or 2)
+    // isDateMoreRecentThan makes sure they are not the same date within a certain tolerance (15 seconds in this case)
+    const issueHasUpdateSinceRotten = isDateMoreRecentThan(
+      new Date(issue.updated_at),
+      new Date(markedRottenOn),
+      15
+    );
+
+    issueLogger.info(
+      `$$type has been updated since it was marked rotten: ${LoggerService.cyan(
+        issueHasUpdateSinceRotten
+      )}`
+    );
+
+    // Should we un-rotten this issue?
+    if (
+      shouldRemoveRottenWhenUpdated &&
+      (issueHasUpdateSinceRotten || issueHasCommentsSinceRotten) &&
+      !issue.markedRottenThisRun
+    ) {
+      issueLogger.info(
+        `Remove the rotten label since the $$type has been updated and the workflow should remove the stale label when updated`
+      );
+      await this._removeRottenLabel(issue, rottenLabel);
+
+      // Are there labels to remove or add when an issue is no longer rotten?
+      // This logic takes care of removing labels when unrotten
+      await this._removeLabelsOnStatusTransition(
+        issue,
+        labelsToRemoveWhenUnrotten,
+        Option.LabelsToRemoveWhenUnrotten
+      );
+      await this._addLabelsWhenUnrotten(issue, labelsToAddWhenUnrotten);
+
+      issueLogger.info(
+        `Skipping the process since the $$type is now un-rotten`
+      );
+
+      return; // Nothing to do because it is no longer rotten
+    }
+
     // Now start closing logic
     if (daysBeforeClose < 0) {
-      return; // Nothing to do because we aren't closing stale issues
+      return; // Nothing to do because we aren't closing rotten issues
     }
 
     const issueHasUpdateInCloseWindow: boolean = IssuesProcessor._updatedSince(
@@ -765,7 +1077,7 @@ export class IssuesProcessor {
       )}`
     );
 
-    if (!issueHasCommentsSinceStale && !issueHasUpdateInCloseWindow) {
+    if (!issueHasCommentsSinceRotten && !issueHasUpdateInCloseWindow) {
       issueLogger.info(
         `Closing $$type because it was last updated on: ${LoggerService.cyan(
           issue.updated_at
@@ -784,7 +1096,7 @@ export class IssuesProcessor {
       }
     } else {
       issueLogger.info(
-        `Stale $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceStale}, hasUpdate? ${issueHasUpdateInCloseWindow})`
+        `Rotten $$type is not old enough to close yet (hasComments? ${issueHasCommentsSinceRotten}, hasUpdate? ${issueHasUpdateInCloseWindow})`
       );
     }
   }
@@ -876,6 +1188,57 @@ export class IssuesProcessor {
       issueLogger.error(`Error when adding a label: ${error.message}`);
     }
   }
+  private async _markRotten(
+    issue: Issue,
+    rottenMessage: string,
+    rottenLabel: string,
+    skipMessage: boolean
+  ): Promise<void> {
+    const issueLogger: IssueLogger = new IssueLogger(issue);
+
+    issueLogger.info(`Marking this $$type as rotten`);
+    this.rottenIssues.push(issue);
+
+    // if the issue is being marked rotten, the updated date should be changed to right now
+    // so that close calculations work correctly
+    const newUpdatedAtDate: Date = new Date();
+    issue.updated_at = newUpdatedAtDate.toString();
+
+    if (!skipMessage) {
+      try {
+        this._consumeIssueOperation(issue);
+        this.statistics?.incrementAddedItemsComment(issue);
+
+        if (!this.options.debugOnly) {
+          await this.client.rest.issues.createComment({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            issue_number: issue.number,
+            body: rottenMessage
+          });
+        }
+      } catch (error) {
+        issueLogger.error(`Error when creating a comment: ${error.message}`);
+      }
+    }
+
+    try {
+      this._consumeIssueOperation(issue);
+      this.statistics?.incrementAddedItemsLabel(issue);
+      this.statistics?.incrementStaleItemsCount(issue);
+
+      if (!this.options.debugOnly) {
+        await this.client.rest.issues.addLabels({
+          owner: context.repo.owner,
+          repo: context.repo.repo,
+          issue_number: issue.number,
+          labels: [rottenLabel]
+        });
+      }
+    } catch (error) {
+      issueLogger.error(`Error when adding a label: ${error.message}`);
+    }
+  }
 
   // Close an issue based on staleness
   private async _closeIssue(
@@ -885,7 +1248,7 @@ export class IssuesProcessor {
   ): Promise<void> {
     const issueLogger: IssueLogger = new IssueLogger(issue);
 
-    issueLogger.info(`Closing $$type for being stale`);
+    issueLogger.info(`Closing $$type for being stale/rotten`);
     this.closedIssues.push(issue);
 
     if (closeMessage) {
@@ -1056,6 +1419,17 @@ export class IssuesProcessor {
       ? this.options.daysBeforeStale
       : this.options.daysBeforePrStale;
   }
+  private _getDaysBeforeIssueRotten(): number {
+    return isNaN(this.options.daysBeforeIssueRotten)
+      ? this.options.daysBeforeRotten
+      : this.options.daysBeforeIssueRotten;
+  }
+
+  private _getDaysBeforePrRotten(): number {
+    return isNaN(this.options.daysBeforePrRotten)
+      ? this.options.daysBeforeRotten
+      : this.options.daysBeforePrRotten;
+  }
 
   private _getDaysBeforeIssueClose(): number {
     return isNaN(this.options.daysBeforeIssueClose)
@@ -1116,6 +1490,21 @@ export class IssuesProcessor {
 
     return this.options.removeStaleWhenUpdated;
   }
+  private _shouldRemoveRottenWhenUpdated(issue: Issue): boolean {
+    if (issue.isPullRequest) {
+      if (isBoolean(this.options.removePrRottenWhenUpdated)) {
+        return this.options.removePrRottenWhenUpdated;
+      }
+
+      return this.options.removeRottenWhenUpdated;
+    }
+
+    if (isBoolean(this.options.removeIssueRottenWhenUpdated)) {
+      return this.options.removeIssueRottenWhenUpdated;
+    }
+
+    return this.options.removeRottenWhenUpdated;
+  }
 
   private async _removeLabelsOnStatusTransition(
     issue: Issue,
@@ -1175,6 +1564,42 @@ export class IssuesProcessor {
     }
   }
 
+  private async _addLabelsWhenUnrotten(
+    issue: Issue,
+    labelsToAdd: Readonly<string>[]
+  ): Promise<void> {
+    if (!labelsToAdd.length) {
+      return;
+    }
+
+    const issueLogger: IssueLogger = new IssueLogger(issue);
+
+    issueLogger.info(
+      `Adding all the labels specified via the ${this._logger.createOptionLink(
+        Option.LabelsToAddWhenUnrotten
+      )} option.`
+    );
+
+    // TODO: this might need to be changed to a set to avoiod repetition
+    this.addedLabelIssues.push(issue);
+
+    try {
+      this._consumeIssueOperation(issue);
+      this.statistics?.incrementAddedItemsLabel(issue);
+      if (!this.options.debugOnly) {
+        await this.client.rest.issues.addLabels({
+          owner: context.repo.owner,
+          repo: context.repo.repo,
+          issue_number: issue.number,
+          labels: labelsToAdd
+        });
+      }
+    } catch (error) {
+      this._logger.error(
+        `Error when adding labels after updated from rotten: ${error.message}`
+      );
+    }
+  }
   private async _removeStaleLabel(
     issue: Issue,
     staleLabel: Readonly<string>
@@ -1188,6 +1613,19 @@ export class IssuesProcessor {
     await this._removeLabel(issue, staleLabel);
     this.statistics?.incrementUndoStaleItemsCount(issue);
   }
+  private async _removeRottenLabel(
+    issue: Issue,
+    rottenLabel: Readonly<string>
+  ): Promise<void> {
+    const issueLogger: IssueLogger = new IssueLogger(issue);
+
+    issueLogger.info(
+      `The $$type is no longer rotten. Removing the rotten label...`
+    );
+
+    await this._removeLabel(issue, rottenLabel);
+    this.statistics?.incrementUndoRottenItemsCount(issue);
+  }
 
   private async _removeCloseLabel(
     issue: Issue,
@@ -1266,6 +1704,32 @@ export class IssuesProcessor {
       : Option.DaysBeforePrStale;
   }
 
+  private _getDaysBeforeRottenUsedOptionName(
+    issue: Readonly<Issue>
+  ):
+    | Option.DaysBeforeRotten
+    | Option.DaysBeforeIssueRotten
+    | Option.DaysBeforePrRotten {
+    return issue.isPullRequest
+      ? this._getDaysBeforePrRottenUsedOptionName()
+      : this._getDaysBeforeIssueRottenUsedOptionName();
+  }
+
+  private _getDaysBeforeIssueRottenUsedOptionName():
+    | Option.DaysBeforeRotten
+    | Option.DaysBeforeIssueRotten {
+    return isNaN(this.options.daysBeforeIssueRotten)
+      ? Option.DaysBeforeRotten
+      : Option.DaysBeforeIssueRotten;
+  }
+
+  private _getDaysBeforePrRottenUsedOptionName():
+    | Option.DaysBeforeRotten
+    | Option.DaysBeforePrRotten {
+    return isNaN(this.options.daysBeforePrRotten)
+      ? Option.DaysBeforeRotten
+      : Option.DaysBeforePrRotten;
+  }
   private _getRemoveStaleWhenUpdatedUsedOptionName(
     issue: Readonly<Issue>
   ):
@@ -1286,4 +1750,24 @@ export class IssuesProcessor {
 
     return Option.RemoveStaleWhenUpdated;
   }
+  private _getRemoveRottenWhenUpdatedUsedOptionName(
+    issue: Readonly<Issue>
+  ):
+    | Option.RemovePrRottenWhenUpdated
+    | Option.RemoveRottenWhenUpdated
+    | Option.RemoveIssueRottenWhenUpdated {
+    if (issue.isPullRequest) {
+      if (isBoolean(this.options.removePrRottenWhenUpdated)) {
+        return Option.RemovePrRottenWhenUpdated;
+      }
+
+      return Option.RemoveRottenWhenUpdated;
+    }
+
+    if (isBoolean(this.options.removeIssueRottenWhenUpdated)) {
+      return Option.RemoveIssueRottenWhenUpdated;
+    }
+
+    return Option.RemoveRottenWhenUpdated;
+  }
 }
diff --git a/src/classes/statistics.ts b/src/classes/statistics.ts
index 321ea70d9..3e6bba3d2 100644
--- a/src/classes/statistics.ts
+++ b/src/classes/statistics.ts
@@ -15,6 +15,10 @@ export class Statistics {
   stalePullRequestsCount = 0;
   undoStaleIssuesCount = 0;
   undoStalePullRequestsCount = 0;
+  rottenIssuesCount = 0;
+  rottenPullRequestsCount = 0;
+  undoRottenIssuesCount = 0;
+  undoRottenPullRequestsCount = 0;
   operationsCount = 0;
   closedIssuesCount = 0;
   closedPullRequestsCount = 0;
@@ -65,6 +69,17 @@ export class Statistics {
     return this._incrementUndoStaleIssuesCount(increment);
   }
 
+  incrementUndoRottenItemsCount(
+    issue: Readonly<Issue>,
+    increment: Readonly<number> = 1
+  ): Statistics {
+    if (issue.isPullRequest) {
+      return this._incrementUndoRottenPullRequestsCount(increment);
+    }
+
+    return this._incrementUndoRottenIssuesCount(increment);
+  }
+
   setOperationsCount(operationsCount: Readonly<number>): Statistics {
     this.operationsCount = operationsCount;
 
@@ -222,6 +237,21 @@ export class Statistics {
     return this;
   }
 
+  private _incrementUndoRottenPullRequestsCount(
+    increment: Readonly<number> = 1
+  ): Statistics {
+    this.undoRottenPullRequestsCount += increment;
+
+    return this;
+  }
+  private _incrementUndoRottenIssuesCount(
+    increment: Readonly<number> = 1
+  ): Statistics {
+    this.undoRottenIssuesCount += increment;
+
+    return this;
+  }
+
   private _incrementUndoStalePullRequestsCount(
     increment: Readonly<number> = 1
   ): Statistics {
diff --git a/src/enums/option.ts b/src/enums/option.ts
index 7a9bff026..f27ff881b 100644
--- a/src/enums/option.ts
+++ b/src/enums/option.ts
@@ -2,18 +2,25 @@ export enum Option {
   RepoToken = 'repo-token',
   StaleIssueMessage = 'stale-issue-message',
   StalePrMessage = 'stale-pr-message',
+  RottenIssueMessage = 'rotten-issue-message',
+  RottenPrMessage = 'rotten-pr-message',
   CloseIssueMessage = 'close-issue-message',
   ClosePrMessage = 'close-pr-message',
   DaysBeforeStale = 'days-before-stale',
   DaysBeforeIssueStale = 'days-before-issue-stale',
   DaysBeforePrStale = 'days-before-pr-stale',
+  DaysBeforeRotten = 'days-before-rotten',
+  DaysBeforeIssueRotten = 'days-before-issue-rotten',
+  DaysBeforePrRotten = 'days-before-pr-rotten',
   DaysBeforeClose = 'days-before-close',
   DaysBeforeIssueClose = 'days-before-issue-close',
   DaysBeforePrClose = 'days-before-pr-close',
   StaleIssueLabel = 'stale-issue-label',
+  RottenIssueLabel = 'rotten-issue-label',
   CloseIssueLabel = 'close-issue-label',
   ExemptIssueLabels = 'exempt-issue-labels',
   StalePrLabel = 'stale-pr-label',
+  RottenPrLabel = 'rotten-pr-label',
   ClosePrLabel = 'close-pr-label',
   ExemptPrLabels = 'exempt-pr-labels',
   OnlyLabels = 'only-labels',
@@ -24,6 +31,9 @@ export enum Option {
   RemoveStaleWhenUpdated = 'remove-stale-when-updated',
   RemoveIssueStaleWhenUpdated = 'remove-issue-stale-when-updated',
   RemovePrStaleWhenUpdated = 'remove-pr-stale-when-updated',
+  RemoveRottenWhenUpdated = 'remove-rotten-when-updated',
+  RemoveIssueRottenWhenUpdated = 'remove-issue-rotten-when-updated',
+  RemovePrRottenWhenUpdated = 'remove-pr-rotten-when-updated',
   DebugOnly = 'debug-only',
   Ascending = 'ascending',
   DeleteBranch = 'delete-branch',
@@ -44,6 +54,9 @@ export enum Option {
   LabelsToRemoveWhenStale = 'labels-to-remove-when-stale',
   LabelsToRemoveWhenUnstale = 'labels-to-remove-when-unstale',
   LabelsToAddWhenUnstale = 'labels-to-add-when-unstale',
+  LabelsToRemoveWhenRotten = 'labels-to-remove-when-rotten',
+  LabelsToRemoveWhenUnrotten = 'labels-to-remove-when-unrotten',
+  LabelsToAddWhenUnrotten = 'labels-to-add-when-unrotten',
   IgnoreUpdates = 'ignore-updates',
   IgnoreIssueUpdates = 'ignore-issue-updates',
   IgnorePrUpdates = 'ignore-pr-updates',
diff --git a/src/interfaces/issues-processor-options.ts b/src/interfaces/issues-processor-options.ts
index 930992284..8789489ac 100644
--- a/src/interfaces/issues-processor-options.ts
+++ b/src/interfaces/issues-processor-options.ts
@@ -4,18 +4,25 @@ export interface IIssuesProcessorOptions {
   repoToken: string;
   staleIssueMessage: string;
   stalePrMessage: string;
+  rottenIssueMessage: string;
+  rottenPrMessage: string;
   closeIssueMessage: string;
   closePrMessage: string;
   daysBeforeStale: number;
   daysBeforeIssueStale: number; // Could be NaN
   daysBeforePrStale: number; // Could be NaN
+  daysBeforeRotten: number;
+  daysBeforeIssueRotten: number; // Could be NaN
+  daysBeforePrRotten: number; // Could be NaN
   daysBeforeClose: number;
   daysBeforeIssueClose: number; // Could be NaN
   daysBeforePrClose: number; // Could be NaN
   staleIssueLabel: string;
+  rottenIssueLabel: string;
   closeIssueLabel: string;
   exemptIssueLabels: string;
   stalePrLabel: string;
+  rottenPrLabel: string;
   closePrLabel: string;
   exemptPrLabels: string;
   onlyLabels: string;
@@ -28,6 +35,9 @@ export interface IIssuesProcessorOptions {
   removeStaleWhenUpdated: boolean;
   removeIssueStaleWhenUpdated: boolean | undefined;
   removePrStaleWhenUpdated: boolean | undefined;
+  removeRottenWhenUpdated: boolean;
+  removeIssueRottenWhenUpdated: boolean | undefined;
+  removePrRottenWhenUpdated: boolean | undefined;
   debugOnly: boolean;
   ascending: boolean;
   deleteBranch: boolean;
@@ -48,6 +58,9 @@ export interface IIssuesProcessorOptions {
   labelsToRemoveWhenStale: string;
   labelsToRemoveWhenUnstale: string;
   labelsToAddWhenUnstale: string;
+  labelsToRemoveWhenRotten: string;
+  labelsToRemoveWhenUnrotten: string;
+  labelsToAddWhenUnrotten: string;
   ignoreUpdates: boolean;
   ignoreIssueUpdates: boolean | undefined;
   ignorePrUpdates: boolean | undefined;
diff --git a/src/main.ts b/src/main.ts
index a7836c160..ea0b82150 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -46,6 +46,7 @@ async function _run(): Promise<void> {
 
     await processOutput(
       issueProcessor.staleIssues,
+      issueProcessor.rottenIssues,
       issueProcessor.closedIssues
     );
   } catch (error) {
@@ -59,22 +60,33 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
     repoToken: core.getInput('repo-token'),
     staleIssueMessage: core.getInput('stale-issue-message'),
     stalePrMessage: core.getInput('stale-pr-message'),
+    rottenIssueMessage: core.getInput('rotten-issue-message'),
+    rottenPrMessage: core.getInput('rotten-pr-message'),
     closeIssueMessage: core.getInput('close-issue-message'),
     closePrMessage: core.getInput('close-pr-message'),
     daysBeforeStale: parseFloat(
       core.getInput('days-before-stale', {required: true})
     ),
+    daysBeforeRotten: parseFloat(
+      core.getInput('days-before-rotten', {required: true})
+    ),
     daysBeforeIssueStale: parseFloat(core.getInput('days-before-issue-stale')),
     daysBeforePrStale: parseFloat(core.getInput('days-before-pr-stale')),
+    daysBeforeIssueRotten: parseFloat(
+      core.getInput('days-before-issue-rotten')
+    ),
+    daysBeforePrRotten: parseFloat(core.getInput('days-before-pr-rotten')),
     daysBeforeClose: parseInt(
       core.getInput('days-before-close', {required: true})
     ),
     daysBeforeIssueClose: parseInt(core.getInput('days-before-issue-close')),
     daysBeforePrClose: parseInt(core.getInput('days-before-pr-close')),
     staleIssueLabel: core.getInput('stale-issue-label', {required: true}),
+    rottenIssueLabel: core.getInput('rotten-issue-label', {required: true}),
     closeIssueLabel: core.getInput('close-issue-label'),
     exemptIssueLabels: core.getInput('exempt-issue-labels'),
     stalePrLabel: core.getInput('stale-pr-label', {required: true}),
+    rottenPrLabel: core.getInput('rotten-pr-label', {required: true}),
     closePrLabel: core.getInput('close-pr-label'),
     exemptPrLabels: core.getInput('exempt-pr-labels'),
     onlyLabels: core.getInput('only-labels'),
@@ -95,6 +107,15 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
     removePrStaleWhenUpdated: _toOptionalBoolean(
       'remove-pr-stale-when-updated'
     ),
+    removeRottenWhenUpdated: !(
+      core.getInput('remove-rotten-when-updated') === 'false'
+    ),
+    removeIssueRottenWhenUpdated: _toOptionalBoolean(
+      'remove-issue-rotten-when-updated'
+    ),
+    removePrRottenWhenUpdated: _toOptionalBoolean(
+      'remove-pr-rotten-when-updated'
+    ),
     debugOnly: core.getInput('debug-only') === 'true',
     ascending: core.getInput('ascending') === 'true',
     deleteBranch: core.getInput('delete-branch') === 'true',
@@ -118,6 +139,9 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
     labelsToRemoveWhenStale: core.getInput('labels-to-remove-when-stale'),
     labelsToRemoveWhenUnstale: core.getInput('labels-to-remove-when-unstale'),
     labelsToAddWhenUnstale: core.getInput('labels-to-add-when-unstale'),
+    labelsToRemoveWhenRotten: core.getInput('labels-to-remove-when-rotten'),
+    labelsToRemoveWhenUnrotten: core.getInput('labels-to-remove-when-unrotten'),
+    labelsToAddWhenUnrotten: core.getInput('labels-to-add-when-unrotten'),
     ignoreUpdates: core.getInput('ignore-updates') === 'true',
     ignoreIssueUpdates: _toOptionalBoolean('ignore-issue-updates'),
     ignorePrUpdates: _toOptionalBoolean('ignore-pr-updates'),
@@ -133,6 +157,13 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
       throw new Error(errorMessage);
     }
   }
+  for (const numberInput of ['days-before-rotten']) {
+    if (isNaN(parseFloat(core.getInput(numberInput)))) {
+      const errorMessage = `Option "${numberInput}" did not parse to a valid float`;
+      core.setFailed(errorMessage);
+      throw new Error(errorMessage);
+    }
+  }
 
   for (const numberInput of ['days-before-close', 'operations-per-run']) {
     if (isNaN(parseInt(core.getInput(numberInput)))) {
@@ -167,9 +198,11 @@ function _getAndValidateArgs(): IIssuesProcessorOptions {
 
 async function processOutput(
   staledIssues: Issue[],
+  rottenIssues: Issue[],
   closedIssues: Issue[]
 ): Promise<void> {
   core.setOutput('staled-issues-prs', JSON.stringify(staledIssues));
+  core.setOutput('rotten-issues-prs', JSON.stringify(rottenIssues));
   core.setOutput('closed-issues-prs', JSON.stringify(closedIssues));
 }