Expand description
Texts on your computers, read and sent through your phone, without Sioul being the phone’s SMS app (docs/texts.md; research: docs/research/sms.md, phase b). The phone’s SMS app stays the record: a fault of Sioul’s can delay a text on the computer, never lose one on the phone.
Reading, the whole history. With READ_SMS, the phone reads its
texts from Android’s provider (the inbox and the sent box, multimedia
messages and group threads included: Android shows no other app the
drafts, the failed or queued texts, nor a multimedia message still to
download) and writes a line per message in its own log,
texts/log/<phone>.jsonl (Text), every column the provider gives kept
for a faithful restore. The first import goes a batch at a time. The log
only grows: a text deleted on the phone gets a line of its own saying so
(Text::deleted), and every device keeps what it holds.
Media. Each part of a multimedia message the phone has downloaded
(pictures, sound, video, cards, words) under a size you set travels as a
sealed blob of the sharing (blobs/), never inside a line (Part).
An archive. The texts and their media are kept in Sioul’s data folder on every device that shares the part, never trimmed by age, with every column a later restore of a new phone would need; that restore is not built.
Sending. A computer writes a Request in its own file
(texts/send/<device>.jsonl): a random key, the phone it must leave from,
the number, the words, the SIM, when it was written. The phone decides at
its step (verdict), claims the key in its private Ledger (written and
flushed before Android is asked), hands the text to Android, and says what
happened in its own texts/outcome/<phone>.jsonl (Outcome).
Never twice (verdict): a key already in the ledger is never sent
again, whatever the sharing reads again; a request written before the
ledger’s mark is refused (a ledger lost with the phone’s data cannot make
old requests new); a request names its phone, and another phone never
sends it; one older than EXPIRY_MS on the phone’s clock, corrected by
how far the writer’s clock may run ahead, is not sent; Sioul never
retries, Android does (three times, “reject duplicates”); after a crash
between the claim and the result, Sioul looks for the row Android filed
for it, and says “Your phone may not have sent it” when there is none
(doubt_after), never sending again by itself. Send again makes a new key.
Sealed at rest: every line of these stores, and every file of their
media, is sealed on the device that writes it (Sealer, with a key made
from the sharing key, in each device’s keyring), lines padded to steps of
PAD_STEP bytes inside: a computer’s copy is unreadable without the key.
Structs§
- Claim
- One line of the phone’s private ledger: a key, when, what was done.
- Conversation
- A conversation, as the Texts page lists it.
- Found
- One text found by
search, with its conversation. - Ledger
- The phone’s private ledger, never shared: every key it decided, and its mark.
- Limits
- What a SIM’s carrier lets a phone send (Android’s carrier configuration,
SmsManager.getCarrierConfigValues, which asks no permission), as the phone says it in its outcomes (a “limits” line): numbers only, never the carrier’s name. - LogRead 🔒
- A phone’s log as
Logsread it: its lines, how far, the bytes just before that place (to tell the same file grown from another one), and the file’s stamp then (Stamp). - Logs
- Every phone’s log under a root as
read_logsgives it, kept between two reads and read again only where a file grew (a log only grows: a line is added at its end, never changed); a file that changed otherwise (another file under its name, cut short) is read again whole. With each text’s fingerprint kept by phone and row (one_each): the window’s refresh after an exchange that brought one text opened 20,000 sealed lines and hashed them all, 0.3 s on its thread (the review of 16 October 2026, LOW 3). - Mark
- The ledger’s mark: requests written before it are never sent (a ledger lost cannot make them new).
- Marks
- Every device’s marks, by conversation: the latest moment read up to, and hidden up to.
- Medium
- A medium of a multimedia message written on a computer: its content’s hash (SHA-256, hex: its sealed blob in the sharing, and its sealed file on the computers), its content type, its size. Never its file’s name.
- Message
- One message of a conversation, or a text being sent.
- Outcome
- What became of a request, as its phone says it.
- Part
- One part of a multimedia message: its own columns, and where its content is.
- What a message is, whichever phone or backup holds it: what SMS Backup & Restore carries from one phone to another unchanged, and what its own backups hold of the rows Sioul’s archive keeps (docs/texts.md, “Each text once”). Never the provider’s row or conversation, which another phone numbers its own way.
- Request
- A text to send, as a computer writes it.
- Row
- A text’s row in its phone’s provider of texts: its table, Android’s
_id, and the row’s own date there (milliseconds for a plain text, seconds for a multimedia message, as the provider counts them): what tells two texts apart on one phone. The plain texts’ table has no AUTOINCREMENT, so the next text takes a deleted newest text’s id again, and a provider emptied starts again at 1; the date tells those rows apart (docs/texts.md, “A row’s name”). - Said
- A request’s state, as the computer says it.
- Shown
- A part of a message, as the page shows it.
- Stamp 🔒
- What tells a file unchanged since it was read: its size and time, and on
Unix its inode and change time, which no tool sets back (a file of the
same size whose time was put back, by rsync -t or a restore, is read
again: the review of 16 October 2026, LOW 6). On Windows, Rust’s
standard library gives neither (NTFS keeps a file ID and a change time,
which only its unstable parts read): such a file is read again there
once its size or time changes. NTFS’s tunnelling gives a file made again
within seconds under the same name the old one’s creation time, so
created()cannot be relied on either. - Text
- A text as the phone’s provider holds it, as it travels.
- Text
Mark - A device’s mark on a conversation (
MARKS): read up to a moment (ms), or hidden up to a moment, its texts until then gone from Sioul on every device (a conversation deleted in Sioul while it is not the phone’s SMS app: the phone’s own app keeps them). - Viewer
- What the view needs besides the lines.
Enums§
- Standing
- Where a device that asks stands in the sharing (
verdict, and the replies’Judge): counted now; gone by a sealed fact (it left, you forgot it, another device replaces it), refused; or not known yet (its records have not come, a file alone, a device silent for weeks), its request waiting while it is fresh (the review of 18 October 2026, I-a). - Took
- What a multimedia message’s result says (
TextSend.Result): sent, when Android took it to the carrier and the carrier answered Ok; not sent, and why; or, Android’s Ok with no answer of the carrier’s, to be looked for in the provider’s sent box (a message Android moved to its failed box is out of Sioul’s sight: none there, not sent); or in doubt, and why (“network”: each of Android’s tries ended on the network; “cancelled”: Android stopped it; “unexpected”: an unexpected failure, or a code Sioul does not know). - Verdict
- What the phone does with a request.
Constants§
- ADDR_
BCC - ADDR_CC
- ADDR_
FROM - A multimedia message’s address types (
addr.type, OMA’s PduHeaders): from, to, copy, hidden copy. - ADDR_TO
- AHEAD_
MS - A request dated further ahead of the phone’s clock than this is refused: the clocks disagree.
- BATCH
- The first import, and each step after: at most this many texts at a time.
- DAY_MS 🔒
- EXPIRY_
MS - A request older than this on the phone’s clock is not sent.
- FOLDER
- Their folder, in the data folder (an archive, never a cache).
- FOLD_MS
- A phone’s notification and a text are one message within this time, by number (
folded_into). - GSM_
BASIC 🔒 - GSM 03.38’s basic alphabet: one septet each.
- GSM_
EXTENDED 🔒 - Its extension table: two septets each.
- KEPT_
DAYS - Requests and outcomes are taken out by their device after this many days…
- LATE_
DAYS - …and by any device this many days later (45 in all). Texts never are.
- LEDGER
- The phone’s private files, in the state folder, never shared: the ledger, its mark, the reader’s marks and the import’s progress, Java’s results.
- LEDGER_
KEPT_ MS - The ledger keeps a key this long, past any request’s life.
- LIMITS_
AHEAD_ MS - A phone’s “limits” line dated further ahead of the reader’s clock than this is passed over (a phone whose clock was once set ahead).
- LOG
- Each phone’s texts, a line each, the whole history.
- LOG_
CHECK 🔒 - How many bytes before the place a log was read to tell the same file grown.
- LOOK_
AFTER_ MMS_ MS - …a multimedia message’s, handed or not, from this long after: Android may wait 30 minutes for a mobile network before its first try, and loses its queue if the phone restarts meanwhile (docs/texts.md)…
- LOOK_
AFTER_ MS - A claim with no word from Android this long after is looked for in the provider.
- MARK
- MARKS
- Each device’s marks on conversations: read up to a moment, hidden up to a moment (a conversation deleted in Sioul; 23 October 2026). Never trimmed.
- MEDIA
- The media of multimedia messages, each sealed at rest by its content’s hash; never shared as a store (they travel as blobs).
- MEDIA_
BATCH - …and this many bytes of media.
- MEDIA_
CAP_ MB - A part over this many bytes stays on the phone, said, unless you set another size (MB,
texts.toml). - MEDIA_
MAX - A multimedia message from a computer: at most this many media.
- MMS_
LAST_ WORD_ MS - …until this long after, Android’s last word at the latest: each of its
three tries may wait 30 minutes and 5 seconds for a network, then two
minutes on it, with 2 and 4 seconds between (
MmsRequest,MmsNetworkManager, android16-release: some 97 minutes). Not found by then: the doubt; until then, it may still go. - MMS_
MAX_ EVER - The most a multimedia message may weigh, whatever a phone said: Android’s
own ceiling for one (
MmsService.MAX_MMS_FILE_SIZE, 8 MB). - MOVED_
WITHIN_ MS - How far apart a received text’s two dates may be for a re-date (a provider re-dates its own sending, an MMS downloaded or sent, a resend; never a text received hours later under a deleted text’s id).
- OUTCOME
- Each phone’s word on each text it was asked to send.
- OWN_
ADDRESS - What Android writes for “this phone” among a multimedia message’s addresses.
- PAD_
STEP - Each line’s plain length is a multiple of this before it is sealed.
- PART
- The sharing’s part that carries them.
- PART_
KINDS - A part’s words for its kind: “texts-part-picture” and the others take a
size. - READER
- RESULTS
- SEND
- Each computer’s texts to send.
- STORES
- The shared stores, in that order.
- UNREAD_
DAYS - A text newer than this, in, not read since: unread (older ones count as read).
- WRITE_
MAX - A text written on a computer: at most this many characters.
Traits§
- Sealer
- What seals a line at rest and opens it: the caller’s, made from the sharing key.
Functions§
- append
- Lines added at the end of a device’s own file, under its lock, each
written whole (padded, sealed), those whose
idthe file holds already left out (id_of; none: every line written). Returns how many were written. - carried
- Words as XML 1.0 can carry them: the control characters it refuses (all below a space but the tab, the line feed and the carriage return, and U+FFFE, U+FFFF) left out. SMS Backup & Restore’s backups are XML, so a text restored from one never holds them.
- conversation_
id - A conversation’s id: its people’s keys, sorted, joined.
- conversations
- The conversations, newest first: every text’s, and those you wrote to from a computer.
- day_
and_ 🔒time - A moment’s day and time, for a thread: (“Today”, “14:02”), (“Monday 5 October”, “14:02”), (“Friday 3 May 2024”, “09:15”).
- doubt_
after - After a crash between the claim and Android’s word: what to say of a
claim
LOOK_AFTER_MSold with no result, given whether the provider holds a sent row Sioul filed for it (found: its row). Found: sent. Not found: “doubt”, never sent again. A multimedia message’s claim is looked for by its key fromLOOK_AFTER_MMS_MSon, and said in doubt only once Android’s last word is past (MMS_LAST_WORD_MS): until then it may still go. - drop_
hidden - A phone’s own log without the texts hidden on any device (
Marks): written again by its one writer, the phone, so that every computer’s copy loses them too. A line that does not open stays. How many went. - file_
name - A device’s name as its files name it (a line’s
device). - fold_
logs - The phones’ log lines (each with its
device) asread_logsgives them: oldest first, each text once by phone and row (a line named by its id alone and the same row named with its date are one: a phone put back on an older Sioul, which writes again under the old names what a newer one read, never doubles a text on the computers; the review of 16 October 2026, MEDIUM 1), a deletion’s line folded into its text, a line moved under its new name (its row’s date rewritten) shown under that name alone, its old name kept beside it (also), so that a request sent from a computer still finds its text (review of 18 October 2026, L-4). - folded_
into - The conversation a phone’s notification of a text is the same message
as (
phonemsgs::Line: its sender’s number’s key, its time): a text in from that one number withinFOLD_MS. None: it stays a line of its own. - folder
- The folder of the texts: the phones’ logs, the requests and outcomes, the media; in the data folder.
- grow 🔒
- A log read on from where it was read (
LogRead), or again whole when it is not that file grown; only whole lines. Whether its lines changed. - is_
false 🔒 - is_
words - A part’s content type that is words, never a medium: the text and the SMIL that lays it out.
- is_zero 🔒
- is_
zero_ 🔒u64 - kept
- What a device keeps: how many texts, and how many bytes of media here (
media: those whose sealed file is on this device). - kind_of 🔒
- What a part is, in a word for the page.
- known_
reason 🔒 - A failure’s reason as the words know it.
- known_
refusal 🔒 - A refusal’s reason as the words know it.
- last_
sim - The SIM a conversation last used, on the phone that sends: its texts’
sub, the newest; -1 none. - limits_
of - What a phone last said its carriers let it send (its newest “limits”
line), and when (ms); none before it said. A line dated more than
LIMITS_AHEAD_MSahead ofnow_ms(the reader’s clock) is passed over: a phone whose clock was once set ahead would otherwise be read by it until that date, whatever it said since. - messages
- A conversation’s messages, oldest first: its texts, deleted ones said, and
the texts you wrote to it from a computer with their states; a request
Android filed is said on its row, once. A row is its phone’s own: another
phone’s row of the same number is another text (
row_key). - mms_
failure - Why a multimedia message was not sent, as the words say it: Android’s code (SmsManager’s MMS_ERROR_…: 8 and 11 mobile data off, 3 no mobile network within 30 minutes, 2, 7 and 12 no multimedia settings for the carrier, 5 not read, 6 the carrier’s messaging app asking to try later, 9 and 10 an inactive SIM, 13 too large for a satellite link), else the carrier’s status (ENC 7.3.48: 0xC0 to 0xDF for a moment, 0xE1 service denied, 0xE5 content not accepted, 0xEB no credit, the rest refused; MMS 1.0’s 0x82, 0x87 and 0x88 alike).
- moved
- Whether
newis the message ofoldunder a date its provider rewrote: the same table and row id, another date, the same way and people; a text’s words the same, and either sent from the phone or dated withinMOVED_WITHIN_MSof the other (the plain texts’ table gives a deleted newest text’s id to the next one: Alice’s “Oui.” deleted, her next “Oui.” is another text, said deleted as before: review of 18 October 2026, L-3); a multimedia message’s media the same by their hashes wherever the older has them, its words and media as complete or more (one read before its parts were attached comes whole). - moved_
marks - The marks of the lines whose row its provider re-dated (
moved): each line of a phone’s log not marked yet whose row is no longer listed, while its row id is listed under another date with a line of the log holding the same message (the newest such): a deletion’s line naming it (Text::moved), never “deleted on your phone”. - new_key
- A random key, 32 hex digits, from the system’s randomness (
/dev/urandom); the clock’s when none. - no_sim 🔒
- number
- A column’s number, written as a number or as words.
- one_
each - Every phone’s texts with each text once (docs/texts.md, “Each text
once”): a text found in several phones’ logs, as after a restore onto a
new phone, once; a text there twice in one phone’s log (truly sent
twice), twice: for each fingerprint (
Print::key), as many as the phone holding most, its copies paired with the others’ in their logs’ order. The copy kept of each pair has the most media here, else is not deleted, else is the first phone’s by name; it is said deleted only when every copy is, and names the others (Text::also). Oldest first, asread_logs. For what the page, the search and agents read; the phones’ logs themselves keep every copy (nothing is lost if one goes). - one_
each_ by one_eachwith each text’s fingerprint asprintgives it (Print::keywith the region of the numbers, kept by phone and row between two reads:Logs).- own_
file - A device’s file in one of the stores under
root:<store>/<device>.jsonl. - padded
- A JSON object padded inside:
{…,"pad":" "}, its length a multiple ofPAD_STEP. - parts
- How many parts a text takes, and in which alphabet: GSM’s 7 bits (160
characters in one part, 153 in each of several) or UCS-2 (70, 67) as soon
as one character is outside it. Android chooses alike (
divideMessage). - place_
of 🔒 - A line’s place in its phone’s log: its row (
Row::of), so that a line named by its id alone (before 16 October 2026) and its row’s name now are one text; its name for a line of no row. - print_
people - Whether a multimedia message’s addresses of this type are its other
people for
Print: a received one’s sender; a sent one’s recipients. - private_
folder - The phone’s private texts folder, in the state folder: never shared.
- read_
file - Every line of a file that opens and reads, in order; the rest passed over.
- read_
lines - Every line of a file’s text that opens and reads, in order; the rest passed over.
- read_
logs - Every phone’s texts, oldest first, each once (by phone and row), a
deletion’s line folded into its text (
deleted); the whole history. - read_
outcomes - read_
requests - Every device’s requests under
root, each with its device: its sealed writer (a line whose writer is not its file’s device is passed over: moved from another device’s file), else, a request of an older Sioul, its file’s name. - read_
store 🔒 - Every device’s lines of a store under
root, each with its device. - record
- A line added to the ledger and flushed to the disk before this returns: the claim exists before Android is asked to send.
- record_
all - Lines added to the ledger together and flushed once before this returns (a step’s decisions: one flush, not one each); nothing for none.
- refusal
- Why a number or words are refused from a computer, if they are: several recipients (an MMS group), a short number (premium risk; Android would ask on the phone), no words, too many. None: it may go.
- refusal_
mms - Why a multimedia message is refused from a computer, if it is: its
words over
WRITE_MAX; no medium, or more thanMEDIA_MAX; a medium of a kind the phone does not send (pictures, videos, sounds, contact cards and calendar entries only: another file goes by mail) or not named by a content’s hash; other people beside its number (a group: a later step); a number asrefusalrefuses one. None: it may go. - replace_
flushed 🔒 - A file written whole beside, flushed, then put in place: a crash leaves the old one or the new one, never an empty one.
- row_key 🔒
- The key of the request a text is, by the row its phone filed it as
(
Outcome::row): its own row or one of its copies’ (Text::also), each on its own phone, never another phone’s row of the same number. An outcome that names no phone matches the row on any (as before phones were two). A row is its name with its date (Row::name); an outcome written before 16 October 2026 names it by its id alone, and matches that id’s text only from when its request could be sent (from) to a little after the outcome itself (Android files the row before its result comes:AHEAD_MS), never an older text whose id the text sent took again, nor a text received days later under that id (review of 16 October 2026, LOW 5). - said
- A request’s state in words, never red, never “late”: waiting for the phone
(and when it last shared), sending, sent at, delivered at (only when the
carrier said so), not sent and why, expired, may not have been sent. A
multimedia message (
media) refused “empty” was read by a phone whose Sioul cannot send one yet: said so; its media not there in time, said. - search
- The texts holding every word of
query, case and accents aside, in their words, a part’s name, or their people’s names or numbers; the newest first,limitat most. For a search of the archive (the MCP server’s). - sendable
- Whether a phone sends a medium of this content type in a multimedia message (decisions 7 to 9): a picture, a video, a sound, a contact card or a calendar entry.
- shown 🔒
- A part as the page shows it: what it is and its size; too large, or not downloaded, said; on its way when its file has not come yet. The SMIL, which only lays the message out, and the text parts (in the words) are not shown apart.
- state_
of - What a request’s outcomes say: its latest meaningful one (delivered over sent over handed…).
- time_of 🔒
- The time a line says (
at, elsewritten), opened; none when it does not open. - time_
of_ day - “14:02”: a moment (ms) as a time of day, in
now’s zone. - title_
of 🔒 - “Dr Martin”, “Dr Martin, Alice”, “01 99 00 12 34”.
- took
- A multimedia message’s result: Android’s code (-1,
Activity.RESULT_OK; elseSmsManager.MMS_ERROR_…), the carrier’s answer (M-Send.conf) when it came, and the HTTP status Android adds to its code 4 (0 none). Android’s Ok alone is not the carrier’s. Its code 4 with no HTTP status, or one under 400, says that every try ended on the network (an I/O failure, even a read timeout after the message was posted:MmsHttpClient,MmsRequest, android16-release): the carrier may have taken it, once or more; with a status of 400 or more, the carrier refused it. Its code 0 (Activity.RESULT_CANCELED: Android stopped it) and 1 (an unexpected failure, which may come after the message went), and any code Sioul does not know, are said in doubt too. - trim_
ledger - The ledger’s old keys taken out,
LEDGER_KEPT_MSon (any request expired long before; the mark refuses those written before it anyway). - trim_
others - Another device’s requests and outcomes
LATE_DAYSpast their time taken out here: texts never. - trim_
own - This device’s own requests and outcomes past
KEPT_DAYStaken out; its texts never (an archive). A line that does not open stays. Returns how many went. - unread
- A conversation’s unread texts: in, newer than
UNREAD_DAYS, after its last read mark, not deleted on the phone; newest first. - verdict
- The never-twice decision, step for step: another phone’s; decided already
(the ledger holds the key, whatever the sharing read again); written by
a computer of an older Sioul after this phone began to check writers
(“old-computer”); asked by a device gone from the sharing (
standing: it left, you forgot it, another device replaces it: “not-counted”), or one it does not know yet, which waits while its request is fresh (Verdict::Wait; then dated ahead or expired, as below); refused (refusal, a multimedia message’srefusal_mms); written before the ledger’s mark; dated ahead of the phone’s clock; older thanEXPIRY_MS; else sent. The time written is corrected by how far the writer’s clock may run ahead (Request::ahead, measured by the writer as an upper bound: a request looks older, never younger).standingis asked only of a request not decided yet. - visible
- The texts without those hidden (
Marks::hides). - when_
words 🔒 - “14:02” today, “Yesterday 14:02”, “Monday 5 October 14:02”.
- words_
hash - A text’s words, hashed as the ledger keeps them (FNV-1a, 16 hex digits).
- write_
flushed 🔒 - Written (or appended) and flushed to the disk, yours alone.
- write_
mark - A mark written in this device’s own file.
- write_
request - A request added to its device’s own file under
root, its writer (device) sealed in it, padded and sealed, under its lock. - written
- A value as written: its JSON padded with spaces inside a
padfield to a multiple ofPAD_STEPbytes, then sealed. No line says how long its words are. - xml_
char - A character XML 1.0 can carry (its
Char; Rust’s strings hold no lone surrogate).