Skip to content

AI Task Suggester

zach115th edited this page Sep 18, 2026 · 1 revision

AI Task Suggester

On main, not yet released. The release after IRIS-NG-v2.2.0 carries this page's feature; until that tag exists, an installed image does not have it. See Changelog.

A case accumulates findings faster than it accumulates a plan: a webshell is confirmed and nobody opens the eradication task, a command-and-control domain is recorded and nobody is asked to block it, evidence is collected and the analysis task never appears. The task suggester reads the case and proposes the tasks that are missing. It only proposes — a task exists when an analyst accepts it, never before.

Open it with the sparkle button on the Tasks tab's toolbar, to the left of Refresh.

What you see

A review panel lists up to eight suggestions, the work that should start first at the top. Each card carries:

Part What it is
Priority high (delay blocks containment or loses evidence), medium or low
Title and description Editable in place. What you accept is what is on screen, not what the model wrote
Why One sentence naming the fact in the case that makes the task necessary
Assign to A picker limited to the people who can work the case — see Who gets proposed
Skill chips The skills the task needs, from your skill catalog
Depends on Work that has to finish first: an existing task (#12 Collect artifacts) or another suggestion (dashed outline)

Accept creates that one task. Accept all creates everything still listed, in one request. Dismiss removes a card for the rest of the session — it is not remembered, so Regenerate may offer the idea again. Edits you have typed into other cards survive an accept or a dismiss.

An accepted task is an ordinary task from then on. It is created through the same path as the Add task dialog, so module hooks run, the activity log records it, and the assignee receives the usual task-assigned notification. Two things mark where it came from and nothing else: the status is To do, and the task carries the tag ai-suggested.

Dependencies become task links

A suggestion can depend on a task the case already has, or on another suggestion in the same list. Accepting creates depends_on task links, so the Tasks tab's tree view shows the order the work should happen in.

A dependency on another suggestion is kept only when that suggestion becomes a task too — accept it first, or accept both together. Accept a task alone while the thing it depends on is still pending (or was dismissed) and the link is dropped; the panel says so rather than dropping it silently. A dependency on a suggestion you accepted a moment ago is followed to the real task it became.

Who gets proposed

The model never sees your analysts. No name, login or skill profile is part of what is sent to the AI backend. The model's part is to tag each suggestion with the skills it needs, chosen from your skill catalog; the server does the rest:

  1. Candidates are the active, human users with full access to the case. Read-only users, service accounts, disabled accounts and people without access to the case are never candidates — a task assigned to someone who cannot open the case helps nobody.
  2. The candidate whose skills overlap the task's skills the most is proposed. Ties go to whoever holds fewer open tasks on this case, so the suggestions spread work instead of stacking it on one person.
  3. When nobody's skills overlap, nobody is proposed and the picker defaults to you, the analyst accepting. You can always choose anyone in the list, or Unassigned.

The proposal is worked out each time the panel opens, not stored with the suggestions, so it reflects today's access and today's skill profiles. If every suggestion comes back without a proposal, the usual reason is that nobody on the case has skills recorded yet — see Analyst Skills and Teams.

What the model is given, and what it is trusted with

The request carries the same case context as the case chat — notes, timeline (honouring event verdicts), IOCs, assets, evidence — plus the case's existing tasks with their ids, status and links, and the list of skill slugs it may use.

The answer is treated as untrusted. Before anything is shown, the server drops:

  • a suggestion that duplicates an existing task — open or closed — or another suggestion (titles are compared ignoring case, punctuation and spacing);
  • skills that are not in your catalog;
  • a dependency on a task that does not exist in this case, on itself, or one that would close a loop;
  • anything past the eighth suggestion.

A reply that is not the expected JSON is an error, and is never stored. Hosted models and organisational AI gateways sometimes answer security content with prose — a refusal, a policy notice, an authentication error. If that were read leniently it would surface as "no tasks needed", which is a claim about the case that nobody made. The panel shows the failure and what the backend said instead. An empty list from a model that answered properly is a different thing and is accepted: it looked, and found nothing to add.

Caching

The suggester runs when you open the panel for the first time on a case, and when you press Regenerate. Otherwise the panel shows the stored run immediately:

  • the key is the model, the prompt and the case content — no clock value, so reopening the panel an hour later is still a cache hit;
  • when the case has changed since the run, a notice says so and Regenerate takes the new data into account;
  • suggestions that have since become tasks are withheld from a stored run, so accepting three of five and coming back tomorrow shows the remaining two.

The surface has its own row — Task suggester (Tasks tab) — in the per-feature backend overrides on /manage/settingsAI, so it can be pinned to either backend slot. See AI Features.

Permissions

Action Needs
Open the panel, read a stored run Read access to the case
Generate or regenerate Full access to the case
Accept suggestions Full access to the case

No new permission is introduced; the case's existing access levels decide.

API

All under /api/v2/cases/<cid>/ai/. Session POSTs carry csrf_token in the JSON body.

Method Path Purpose
GET /task-suggestions The newest stored run, assignees ranked live. 404 when the suggester has never run for the case
POST /task-suggestions Generate. 202 {task_id} — poll /api/v2/ai/jobs/<task_id> for result. ?sync=true runs inline; ?force=true bypasses the cache
POST /task-suggestions/accept Create tasks and links from the accepted suggestions

A run looks like this:

{
  "suggestions": [
    {
      "ref": "S1",
      "title": "Eradicate the webshells and restore the modified core files",
      "description": "",
      "rationale": "Eight core files failed the integrity check and several webshells were deployed.",
      "priority": "high",
      "skills": ["malware-static", "linux-forensics"],
      "depends_on": [{"ref": "T12", "kind": "task", "task_id": 12, "title": "Collect artifacts"}],
      "assignee": {"user_id": 7, "user_name": "", "matched_skills": ["linux-forensics"]}
    }
  ],
  "assignable_users": [{"user_id": 7, "user_name": "", "skills": [""], "open_tasks": 1}],
  "withheld_now_tasks": 0,
  "stale": false,
  "cached": true,
  "model": "",
  "prompt_id": "TaskSuggesterSystemPrompt-v1",
  "generated_at": ""
}

assignee is null when no candidate's skills overlap. stale is true when the case changed since the run, false when it did not, and null when that could not be determined because no AI backend is configured — unknown is not the same as unchanged.

The accept body lists what to create, as the analyst left it:

{
  "tasks": [
    {"ref": "S1", "title": "", "description": "", "assignee_id": 7, "depends_on": ["T12"]},
    {"ref": "S2", "title": "", "description": "", "assignee_id": null, "depends_on": ["S1"]}
  ],
  "csrf_token": ""
}

and the answer reports each item separately — one bad item never blocks the others:

{
  "created": [{"ref": "S1", "task_id": 140, "title": "", "assignee_id": 7}],
  "failed": [{"ref": "S3", "error": "assignee cannot work this case"}],
  "links_created": 2,
  "links_dropped": [{"ref": "S5", "depends_on": "S9", "reason": "that suggestion was not accepted"}]
}

What the accept endpoint refuses, per item: a title shorter than two characters, a title the case already has a task for, and an assignee who is not among the case's assignable users. A batch is at most eight items; an empty batch is a 400.

Key files

File Role
source/app/iris_engine/ai/task_suggester.py Payload, validation, assignee ranking, cache
source/app/resources/ai_prompts/task_suggester.md System prompt
source/app/business/task_suggestions.py Accept: tasks through tasks_create, links, per-item results
source/app/blueprints/rest/v2/cases/ai.py The three endpoints
source/app/blueprints/pages/case/templates/modal_task_suggestions.html The review panel

Clone this wiki locally