← All ivy-agents
IVYXSTUDIO · IVY AGENT
I

Inbox Triage

ivy.agent.inbox-triage · v1.1.0

ivyx

Reads the unread mail of an inbox, has a model sort each message into urgent, finance, newsletter, personal or other with a one-line note, and writes the result as a table.

Steps

In the order the agent's file lists them, each with where its inputs come from and the values the file fixes. A branch or a loop is a step too.

  1. 01
    Read the unread mail
    ivy.node.mail-fetch

    Reads the newest messages of a mailbox folder that match a query over IMAP and returns each one's sender, subject, date and plain text, newest first.

    takes
    username from the agent's input
    query from the agent's input
    limit from the agent's input
    imap_host from the agent's input
    imap_port from the agent's input
    use_ssl from the agent's input
    set
    imap_host imap.gmail.com
    imap_port 993
    use_ssl true
    query unseen
    limit 20
    secret
    mail_password the stored secret mail-password
    Ivy Node
  2. 02
    Sort each message

    Sort every message in the context into one category: urgent (needs action today: an outage, a deadline, a request from a customer that cannot wait), finance (an invoice, a receipt, a payment, a bill), newsletter (a bulk mailing or announcement), personal (a note from a person about something that is not work), or other. Return one row per message with uid (copied exactly from the message), from, subject (copied), category and note (one short sentence saying what the message asks or tells). Use only what the messages say; do not leave any message out.

    takes
    context from step 1, messages
    Model turn
  3. 03
    Check each row
    ivy.node.rows-validate

    Checks every row against a JSON Schema and splits the rows into valid ones and invalid ones with their problems.

    takes
    rows from step 2, output.rows
    set
    schema {"type":"object","required":["uid","subject","category","note"],"properties":{"uid":{"type":"string","minLength":1},"...
    returns
    rows, rejected
    Ivy Node
  4. 04
    Lay out the table
    ivy.node.markdown-table

    Formats rows as a Markdown table, with the columns in the order given or as they first appear.

    takes
    rows from step 3, valid_rows
    set
    columns ["category","from","subject","note"]
    returns
    count, markdown
    Ivy Node
  5. 05
    Write the table
    ivy.node.file-write

    Writes text to a file, creating its folder, and returns the absolute path and the number of bytes written.

    takes
    text from step 4, markdown
    set
    path reports/inbox-triage.md
    overwrite true
    returns
    path
    Ivy Node

Nodes it brings

Adding this agent in IVYX Studio adds these nodes with it. A node your workspace already has is kept as it is, even at another version.

What it touches

Collected from what each of its nodes declares, plus the model call when a step is a model turn. A declaration is the author's statement, and it is what policy rules select on.

Writes filesCalls a modelmessage-readNetwork

What it needs

  • A stored secret named mail-password. The agent's file carries the name, never the value.

Inputs

FieldTypeDescription
usernamerequiredstringThe mailbox address, which is the login name; its password is the stored secret mail-password.
querystringWhich mail to read: unseen, since:<days>, from:<name>, subject:<word>, joined with spaces.
limitintegerAt most this many messages, the newest.
imap_hoststringThe IMAP server; imap.gmail.com when left out.
imap_portintegerThe IMAP port; 993 when left out.
use_sslbooleanConnect to IMAP over SSL; on when left out.

Outputs

FieldTypeDescription
rowsarrayOne row per message: uid, from, subject, category and note.
countintegerHow many messages were sorted.
rejectedintegerHow many of the model's rows lacked a field.
markdownstringThe table that was written.
pathstringThe file the table was written to.

Tests

2 of 2 test cases passed on Oct 7, 2026, in the publisher's own environment, before this version was published. The registry keeps that record; it does not run the cases again.

Requires: python:3.9, a mailbox over IMAP (Gmail unless imap_host says otherwise) with its password stored as the secret mail-password, for the cases, GreenMail on 127.0.0.1:3143/3025 (mkdata-mail.py), a model core, the eight [ivyx-test] messages of mkdata-mail.py, unread

  • eight-unread

    Eight unread test messages: the outage and the full disk are urgent, the three receipts are finance.

    given
    imap_host 127.0.0.1
    imap_port 3143
    use_ssl false
    username agent@ivyx.test
    query unseen subject:[ivyx-test]
    limit 20
    expects
    count equals 8
    rejected equals 0
    markdown matches urgent[^\n]*(checkout|disk)[\s\S]*urgent[^\n]*(checkout|disk)
    path matches reports/inbox-triage\.md$
  • receipts-only

    A narrower query sorts only the mail it names.

    given
    imap_host 127.0.0.1
    imap_port 3143
    use_ssl false
    username agent@ivyx.test
    query unseen subject:[ivyx-test] subject:receipt
    limit 20
    expects
    count equals 2
    markdown matches finance[\s\S]*finance