put(), put_auto(), put_generate(), and put_merge() now default to
recursive = TRUE (previously FALSE). Directory scans now include
subdirectories by default. Pass recursive = FALSE for the old behavior.
(#34)
put_diagram() output now starts with a frontmatter block that keeps
Mermaid 11's drawing on Mermaid 12 renderers that set a theme: GitHub
has drawn Mermaid 12's "neo" look, with labels wrapped at 120px, since
it moved to Mermaid 12.1.0 in October 2026. The block sets the dagre
layout, the classic look, a 200px wrapping width and no minimum node
width; it sets no theme, so the page's light or dark theme still
applies. Mermaid 9.3.0 to 11.17.2 draw the same with or without it. The
new argument mermaid_config takes "classic" (the default), "none"
for the previous output, or a named list written as the configuration.
The title, if any, shares the frontmatter. The MCP put_diagram tool has
the same argument. Mermaid reads the frontmatter only at the very start
of the diagram code, and versions before 9.3.0 not at all: text in front
of it, such as an %%{init}%% line, makes the diagram fail to parse, so
use mermaid_config instead, or "none" for such hosts. (#54)
put_diagram() output now also carries accessibility metadata for
screen readers, right after the flowchart line: accTitle with the
title, if one is given, and accDescr with a summary such as
"Workflow with 4 steps and 3 data files." (.internal variables are
not counted as files). Mermaid puts them into the SVG's <title> and
<desc>; the frontmatter title alone does not (Mermaid 10.5.0 and
later). The title is escaped so that Mermaid shows it as written: like
labels, plus < and %%{, which Mermaid's sanitizer and directive
handling would change. Mermaid reads these lines from 9.1.0 on; for an
older renderer use accessibility = FALSE together with
mermaid_config = "none". The MCP put_diagram tool has the same
argument. ?put_diagram and GUIDE.md now list the Mermaid versions
that putior supports and that its CI tests. A decision node with the id
accDescr is now written as node_accDescr: accDescr{ started an
accDescr block, and the node lost its shape and label. (#50)
With show_artifacts = TRUE, put_diagram() now draws each data hop
once, through the file's node (script --> file --> script). Before, it
also drew a direct edge between the two scripts, so every hop appeared
twice and the diagram had about 1.5 times the edges it needed, which
brings Mermaid's 500-edge limit closer. A script that another script
reads (such as utils.R) has no file node and keeps its direct edge.
artifact_edges = "both" draws the direct edges as before; the MCP
put_diagram tool has the same argument. (#55)
Everything in this section is new since putior 0.1.0. Where an entry says what changed or what happened before, it describes development versions of 0.2.0, not putior 0.1.0.
putior_mcp_server() to expose putior functions as MCP tools for AI assistantsputior_mcp_tools() to get/filter tool definitions for custom MCP integrationsput, put_diagram, put_auto, put_generate, put_merge,
get_comment_prefix, get_supported_extensions, list_supported_languages,
get_detection_patterns, get_diagram_themes, putior_guide, putior_help,
set_putior_log_level, is_valid_put_annotation, split_file_list, ext_to_languageset_putior_log_level is read-only. The put_diagram tool scans a path
and returns the Mermaid code. (#65)put_diagram tool takes a source argument: annotations (the
default) scans with put(), auto draws the workflow that put_auto()
detects, and merge combines both like put_merge(), with
merge_strategy. When a scan finds nothing and R warned (the directory
is empty, no file matches pattern, a file cannot be read), the scan
tools now fail with R's warnings instead of returning [] or empty text:
the warnings never reached the client. When nothing warned,
put_diagram says what is missing for its source: no annotations
(and it suggests source = "auto"), or no file that put_auto() can
analyze. (#73)null gets its default. Before, most
arguments of the scan and diagram tools and of list_supported_languages
then stopped the call with "argument is of length zero".< in a title or label,
a diagram over Mermaid's limits or an invalid annotation went unnoticed.
A tool that warned returns the warnings (at most 20, each cut to 1,000
characters) as a second text item after its unchanged result. For put_diagram they are Mermaid
comment lines, so the diagram still renders when a client joins both
items, and a %%{ in a quoted label cannot act as a directive. An error
lists the warnings raised before it. The MCP server needs mcptools
1.0.0 or later, which passes such a list on; older versions turned it
into "<object>" text.putior_mcp_server() serves only its 16 tools. mcptools' tools for
choosing a running R session (list_r_sessions, select_r_session)
were on as well, so clients saw 18 tools, and a call could run in a
user's live R session instead of the server's own process.type = "http"), the tools scan only the folder given as
root (default: the working directory), with the ACP server's rules,
and replies show the root as <root>; before, a client could scan any
folder the server's R process could read. put_diagram refuses
enable_clicks over HTTP, as its links name files by their path on
the server. A token makes mcptools require the header
Plumber-Shared-Secret: <token>; a server on an address other than a
loopback one refuses to start without one. Without a token, the
server answers only requests addressed to a loopback name (against DNS
rebinding). mcptools' own settings (trusted hosts, shared secret) stay
in force. Before serving, the server tests that mcptools refuses
requests without the token or from an untrusted Host, and does not
start if it does not. Over stdio nothing changes. ?putior_mcp_server describes
the security model. (#111)putior_acp_server() to expose putior as an ACP agent for inter-agent
communication via REST APIputior_acp_manifest() for agent discoveryroot (default: the working
directory) and what lies below it; a path outside it, also through a
symbolic link, is rejected, and a scan skips files that links inside it
lead outside to (a folder with more than 200 such links is refused).
Before, a request could name any absolute path the server's R process
could read. Network and device paths are rejected before the disk is
touched, and messages show the root as <root>. A token makes the
server require Authorization: Bearer <token> on /runs; a server on
an address other than a loopback one refuses to start without one.
Without a token, the server answers only requests addressed to a
loopback name (against DNS rebinding). POST /runs needs
Content-Type: application/json, and a Content-Length over 1 MB is
refused; these checks, the Host and the token come before the request
is handled. Run IDs are 128 random bits from openssl, also without the
uuid package, where they were a timestamp and a counter that another
client could guess. ?putior_acp_server describes the security model.
(#111).. or control characters ends the run with an error; it
used to be replaced by . with a warning in the server log, so the run
scanned the server's working directory. An unquoted ../ path is now
recognized, so it is rejected too instead of being ignored.scan ./R/ read the path as ./R/,
with the space in front, and reported that it does not exist.D:/data,
C:\Users\me), ~/ paths, relative paths such as R/ that exist,
and paths in backticks or curly quotes; punctuation after a path
(./R?) is dropped. A path-like word wins over a quoted word that is
not one (for ./R/ using the 'dark' theme, titled "ETL" for ./R/), a
theme or direction name is never the path, and an apostrophe ("Let's")
is no quote. A lone /, \, ~ or drive in prose is not taken for
the root of a drive or the home directory. A scan with no path in the
request reads the server's root folder and says so; before, an
unrecognized path silently gave the results of another folder. A ..
after a drive (D:..\x) is rejected like any other. (#109)POST /runs failed with "500
Internal Server Error": plumber2's JSON parser turns the request's
input into a data frame, which the request handling did not expect.
The tests had called the handlers directly; a test now sends real
requests to a running server. Responses now give scalars as JSON
scalars ("name": "putior", not ["putior"]), a missing session id
as null, and GET /runs/<run_id> returns a stored run. (#113)< in a
label, ...) come as a second text/plain part of the output; the
server only logged them.# (R, Python, Shell, etc.), -- (SQL, Lua, Haskell),
// (JavaScript, TypeScript, C/C++, Go, Rust, Java, etc.), % (MATLAB, LaTeX)get_comment_prefix(), get_supported_extensions(), ext_to_language()list_supported_languages() to enumerate all supported languagesR/language_registry.R)put_auto() for automatic workflow detection from code analysisput_generate() for generating PUT annotation comments (roxygen2-style)
output = "raw" for programmatic accessput_merge() for combining manual and auto-detected annotations
viridis: Purple-blue-green-yellow (general accessibility)magma: Purple-red-yellow (high contrast, print-friendly)plasma: Purple-pink-orange-yellow (presentations)cividis: Blue-gray-yellow (deuteranopia/protanopia optimized)put_theme() for creating custom color palettes (#39)palette parameter on put_diagram() accepts putior_theme objectsbase theme's style for that node type,
including the text color and the border width (3px for start and end
nodes, 1px for artifacts); earlier development versions dropped the unset
keys and forced a 2px border (#61). If an override changes how light fill
is, set color too, so the label stays readable/* */ and /** */ block comments (#37)* put as line prefix inside block bodies for all //-prefix languagesexclude parameter to put(), put_auto(), put_generate(), and
put_merge() for regex-based file exclusion (#38).wgsl with // comment prefix (#31).FILENAME_MAP (#35).FILENAME_MAP (#36)show_source_info parameter to put_diagram() for displaying source file
information in diagram nodessource_info_style parameter with "inline" and "subgraph" display optionsenable_clicks parameter to put_diagram() for making nodes clickableclick_protocol parameter: "vscode" or "file". The development
version also offered "rstudio", which was removed before release:
RStudio has no URL scheme for opening files, so rstudio:// links did
nothing. click_protocol = "rstudio" now warns and writes file://
links. (#101)vscode://
links, which open that line; file:// links have no line number.logger package integration for debugging annotation parsingset_putior_log_level() for configurationlog_level parameter on core functionsputior_workflow S3 classprint.putior_workflow() for concise workflow summariessummary.putior_workflow() for structured summary informationputior_workflow inherits from data.frame, so code that uses the
result as a data frame keeps workingrun_sandbox() opens an interactive Shiny app for trying PUT
annotations: paste or type annotated code, simulate several files, and see
the workflow diagram update as you edit (needs the shiny package)# ===== File: name.R =====) are read one line at a time,
with any spaces or tabs around them, at least three = and an optional
closing run, so an unclosed marker no longer takes the next file with it
and a name containing = is recognized. When two simulated files have the
same name (ignoring case), both are kept, the later one in a copy_2/
folder, and the status line says so; so does text before the first marker,
which is ignored. File names are made safe to write on Windows (trailing
dots dropped, characters such as : or ? replaced), and a file that still
cannot be written is left out with a note instead of emptying the whole
diagram (#53)node_type values across vignettes and reference (#40)inst/cheatsheet/putior-cheatsheet.qmd)inst/examples/putior_guide() and putior_help() for in-session referencegetting-started is replaced by quick-start and
annotation-guideput_diagram() checks direction: it takes "TD", "TB", "LR",
"BT" or "RL" (or an unambiguous abbreviation, such as "L"), and
other values give an error. 0.1.0 wrote any value into the diagram,
which Mermaid then could not parse.put_diagram() warns when a diagram is over Mermaid's default limits
of 500 edges (maxEdges) or 50,000 characters (maxTextSize).
Renderers such as GitHub, GitLab and Quarto then show an error or an
empty placeholder, and the diagram cannot raise either limit itself.
The size is counted as mermaid.render() counts it (without the
frontmatter and comments, with the newline that ends a code block), and
the Mermaid check confirms both limits at the boundary. Hosts that use
mermaid.run(), such as pkgdown sites, count up to a few characters
less, so the warning there can come a little early, never late. The
warning names the options; ?put_diagram and the troubleshooting
vignette describe both limits. Large diagrams are also much faster to
generate: a 500-step chain took about two minutes, because every input
looked through every step's outputs, and now takes about two seconds.
(#56)output parameter across put_diagram(), put_generate(), and
putior_guide() -- all now support "raw"|) in node labels breaking Mermaid diagram parsing.
Pipes are now escaped using the #124; entity. (#33)put() now gives annotations without an id a fallback id (node_1,
node_2, ...) when the uuid package is not installed. Before, such
annotations had no id: if none had one, put_diagram() failed with a
misleading "missing required column(s): id" error, and if only some had
one, it silently dropped the others. This broke the quick-start example and
the sandbox templates for anyone without uuid. The sandbox now also shows
diagram errors in its status line instead of a blank preview. (#58)label:"Don't panic" and label:'Say "hi"' keep their labels. Before,
put() dropped any value with a quote character in it, without a warning,
and the node showed its id instead; the troubleshooting vignette even
recommended label:"Load 'raw' data". There are still no escapes, so a
value cannot contain its own kind of quote, and backslashes in Windows
paths stay as they are. A property that put() cannot read is now named
in its validation warning (with validate = TRUE, the default) instead
of being dropped silently, and is_valid_put_annotation() returns
FALSE for such a line. An annotation that ends with a continuation \
(without a comma before it) on the last line of the file no longer loses
its last property. put_generate() wraps a value that contains a double quote
in single quotes, so that put() reads its suggestions back unchanged.
(#91)put() help
page, the vignettes and the cheatsheet have always shown
(# put id:"a", label:"Load" # first step). Before, the comment made
the last property unreadable, and it was dropped. Outside quotes,
whitespace followed by #, --, // or % after a value starts the
comment. In a multiline annotation, a comment may also come before the
continuation \ of a line. (#91)put_diagram() gives every node one Mermaid id and uses it in the node
definition, edges, class lines and click directives. Before, edges to an
artifact whose path has two punctuation characters in a row (such as
./raw data (v2).csv) used a different id than the artifact node, so
Mermaid drew an extra unlabeled node and left the artifact unconnected.
Annotation ids that differ only in punctuation (a-b and a_b) were
merged into one node with a self-loop; they now stay two nodes (a_b,
a_b_2) and put_diagram() warns. Two data files whose names differ only
in punctuation get two artifact nodes. put_auto() and put_generate(),
which derive ids from file names, now give files that would share an id
(a-b.R and a_b.R, end.R and node_end.R, or load.R in two
folders) distinct ids (load, load_2). put_generate(output = "file")
now writes each annotation next to the file it belongs to; when a file in
between gave no annotation, the next one went into the wrong .put file.
(#46)end, graph, flowchart,
subgraph, style, class, classDef, click, linkStyle, call,
href, interpolate, and the link targets _self, _blank, _parent,
_top) made the whole diagram fail to parse. They are now written as
node_end and so on. id:"end" is a natural name for a
pipeline's last step. (#45)show_files = TRUE, edge labels are now quoted and escaped like node
labels (-->|"raw data (v2).csv"|). A file name with parentheses or other
special characters made the diagram fail to parse. (#45)title of put_diagram() is now written as a quoted YAML string.
A title with : (such as "ETL: stage 1") made the diagram fail to
parse, and text after # was dropped as a YAML comment. (#45)# in a label that Mermaid would read as a character entity is now
escaped as #35;. Mermaid decodes #<name>; and #<digits>;, so a label
such as Step #35; was shown as Step #. A plain # (C#, item #1)
is left alone. ?put_diagram now describes how labels and ids are
written. (#45)direction, whitespace and
TB, BT, RL or LR (and TD from Mermaid 11.17.2 on), as in
"Change direction LR to TB", as a direction statement and dropped it:
the node lost its label, and with source_info_style = "subgraph" a file
named direction LR.R made the diagram fail to parse. That whitespace is
now written as an entity (direction#32;LR). The same rule spans line
breaks, so an edge to an id ending in direction (wind_direction)
followed by an edge from an id starting with LR (LR_prep) lost both
edges; such an edge now ends with ;. On a line where style or
classDef comes before it, in the label or in the node id, a :
followed by an escaped character, as in style:"bold" (written
style:#quot;bold#quot;), is now written as #58;: Mermaid removed the
last ; of such a line and showed style:"bold#quot. (#89)%%{ in a node, edge or subgraph label is now written with its first
% as #37;, so that Mermaid shows it as written. Mermaid removes
%%{...}%% directives from the whole diagram text before it parses it,
so a label such as "Budget 50%%{x: draft" was cut short or made the
diagram fail to parse, and with a later }%% the text in between was
lost. put_diagram() now also warns when the title contains a <:
the drawn title then shows HTML entities such as <, > and
& and drops text that looks like an HTML tag, and no escape avoids
that. The accTitle line shows the title as written. (#98)%% made the diagram fail to parse: Mermaid removes comment lines
with a JavaScript regex that treats these characters as line ends. They
are now written as spaces, as line breaks are. The title, the accTitle
line and click tooltips already replaced them, except in the C locale;
they now do so there too. (#104)put_diagram() now warns when a drawn label contains a < before a
letter, /, ! or ?, such as n<threshold or <draft>: Mermaid
draws labels as HTML and reads it as the start of a tag, so the text up
to the next > disappears (a<b and c>d shows "ad"). The docs show
< for a < that should show (\lt in $$...$$ math). The tags
br, b, i, em, strong, sub, sup, code and span still
count as intended HTML. (#102)name instead of id in examples1:nrow() loops with seq_len(nrow()) to handle empty data framesThese entries fix features that were not in putior 0.1.0, or checks added while 0.2.0 was developed. They matter only to users of a development version.
putior_skills() to putior_guide(). The function, its MCP tool
(putior_guide), and its ACP operation (guide) all use the new name.
putior_help("skills") still works as an alias for backward compatibility.
The inst file was renamed from SKILLS.md to GUIDE.md, and the vignette
from skills.Rmd to ai-integration.Rmd.put_diagram() and the MCP and ACP servers accept direction = "TB",
Mermaid's synonym for "TD". GUIDE.md named TB as the default, but
"TB" was rejected with an error. (#79)enable_clicks = TRUE) now use the path the scan recorded
(file_path) instead of the file's base name, which was resolved against
the working directory at the time the diagram was made. Absolute Unix
paths give vscode://file/home/... and file:///home/... instead of a
doubled or quadrupled slash, UNC paths (//server/share/...) give
vscode://file//server/... and file://server/..., and a relative path
to a missing file is made absolute. Paths are percent-encoded, and
tooltips escaped like labels: a quote in a file name made the diagram
fail to parse, and a name such as direction LR.R made Mermaid drop the
click line. The docs now say that Mermaid keeps click links only with
securityLevel: "loose", so they do not work on GitHub, GitLab or in
Quarto with default settings. The pkgdown site and the sandbox stay
"strict", because "loose" would also let click callbacks run
JavaScript. (#47)show_source_info = TRUE using <small> HTML tags that are unsupported
by GitHub's Mermaid renderer. Source file names are now shown without HTML
formatting tags. (#32)putior.log_level option,
set by set_putior_log_level() or for one call by the log_level argument,
is now the only threshold, and an invalid log_level is an error. With
logger installed, WARN-level messages now appear on stderr next to the
matching R warnings. (#70)/* put ... */) silently
losing their last property, which could drop an output and its edge.
(#72)put_merge() no longer merges a manual annotation and an auto-detected
file into one node when their ids meet: auto-detected rows get a suffix
when their id (also in its Mermaid form, where 1 is node_1) is already
used, so an unannotated node_1.R next to an annotation with the fallback
id node_1 stays separate. It also matches manual and auto-detected rows
by file path, so an annotated x/load.R no longer hides an unannotated
y/load.R, and with merge_strategy = "supplement" or "union" no
longer takes the inputs and outputs detected in the other file. (#74)source_info_style = "subgraph", subgraph ids are now file_<name>
and never equal a node id. Before, a file load.R with a node id:"load"
failed to render ("would create a cycle") on Mermaid 11, and on Mermaid 12,
which GitHub uses, the node silently disappeared. Files with the same name
in different folders now get one subgraph each instead of sharing one, and
the subgraph label then includes as much of the folder path as it takes
to tell them apart (x/load.R, a/x/load.R). (#45, #46)put_generate() called with invalid output = "raw" (now supported)put() function for extracting workflow annotations from source code filesput_diagram() function for creating Mermaid flowchart diagramsis_valid_put_annotation() for validating annotation syntaxid field is omitted from annotationsoutput field is omittedname to id for better graph theory alignment