)]}'
{
  "log": [
    {
      "commit": "6e764b07934d3b4d5ebad381453978684f922d96",
      "tree": "5262976bedd7eb2fc0ba12251819f0d2f3745259",
      "parents": [
        "7e1fd7a403336c5048b47b7c66539361bf0e1a3e"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Jul 20 08:56:06 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Jul 20 08:56:06 2026 +0200"
      },
      "message": "process-mbox: recreate the \u0027on ... \u003cauthor\u003e wrote:\u0027 line\n\nI often drop it by accident before responding, so let\u0027s recreate one\nfrom the message\u0027s headers.\n"
    },
    {
      "commit": "7e1fd7a403336c5048b47b7c66539361bf0e1a3e",
      "tree": "fecd5eea179aac11c50e79723245876622d7d475",
      "parents": [
        "405f0d9db9d2bbe2b1941ea45c960b59e5d825d4"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Jul 20 08:18:54 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Jul 20 08:18:54 2026 +0200"
      },
      "message": "process-mbox: add a line about email clients\n\nToo many messages continue to arrive with mangled spaces/tabs, let\u0027s\nadd a sentence about this.\n"
    },
    {
      "commit": "405f0d9db9d2bbe2b1941ea45c960b59e5d825d4",
      "tree": "4a6346d58fd4e6b32979d03dfb43d4e0acec7d48",
      "parents": [
        "22e6d277efe542d7d23f294618f1e5caf682384f"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:08:41 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:08:41 2026 +0200"
      },
      "message": "process-mbox: also request to CC maintainers\n\nSince it was manually added for more than half of the messages, let\u0027s\nadd it there too.\n"
    },
    {
      "commit": "22e6d277efe542d7d23f294618f1e5caf682384f",
      "tree": "adc635bda7761dcfb24c3c98eecf96b5fd9eae30",
      "parents": [
        "03c16573fc1e4d4a778567e558d232129143d2ee"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun May 31 06:08:40 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "append-lines: add -h to print a short usage summary\n\nA -h option prints one line per option to stdout and exits, sharing the\ntext with the error path (print_usage). The print_usage() function now\ntakes a return code so that -h is not an error.\n"
    },
    {
      "commit": "03c16573fc1e4d4a778567e558d232129143d2ee",
      "tree": "a07965b375756a61a043e02c735fbd12efc55899",
      "parents": [
        "d8206d0375579d5d381f256a17b2a5966e250fcf"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun May 31 09:41:06 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "append-lines: parse options in a single switch/case loop\n\nThe option handling validated arguments with a chain of strcmp() on argv\nand a separate scan for -h. Replace it with one cleaner switch/case loop.\n"
    },
    {
      "commit": "d8206d0375579d5d381f256a17b2a5966e250fcf",
      "tree": "75bd2dd49bcb9c7e09ba40fb73348dacc9d2e532",
      "parents": [
        "e6391569f8960d43d57bb3d1a76136311f9c4f8c"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun May 31 09:31:33 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: print usage message when getting -h\n\nIt was lacking a bit.\n"
    },
    {
      "commit": "e6391569f8960d43d57bb3d1a76136311f9c4f8c",
      "tree": "5f0f473b24b28ce892bbeceb07f839360f4cb510",
      "parents": [
        "b606f72ce8e93e0b3610f8aeb6381b14e0ad7217"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun May 31 09:30:32 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: add -q to quote the kept body\n\n-q prefixes each line of the produced body with \u0027\u003e \u0027 or a bare \u0027\u003e\u0027 for\nempty lines. Quoting is done here, where the body is generated, so the\nprefix bytes are counted into the reported length and the Content-Length\nstays exact with no extra plumbing. This way the user can easily just\ndrop a level of indent in the whole message using vertical selection\nwhen replying and have the text properly formatted to split the original\nmessage from the added parts.\n"
    },
    {
      "commit": "b606f72ce8e93e0b3610f8aeb6381b14e0ad7217",
      "tree": "ebe05d37bc0af431d043f4ad6efd7bfb3c73bf71",
      "parents": [
        "1dcd2004d75a66932ac46063781662cc825ef80d"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 23:36:47 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: walk multipart parts recursively\n\nReplace the flat part loop with its manual boundary stack by a recursive\nwalk_level(): each level processes its parts, recurses into nested\nmultipart wrappers, and emits the first text/plain leaf found in the\nsubtree. The boundary array is allocated once in process_mbox() and\npassed down with the current depth; a level reports the boundary it\nstopped at so an ancestor delimiter unwinds cleanly. Part-header parsing\nmoves into read_part_hdrs(). This removes the inline nested-multipart\nsub-block that pushed a boundary mid-header-read and flattened recursion\nonto the stack.\n"
    },
    {
      "commit": "1dcd2004d75a66932ac46063781662cc825ef80d",
      "tree": "acd33d27f5572fdecc5dfa3af9a695614c5acf5d",
      "parents": [
        "85f12e299010a0162fe3f653d7606d229350a5a1"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 23:10:10 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: fix closing-delimiter detection in multipart parsing\n\nFor now we didn\u0027t check that when processing multipart, the closing\nboundary properly ended with \"--\", and we only compared with the opening\none. It could leave ambiguities for variable length boundaries if a second\nlevel reuses the same beginning as the previous one for example, as it\ncould be mistaken for a closure. Let\u0027s move all this to a function\n\"is_close_delim()\" which properly checks all of this.\n"
    },
    {
      "commit": "85f12e299010a0162fe3f653d7606d229350a5a1",
      "tree": "a03fd5c79cd9e20f0ed87447b41e02797461860a",
      "parents": [
        "6d63985f229172206165dcc5244e3c1550e233d0"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 22:14:20 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: extract leaf body emission into dump_leaf()\n\nLet\u0027s continue to deduplicate code. Now it\u0027s the loop that handles the\n\"leaf\" body part (base64/quoted-printable/raw, counting produced bytes,\nstopping at a boundary or Content-Length exhaustion). We move it from\nprocess_mbox() into dump_leaf(). It takes the boundary array and the\ncurrent level explicitly, preparing for upcoming recursive multipart\nprocessing. Aside this, the code only moved, but didn\u0027t really change.\n"
    },
    {
      "commit": "6d63985f229172206165dcc5244e3c1550e233d0",
      "tree": "2d5c71b33d0a62b6ba1182ef9b50f2bca1b80943",
      "parents": [
        "c8ad0f50cb593c89f578e0c011c9ec1baf8a5039"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 21:53:11 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: centralize MIME boundary detection in boundary_level()\n\nThree places were scanning the boundary stack to decide whether a line is\na known MIME delimiter, two of them duplicating the same \"--\" check plus\nthe loop over boundaries. Move this into boundary_level(), which returns\nthe deepest matching level (or -1). The main part loop now uses the\nreturned level to unwind the stack.\n"
    },
    {
      "commit": "c8ad0f50cb593c89f578e0c011c9ec1baf8a5039",
      "tree": "86e6e96d8896085498c5a16fb470e27eaa4598ac",
      "parents": [
        "98612ee2c36c814373444941410662a9d11bfeb2"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 21:52:16 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: centralize Content-Length accounting in consume()\n\nWhen calculating content-length, we\u0027re repeating many times the pattern\n\"if (clen \u003e\u003d 0) clen -\u003d strlen(line)\". Let\u0027s move it into single consume()\nand use that one everywhere instead.\n"
    },
    {
      "commit": "98612ee2c36c814373444941410662a9d11bfeb2",
      "tree": "a4ed4cfc1898291339a84c1e0f9a5f6699f0f3d1",
      "parents": [
        "14fa4e1de4ca055b0d2f34ea640c6057d5c0c1ab"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Jun 09 13:09:51 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "process-mbox: pass content-length between textonly and append2lines\n\nin sec-process we now call textonly with -w to store the computed\ncontent-length into msg.mbox.clen, and in process-mbox we detect the\npresence of that file, and if found, we pass it to append-lines which\nwill automatically update it from the amount of inserted data and emit\nit so that the output is correct.\n"
    },
    {
      "commit": "14fa4e1de4ca055b0d2f34ea640c6057d5c0c1ab",
      "tree": "280e655e8f136c74cac7637b504478d4673bbea7",
      "parents": [
        "563df873513e45717e8fc1c443f209ebb4e26096"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 17:05:40 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "append-lines: re-introduce an accurate Content-Length header\n\nThe mbox post-processing pipeline used to delete Content-Length entirely\nbecause the body size changes between stages. Now append-lines can put a\ncorrect one back: with -L \u003cbase\u003e it takes the upstream body length and\nadds the bytes its own -B lines contribute, dropping any stale\nContent-Length and emitting the computed value at the end of the header\nblock. Without -L it emits none (mutt recovers fine).\n\nOnly the first message is annotated, so a \"From \" line inlined in the\nbody (e.g. a pasted patch) can no longer trigger a spurious second\ninsertion. process-mbox.sh passes the length saved by textonly.\n"
    },
    {
      "commit": "563df873513e45717e8fc1c443f209ebb4e26096",
      "tree": "84797897ead0d9a99ec5a6461e23333561d100df",
      "parents": [
        "e30b283e293884a20d657a3df7796788e54bbb56"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Jun 09 13:31:38 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "append-lines: cleanup leftover trailing spaces in code\n\nDrop various spaces left at the end of lines, which happens after using\nan unconfigured editor with broken auto-indent on by default.\n"
    },
    {
      "commit": "e30b283e293884a20d657a3df7796788e54bbb56",
      "tree": "c5690efd50ad4437da817c2d9a0287d4f2d9b200",
      "parents": [
        "47549a6a9b50aee6c725e50377ad883fd441c9f2"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 18:28:31 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: emit the produced body length for Content-Length recomputation\n\nAdding \"-w \u003cfile\u003e\" emits the computed resulting content-length once the\nmessage has been entirely sent. The body bytes really produced are\ncounted and the total written to the designated file. The message body\noutput now goes through put_body_str()/put_body_ch() which adapt to the\nrequested behavior: without -w nothing is written, so textonly stays a\nplain filter usable on large mailboxes.\n"
    },
    {
      "commit": "47549a6a9b50aee6c725e50377ad883fd441c9f2",
      "tree": "f2ff8eb5e0074e4f0bce03a1c5b7a541ea2fdeda",
      "parents": [
        "90130e9059cb72f093caa933a0928381a97cbbcf"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sat May 30 18:27:26 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Jun 10 10:01:04 2026 +0200"
      },
      "message": "textonly: respect the Content-Length header to delimit the message body\n\nMessage boundaries were found only by the mbox \"From \" line, which is\nunreliable: an inlined patch or a quoted mail can contain a line\nstarting with \"From \" and would prematurely cut the message. While the\nquoted message was deliberately ignored first as rare, the inline patch\nregularly causes problems, with changes happening a second time there.\n\nWhen a Content-Length header is present it is authoritative, so keep its\nvalue in a counter, decrement it by each consumed body line, and stop\nonce it reaches zero; \"From \" detection (body_done()) is kept only as the\nfallback for messages that have no Content-Length. The parsing stays a\nplain byte stream, no buffering or allocation.\n\nThe Content-Length is still dropped from the output (the body we emit,\nafter dropping attachments and decoding, has a different size) since\nwe\u0027re processing it as a stream, we can\u0027t roll back to the headers area.\nA future patch will permit to save it into an extra file.\n"
    },
    {
      "commit": "90130e9059cb72f093caa933a0928381a97cbbcf",
      "tree": "41e6933873509457d287fc979c8b0c1a41a233e5",
      "parents": [
        "78f59101eb9aa0ee8e34cd2fbf52ad4081455a78"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 09:29:17 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 09:29:17 2026 +0200"
      },
      "message": "textonly: decode quoted-printable\n\nQuoted-printable prepends non-printable chars with \"\u003d\" followed by their\nhex code. It supports soft-breaking of lines by placing a lone \"\u003d\" at the\nend of a line. Let\u0027s decode this for main part and subparts.\n"
    },
    {
      "commit": "78f59101eb9aa0ee8e34cd2fbf52ad4081455a78",
      "tree": "defd671f2588af902c4e96abf862b756d194627e",
      "parents": [
        "04ed8c28665f8fc5aa9e25908b5429c76d785269"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 09:14:41 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 09:28:30 2026 +0200"
      },
      "message": "textonly: don\u0027t merge successive lines in plain text\n\nWe only need to read multiple lines when reading headers, but not plain\ntext. This was causing some lines to be truncated in code (which often\nstarts with spaces/tabs).\n"
    },
    {
      "commit": "04ed8c28665f8fc5aa9e25908b5429c76d785269",
      "tree": "0c314d263d1993ae533642119657b60e16b5ae0b",
      "parents": [
        "661719d40aa936f164c072c9a2d3c93a464f016e"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:44:02 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:45:31 2026 +0200"
      },
      "message": "textonly: clean up the base64 decoder\n\nLet\u0027s put the decoder into its own function. It counts input bytes and\noutput bits. Note that the state (bits and bytes) could even be stored\nin the upper bits of the current word (5 bits for #bits and 2 bits for\n #bytes) but that\u0027s pointless here, so let\u0027s stay simple. At least now\nwe can ignore non-base64 chars so the converter is more robust (may\nskip spaces/tabs/cr/lf for example).\n"
    },
    {
      "commit": "661719d40aa936f164c072c9a2d3c93a464f016e",
      "tree": "f977fcba38a3720ac2707da4b877cf45354de70c",
      "parents": [
        "16ce4c230d235cb1254342ad2196591ddd1b777d"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:13:46 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:13:46 2026 +0200"
      },
      "message": "textonly: do not forget to add 6 bits for \u0027/\u0027 in base64\n\nThe base64 decoder forgot to add 6 bits of output for \u0027/\u0027 (63), resulting\nin a few missing chars (e.g. \u0027?\u0027 at the end of a 3-bytes block).\n"
    },
    {
      "commit": "16ce4c230d235cb1254342ad2196591ddd1b777d",
      "tree": "2feebd45dc9bc9413c13e0c0803865bd81b722e9",
      "parents": [
        "205474bf355a836d5e69147d6ecf2574d575d24f"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:12:44 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Apr 05 08:12:44 2026 +0200"
      },
      "message": "textonly: include ctype.h for tolower\n\nCommit 222b2ec (\"textonly: get rid of strncasecmp() to support building\nwith nolibc\") broke the build by including tolower without ctype.\n"
    },
    {
      "commit": "205474bf355a836d5e69147d6ecf2574d575d24f",
      "tree": "ae29175d99865dd7ea6e0b624fa1173bfe5704b6",
      "parents": [
        "6129efbe5c909dd6239139d6a6a0d585264248a7"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 06:12:34 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 06:12:34 2026 +0200"
      },
      "message": "process-mbox: move all user-editable lines to the top\n\nIt appears that grouping all questions together is easier to edit,\nas it allows to quickly delete all meta-data at once when finished.\n"
    },
    {
      "commit": "6129efbe5c909dd6239139d6a6a0d585264248a7",
      "tree": "c2df38e1a0e6690148d96abb4a0c02dbc0cf2f08",
      "parents": [
        "9ff2bb56714e257528fc05f28d96c2cb96a2eaee"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 06:04:05 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 06:11:53 2026 +0200"
      },
      "message": "process-mbox: automatically ask for kernel version if not found\n\nThe version extraction seems reliable enough so that we can automatically\nadd a request for version when not found.\n"
    },
    {
      "commit": "9ff2bb56714e257528fc05f28d96c2cb96a2eaee",
      "tree": "5f466e83da85bd1d33cbedb3690063ecff43fb28",
      "parents": [
        "9dea54a1b6f39c110d24e292087350fa35d31ccf"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:43:48 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:54:40 2026 +0200"
      },
      "message": "process-mbox: ask for all meta-data in the initial instructions\n\nInstruction-based models handle complex instructions well, so it\u0027s\nmore efficient to ask them to produce all meta-data at once in a single\ncall, as we\u0027re saving on python calls. Let\u0027s see if smaller models are\nfine with this as well, otherwise we\u0027ll revert.\n"
    },
    {
      "commit": "9dea54a1b6f39c110d24e292087350fa35d31ccf",
      "tree": "148c850fe4ddefecefc1fde6b0d0a1c14cd46a75",
      "parents": [
        "03d93d1ffb37ee3ba60209d282414e413d5b120e"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:53:56 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:54:40 2026 +0200"
      },
      "message": "process-mbox: also emit the affected function(s) on its own line\n\nNow that we possibly have them in the extracted meta-data, let\u0027s dump\nthem.\n"
    },
    {
      "commit": "03d93d1ffb37ee3ba60209d282414e413d5b120e",
      "tree": "b63f3147d5d5767cec11bd049c21e9d8467aeeb8",
      "parents": [
        "f4e7b96648213f4fcd7283e8cc7fcb4937b676d3"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:40:27 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:40:27 2026 +0200"
      },
      "message": "process-mbox: place all variables into a single file\n\nWe already grep for \u0027header\u0027 names in output files, so better merge all\nmeta-data into a single file, this will make it easier to handle and\nallow to mix multiple requests at once. Now the only file is \"$MSG.var\".\n"
    },
    {
      "commit": "f4e7b96648213f4fcd7283e8cc7fcb4937b676d3",
      "tree": "4240091cc45513936b58c70bfbc3a8f246c31833",
      "parents": [
        "d4430203abbb705674842fa830afb087617bb838"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:31:28 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:31:28 2026 +0200"
      },
      "message": "process-mbox: refine instructions to avoid non-ASCII characters in ouput\n\nSome models tend to place emojis in the summary, let\u0027s try to avoid this.\n"
    },
    {
      "commit": "d4430203abbb705674842fa830afb087617bb838",
      "tree": "513f27665b9858220ecc05fa237aa3c27f2c7bd2",
      "parents": [
        "a33375d2cfa7bf6e6a35daf8c648fb864f6a3622"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:25:21 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:25:21 2026 +0200"
      },
      "message": "process-mbox: indent the maintainers list in the output\n\nThe maintainers list was visually difficult to delimit from the rest,\nlet\u0027s indent it.\n"
    },
    {
      "commit": "a33375d2cfa7bf6e6a35daf8c648fb864f6a3622",
      "tree": "9cc806fff3500786bf8a658a6dddba45ff5421d7",
      "parents": [
        "8dcd11c43bed13dee974e557281f1fe2e2a3ed8d"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:16:58 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Wed Apr 01 05:20:23 2026 +0200"
      },
      "message": "process-mbox: also emit a \"Version\" line with the range of affected versions\n\nThe version is often difficult to find in certain reports, and the LLM\ngenerally manages to find it well. Let\u0027s add the information on its own\nline. The output was slightly reformatted to better separate the added\ninfo from the rest of the message.\n"
    },
    {
      "commit": "8dcd11c43bed13dee974e557281f1fe2e2a3ed8d",
      "tree": "b118271cb291ec81b95d8304ef981c8d553a98ec",
      "parents": [
        "127ba243e560ce3dc8770d2fdcf17544e1e9883e"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:56:12 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 16:12:50 2026 +0200"
      },
      "message": "process-mbox: provide a few variants of the welcome message.\n\nSome say we\u0027ve forwarded the original, others say maintainers CCed.\nSame depending on the presence of a patch or not. Also hello is\nadded.\n"
    },
    {
      "commit": "127ba243e560ce3dc8770d2fdcf17544e1e9883e",
      "tree": "86adea5a9ec2e309f9ec939d4c7232ae4dda88dc",
      "parents": [
        "555c23e58a17a867f076de854fdc369999bbc9cb"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:53:57 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 16:10:40 2026 +0200"
      },
      "message": "process-mbox: dump the full maintainers list for easier control\n\nIn order to make sure not to forget anyone, and in an attempt to also\ndeal with files with no immediately identified maintainer, let\u0027s also\nbuild the unified list of maintainers for the set of files presented.\nIf some don\u0027t have any maintainer, we switch to git log. This is dumped\nin a block \"full maintainers list\" that can easily be deleted in the\nmessage\u0027s body.\n\nIt\u0027s also one less call to the LLM and one less possibility to\nhallucinate names (already observed previously).\n"
    },
    {
      "commit": "555c23e58a17a867f076de854fdc369999bbc9cb",
      "tree": "99ecc8ff1f1fb7ea1d018fa16f70c87d1e5ad44b",
      "parents": [
        "e979c46e540739704f2aaa08269e6a4ae996f107"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:45:35 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 16:10:40 2026 +0200"
      },
      "message": "process-mbox: pre-build the Cc list from most specific maintainers\n\nBy tweaking a little bit get_maintainers, we can get the most specific\nlist of maintainers and directly emit the Cc field after deduplicating\nthem. We also keep a copy in $MSG.cc for post-analysis.\n"
    },
    {
      "commit": "e979c46e540739704f2aaa08269e6a4ae996f107",
      "tree": "4abe02d7f5a143037d322445f1a018013715dc0e",
      "parents": [
        "b9ebcef765b057df793863dd2c1d913d1bcae7a9"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:08:55 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 16:05:39 2026 +0200"
      },
      "message": "process-mbox: always output identified file names\n\nSometimes maintainers selection looks suspcious and it then remains\ndifficult to spot affected file names in certain reports. Let\u0027s just\ndump the identified files to permit an easy check.\n"
    },
    {
      "commit": "b9ebcef765b057df793863dd2c1d913d1bcae7a9",
      "tree": "e4e70efd13a5100909e2a5c2a79e07386802cf1f",
      "parents": [
        "c727281fb04fc55365812e475ae86df7848048e3"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:05:17 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Tue Mar 31 15:05:17 2026 +0200"
      },
      "message": "process-mbox: refine file name extraction to eliminate duplicates\n\nWe can sometimes face duplicates in file names output, let\u0027s deal with\nthis and also eliminate the occasional \"n/a\" that can appear when no\nfile could be identified.\n"
    },
    {
      "commit": "c727281fb04fc55365812e475ae86df7848048e3",
      "tree": "679c782bd0c0826289045a41e77f120f7cbde0a4",
      "parents": [
        "b04518374521788023631669e086ad03a850fa44"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 05:17:37 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 05:17:37 2026 +0200"
      },
      "message": "process-mbox: make the agent name configurable\n\nIt was always called \"local\" but this is not convenient for testing other\nvariants, let\u0027s make it configurable via the AGENT variable. Also definitely\nswitch to \"clean\" headers mode, which is particularly important for CPU-only\nmodels.\n"
    },
    {
      "commit": "b04518374521788023631669e086ad03a850fa44",
      "tree": "b7331e45006b45292cd10227a616737b80a74bf7",
      "parents": [
        "1ee2e370a50c524bfdd4ce140c418d99695b7913"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:33:01 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:33:01 2026 +0200"
      },
      "message": "config: add sample sec-process.sh and procmailrc\n\nThese are just samples to ease reuse in local setups.\n"
    },
    {
      "commit": "1ee2e370a50c524bfdd4ce140c418d99695b7913",
      "tree": "7506615b668ed96b4a4c29b54948c2998ce43fe9",
      "parents": [
        "b1ffd6beb1a91e99d30e5906fb3a57cc0ee600c2"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:28:35 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:28:35 2026 +0200"
      },
      "message": "process-mbox: add a script to process an mbox through \"llm\"\n\nThis takes an mbox in argument, and produces several temporary files\nbased both on llm questions and calls to get_maintainers. The calls\nto the LLM are performed via the \"llm\" tool. The kernel directory\ncan be set by the caller via KDIR. An example calling script that\nhandles everything in procmail is the following (sec-process.sh):\n\n  #!/bin/bash\n\n  PROG\u003d\"${BASH_SOURCE[0]}\"\n  PROGS\u003d\"${PROG%/*}\"\n\n  export KDIR\u003d/path/to/kernel/source\n  export PATH\u003d$HOME/.local/bin:$PATH\n\n  die() {\n          echo \"Fatal: $*\"\n          exit 1\n  }\n\n  cd \"$PROGS\" || die \"couldn\u0027t locate script\"\n\n  TMP\u003d\"$(/usr/bin/mktemp -d -p /tmp)\"\n  [ -n \"$TMP\" -a -d \"$TMP/.\" ] || die \"mktemp error\"\n\n  ./textonly \u003e \"$TMP/msg.mbox\"\n  ./process-mbox.sh \"$TMP/msg.mbox\" #2\u003e\"$TMP/msg.mbox.log\"\n  cat \"$TMP/msg.mbox.edited\"\n\nIn .procmailrc it can be called like this:\n\n  :0\n  * ^List-Id:.*security.linux.kernel.org\n  * !^In-Reply-To:\n  {\n      # 1. Create a clone of the message for the following block.\n      :0 c\n      {\n          # 2. apply the filter to this copy.\n          :0 fw\n          | scripts/sec-process.sh\n\n          # 3. Deliver the resulting summarized text to the mbox.\n          :0:\n          mbox\n      }\n  }\n"
    },
    {
      "commit": "b1ffd6beb1a91e99d30e5906fb3a57cc0ee600c2",
      "tree": "8b0a113080ae19c516b309b5c4771833b2549cd8",
      "parents": [
        "222b2ec37f9159c131934e073670682c19acca4b"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:21:06 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:21:06 2026 +0200"
      },
      "message": "textonly: add -c to clean useless headers\n\nA lot of ARC-*, DKIM-*, DMARC-*, Received etc headers are present in the\ninput messages. They\u0027re taking a lot of context space for LLM analysis,\nthey sometimes result in a less accurate analysis, and increase processing\ntime for no added value. Let\u0027s just permit to clean them up using \"-c\". It\nis convenient to do this here because the parser has multi-line knowledge,\ncontrary to grep or anything that could be done later. A test shows that\na 15.5s analysis was brought down to 9s thanks to this!\n"
    },
    {
      "commit": "222b2ec37f9159c131934e073670682c19acca4b",
      "tree": "5508781e5aaf656c0ae144950f97ce9fac4e5f42",
      "parents": [
        "481c5174095e214f673979fc872e63f36731b892"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:09:31 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:09:31 2026 +0200"
      },
      "message": "textonly: get rid of strncasecmp() to support building with nolibc\n\nIt was the only thing preventing from building with nolibc, and it\nturns out that having a portable static binary is convenient over NFS.\n"
    },
    {
      "commit": "481c5174095e214f673979fc872e63f36731b892",
      "tree": "4f7bc4656a107fed5fe136fecc2a598d278bc49b",
      "parents": [
        "62a7484bba9cf41102d2e443aa6c0811c1cb8543"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:01:16 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Mon Mar 30 00:01:16 2026 +0200"
      },
      "message": "textonly: automatically decode base64\n\nSome plain-text attachments are encoded in base64. Since the goal is to\npass the output to an LLM for processing, this will be useless. Let\u0027s\ndetect and decode base64 when found (and delete the content-transfer-encoding\nheader). Note that the implementation is naive and relies on having exactly\nonce space after the header name.\n"
    },
    {
      "commit": "62a7484bba9cf41102d2e443aa6c0811c1cb8543",
      "tree": "a0fc1b40aae886dec35bb6e21cb23adb5b3f102b",
      "parents": [
        "94efd0cf80c41e0b85486e42480330f5c4b57e9e"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 23:21:50 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 23:21:50 2026 +0200"
      },
      "message": "textonly: extract only the plain text part of an e-mail\n\nThe goal here is to detect attachments and when found, only extract the\ntext/plain one with its headers. Content-length and Lines are dropped. A\nspecial case was made for nested attachments (e.g. multipart/alternative)\nwhich would require a cleaner recursive parser, but the current \"hack\"\nconsisting in detecting a second time with a stack gets the job done.\n"
    },
    {
      "commit": "94efd0cf80c41e0b85486e42480330f5c4b57e9e",
      "tree": "52270746effced7686fa366b0571f88b1e719164",
      "parents": [
        "f4db3e04e0c1122ea9be8e9da1a7d04ffcfbd427"
      ],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 16:31:04 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 16:31:04 2026 +0200"
      },
      "message": "append-lines: add utility to append lines in header / body of an e-mail\n\nWith -H we append lines to the header; with -B we insert lines at the\nbeginning of  the body (which must obviously be in plain text and non\nencoded).\n"
    },
    {
      "commit": "f4db3e04e0c1122ea9be8e9da1a7d04ffcfbd427",
      "tree": "4b825dc642cb6eb9a060e54bf8d69288fbee4904",
      "parents": [],
      "author": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 16:24:40 2026 +0200"
      },
      "committer": {
        "name": "Willy Tarreau",
        "email": "w@1wt.eu",
        "time": "Sun Mar 29 16:24:40 2026 +0200"
      },
      "message": "Initial commit\n"
    }
  ]
}
