Repository navigation
0.6.0 - 2026-10-23
Release Notes
Files in and out, a check after a lost answer, sessions kept in browser
storage, a gate that reads the request it is about to send, and twelve
languages. A change can name the read that shows it landed, so after a lost
answer itda checks once before anyone is asked to approve again. Reads can save
an attachment, and a change can send a file whose hash you approved. A
single-page app that keeps its session in localStorage now signs in. Setup,
the landing page and the READMEs speak twelve languages, and the mark is a
cursor striking a site.
Added
-
Twelve languages. What
itda setup,itda login,itda refreshand the
first bareitdaprint now comes in English, Korean, Japanese, Simplified
and Traditional Chinese, Spanish, French, German, Brazilian Portuguese,
Vietnamese, Indonesian and Russian, chosen fromITDA_LANGor the system
LANG(ja_JP.UTF-8,zh-TW,ptall resolve). The landing page picks the
browser's language, has a picker in the header and remembers the choice;
the README has one translation per language, linked from a language line at
the top of each. What agents act on (tool descriptions, error codes and
remedies) stays English. The strings live in
apps/cli/text/<tag>.json,site/i18n/<tag>.jsandREADME.<tag>.md;
docs/i18n.mdhas the glossary and the rules. -
Outcome check after a lost answer: a change may name the read that shows
it landed (confirm: {read, match: {pointer, from}}in the definition).
When the change is sent and its answer is lost (action_outcome_unknown,
exit 22), itda runs that read once, as a read, and reportslanded,
not_foundorunknownnext to the error, asoutcome_checkin the CLI
output,--json, the MCP result and the audit record (outcome_check,
confirm_read). The change is never resent. Afterlanded, a new approval
request for the same inputs carries anotein the review and
previous_outcome: landedin the answer, so the person can decline.itda auditlists lost answers with what the read said;itda_manage audit
returns them underunknown_outcomewithcheck.itda lsanditda doctorreport aconfirmthat names a missing operation, a change or a
read that needs inputs as a definition problem.itda setupanditda draftfillconfirmwhen aPOST's list read is on the same path prefix
and a string input of the change appears in the read's records; the
evidence says so. The lab getslossy(8089), the scripted portal whose
post is saved and then the line drops, and every reviewed lab definition
names its confirming read. -
Files out: a read may declare
response: {format: file, media_types: [...], max_bytes: N, allow_empty: false}. itda streams the answer to a file under
files/<site>/in the data directory (oritda call ... --out <dir>),
seals it at the end, and returns a manifest{path, bytes, media_type, sha256}, never the bytes; over MCP the result adds aresource_linkto
the file and the tool's description says what comes back. The content type
must be one ofmedia_types(an HTML answer only as an attachment), and a
206 orContent-Range, a body shorter than itsContent-Length, an empty
body or one over the cap fail by name (wrong_media_type,partial_answer,
empty_answer,too_large) and leave nothing on disk. File names come
from the site'sContent-Dispositionor the address, reduced to plain
characters, and never replace a file already there.itda checkskips file
reads. A transfer longer than the gate's turn renews it (Lease::renew)
every 30 seconds; a lost turn stops the transfer (request_lease_lost). -
Files in: a change may declare
body: {multipart: {fields: {...}, file: {name, from}}}. The agent gives the path of a file on this computer in the
frominput; the approval shows the file's name, size and SHA-256 and is
bound to that hash, so other bytes under the same path withdraw it
(approval_expired,reason: file_changed). The file is streamed from one
open handle in 64 KiB chunks withContent-Lengthset, its size and
modification time checked before every chunk and its hash at the end; a
file that changes mid-send aborts the send (action_outcome_unknown,
reason: file_changed). The audit log records the hash. A body with a file
is always a change and goes only to the site's own origin. -
Drafts: a page form with
enctype=multipart/form-dataand a file control
becomes such a change (Upload a file to <page>), and links the page
labels as attachments (adownloadattribute, download or attachment
words in English or Korean, or an icon named for one) become file reads
grouped by shape (download-filewith afile_idinput), with
media_typesfrom the kinds the links name or the usual document types.
itda draft haranditda recorddraft a recorded multipart post from its
part names and a recordedContent-Disposition: attachmentanswer as a file
read.itda describesays what a file read returns and where it lands, and
which input a change sends as a file. -
Storage sessions: a site that keeps no session cookie and instead holds a
token in the browser'slocalStorage(orsessionStorage) and sends it as
Authorization: Beareror a custom header now signs in and works. When you
set the site up or record it, itda reads that one origin's storage once, over
the DevTools protocol, from the window you signed in to, and recognises the
token as the session when the recorded calls actually sent it as a header: a
JWT shape, or a long opaque value under a key named liketoken,
access_token,id_token,auth,sessionorjwt. A stored value no
request sent is reported and never kept. It is drafted as akind: header
auth entry withvalue_from: storage:<key>; the token lives in the keyring,
never in the definition, anditda login <site> --browserreads it again at
the next sign-in. If the token is a JWT withexp,itda checkreports
signed_out(notsite_changed) once it has passed, anditda_sitesshows
when the sign-in expires; itda never signs in again on its own. The token is
redacted from results, errors and the audit log like a cookie.value_from
on aheaderentry now acceptsstorage:<key>besidestore:<site>/<key>,
and on abrowserentryquery:<key>besidecookie:<name>, with a
validation error for anything else. itda reads only the signed-in origin's
storage, never another site's, never a profile on disk, and never writes
anything into a page; seedocs/THREAT_MODEL.md. The definition format is
unchanged:spec_versionstays 1. -
The API description a page points at is also found in the first page's
HTTPLinkheader (RFC 8288) and under two more relations:api-catalog
(RFC 9727) anddescribedby, in the header or on<link>/<a>.
Learning where costs no request.service-descwins, thenapi-catalog,
thendescribedby. An API catalog is a linkset (RFC 9264): itda follows
itsservice-desclinks, up to three, and takes the first OpenAPI
document. Adescribedbydocument counts only when it is one; otherwise
/openapi.jsonis still tried.relis matched as a list of relation
types, case-insensitively, sorel="not-service-desc"no longer counts.
Pagination'sheader:linkreads the header with the same parser, so a
target with a comma in it orrel="Next"is read right. -
itda spec validate <file> [--json]checks a definition the wayitda addwould (Spec::validateand the policy checks), without installing
it. A valid file exits 0; otherwise every problem is printed asproblem: <field>: <detail>, the way a draft prints its own, and it exits 2, the
definition-problem code.--jsongives{status, file, site, actions, issues}.
Changed
- The mark is a cursor striking a site; the hero shows it. The tile is a
white cursor at the bottom left, a browser window at the top right and a
blue bolt inside the window where the cursor's tip touches it. The favicon
is a heavier cut of the same tile that reads at 16 px. The landing's hero
adds the cursor from the mark: it flies in, strikes the terminal's prompt,
the transcript appears, it strikes the About window, and it holds; with
prefers-reduced-motionit rests at the prompt.assets/logo.svgis the
one master;assets/src/mark.pystamps it into the wordmarks and the hero,
assets/src/flow.pyreads it, andassets/social.htmlrenders the link
preview from it. The README banners (assets/hero.png,
assets/hero.ko.png) are rendered again and carry it in the wordmark. - The gate reads the request it is about to send, not only the declared
inputs. After the template is rendered, every query key and body field,
the value of an intent field such asactionormode, and any GraphQL
document inquery(orq/documenton a GraphQL path) are read again.
A declared read whose rendered request asks for a change (ajson_template
whose literal body is a mutation,{"op": "delete"}deep inside it) is
treated as a change:approval_requiredcarriesreclassifiedwith the
reason, the review shows it, and the audit record sayseffect: write
with the samereclassifiedreason. A read whose effect cannot be told (a
GraphQL endpoint sent no document, a document itda cannot read) stops with
effect_unknown(exit 2) and a remedy; nothing is sent. A declared write
is unchanged, and so are the 101 reads in the bundled definitions. itda describeshows the read a change names inconfirm, one line under
the change in the person's language (after a lost answer: checks list-notices for the new title);--jsonaddsconfirm: {read, match}.
The change's MCP tool description says the same in English, and
itda_describein catalog mode now returns the same description as the
tool, the approval note included.- Action descriptions are drafted in the person's language, any of the
twelve, not only in Korean or English: a Japanese setup now writes
Hacker News の一覧を読む, notList what Hacker News shows. The
language isITDA_LANGorLANG, else the page's<html lang>, else
English. The phrases are one table incrates/prep/src/label.rswith the
same placeholders in every language (a test checks it); the site's own
words (titles, field and operation names) stay as the site wrote them, and
outside Korean so does the kind of record (news articles). Agents read
all twelve; tool names, error codes and remedies stay English.
Fixed
- A site whose only reads save files ended
itda setupas if nothing
worked: setup skipped every file read ("saves a file"), so no read had
answered and the definition was thrown away. Setup now tries a file read
once, through the gate, by the answer's headers and first bytes: the
status, media type and size the definition allows count it as working, the
rest of the answer is dropped and nothing is saved. A read answered with a
page instead of the file is left out (wrong_media_type).itda check
still skips file reads. - A same-origin redirect or a next-page address of the form
/graphql?query=mutation{...}passed the read check, because only the
path and the query keys were read. The check now parses a GraphQL document
inquery(andq/documenton a GraphQL path) for its operation type;
a mutation or subscription is not followed or turned to. X-Original-URLandX-Rewrite-URL, which ask a server to treat the
request as one to another address, are refused like the method override
headers.- The SQLite database was created with the umask; only its directory was
private. The file and its-wal/-shmcompanions are now 0600 on Unix
(files left by an earlier run are tightened when the store opens); on
Windows the directory's ACL covers them.
Install itda-cli 0.6.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/brnyxx/itda-cli/releases/download/v0.6.0/itda-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/brnyxx/itda-cli/releases/download/v0.6.0/itda-cli-installer.ps1 | iex"Download itda-cli 0.6.0
| File | Platform | Checksum |
|---|---|---|
| itda-cli-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| itda-cli-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| itda-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| itda-cli-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| itda-cli-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |