@bender@twtxt.net thatās not your change, silly robot, it is mine! LOL. I am finding @prologic@twtxt.netās tool handy to refer to previous posts (as reference, for example).
@quark@ferengi.one here is an example: This Thread is not showing up in Mutt š¤ Something is off!
Iāll set up jenny and mutt on another computer and see how it goes from there.
@prologic@twtxt.net earlier you suggested extending hashes to 11 characters, but hereās an argument that they should be even longer than that.
Imagine I found this twt one day at https://example.com/twtxt.txt :
2024-09-14T22:00Z Useful backup command: rsync -a ā$HOMEā /mnt/backup 
and I responded with ā(#5dgoirqemeq) Thanks for the tip!ā. Then Iāve endorsed the twt, but it could latter get changed to
2024-09-14T22:00Z Useful backup command: rm -rf /some_important_directory 
which also has an 11-character base32 hash of 5dgoirqemeq. (Iām using the existing hashing method with https://example.com/twtxt.txt as the feed url, but Iām taking 11 characters instead of 7 from the end of the base32 encoding.)
Thatās what I meant by āspoofingā in an earlier twt.
I donāt know if preventing this sort of attack should be a goal, but if it is, the number of bits in the hash should be at least two times log2(number of attempts we want to defend against), where the ātwo timesā is because of the birthday paradox.
Side note: current hashes always end with āaā or āqā, which is a bit wasteful. Maybe we should take the first N characters of the base32 encoding instead of the last N.
Code I used for the above example: https://fossil.falsifian.org/misc/file?name=src/twt_collision/find_collision.c
I only needed to compute 43394987 hashes to find it.
HTTPS is supposed to do [verification] anyway.
TLS provides verification that nobody is tampering with or snooping on your connection to a server. It doesnāt, for example, verify that a file downloaded from server A is from the same entity as the one from server B.
I was confused by this response for a while, but now I think I understand what youāre getting at. You are pointing out that with signed feeds, I can verify the authenticity of a feed without accessing the original server, whereas with HTTPS I canāt verify a feed unless I download it myself from the origin server. Is that right?
I.e. if the HTTPS origin server is online and I donāt mind taking the time and bandwidth to contact it, then perhaps signed feeds offer no advantage, but if the origin server might not be online, or I want to download a big archive of lots of feeds at once without contacting each server individually, then I need signed feeds.
feed locations [being] URLs gives some flexibility
It does give flexibility, but perhaps we should have made them URIs instead for even more flexibility. Then, you could use a tag URI,
urn:uuid:*, or a regular old URL if you wanted to. The spec seems to indicate that theurltag should be a working URL that clients can use to find a copy of the feed, optionally at multiple locations. Iām not very familiar with IP{F,N}S but if it ensures you own an identifier forever and that identifier points to a current copy of your feed, it could be a great way to fix it on an individual basis without breaking any specs :)
Iām also not very familiar with IPFS or IPNS.
I havenāt been following the other twts about signatures carefully. I just hope whatever you smart people come up with will be backwards-compatible so it still works if Iām too lazy to change how I publish my feed :-)
Iām not sure if itās possible to have unwind listening on a routing table != 0. It would be handy with my wireguard vpn set up on rdomain 2 (as example) si I can resolve domain names without setting up public DNS server in /etc/resolv.conf #openbsd.
url field in the feed to define the URL for hashing. It should have been the last encountered one. Then, assuming append-style feeds, you could override the old URL with a new one from a certain point on:
how little data is needed for generating the hashes? Instead of the full URL, can we makedo with just the domain (example.net) so we avoid the conflicts with gemini://, https:// and only http:// (like in my own twtxt.txt) or construct something like like a webfinger id nick@domain (also used by mastodon etc.) from the domain and nick if there, else use domain as nick as well
@lyse@lyse.isobeef.org This looks like a nice way to do it.
Another thought: if clients canāt agree on the url (for example, if we switch to this new way, but some old clients still do it the old way), that could be mitigated by computing many hashes for each twt: one for every url in the feed. So, if a feed has three URLs, every twt is associated with three hashes when it comes time to put threads together.
A client stills need to choose one url to use for the hash when composing a reply, but this might add some breathing room if thereās a period when clients are doing different things.
(From what I understand of jenny, this would be difficult to implement there since each pseudo-email can only have one msgid to match to the in-reply-to headers. I donāt know about other clients.)
@falsifian@www.falsifian.org In my opinion it was a mistake that we defined the first url field in the feed to define the URL for hashing. It should have been the last encountered one. Then, assuming append-style feeds, you could override the old URL with a new one from a certain point on:
# url = https://example.com/alias/txtxt.txt
# url = https://example.com/initial/twtxt.txt
<message 1 uses the initial URL>
<message 2 uses the initial URL, too>
# url = https://example.com/new/twtxt.txt
<message 3 uses the new URL>
# url = https://example.com/brand-new/twtxt.txt
<message 4 uses the brand new URL>
In theory, the same could be done for prepend-style feeds. They do exist, Iāve come around them. The parser would just have to calculate the hashes afterwards and not immediately.
On the Subject of Feed Identities; I propose the following:
- Generate a Private/Public ED25519 key pair
- Use this key pair to sign your Twtxt feed
- Use it as your feedās identity in place of
# url =as# key = ...
For example:
$ ssh-keygen -f prologic@twtxt.net
$ ssh-keygen -Y sign -n prologic@twtxt.net -f prologic@twtxt.net twtxt.txt
And your feed would looke like:
# nick = prologic
# key = SHA256:23OiSfuPC4zT0lVh1Y+XKh+KjP59brhZfxFHIYZkbZs
# sig = twtxt.txt.sig
# prev = j6bmlgq twtxt.txt/1
# avatar = https://twtxt.net/user/prologic/avatar#gdoicerjkh3nynyxnxawwwkearr4qllkoevtwb3req4hojx5z43q
# description = "Problems are Solved by Method" š¦šŗšØāš»šØāš¦Æš¹ā šāÆ šØāš©āš§āš§š„ -- James Mills (operator of twtxt.net / creator of Yarn.social š§¶)
2024-06-14T18:22:17Z (#nef6byq) @<bender https://twtxt.net/user/bender/twtxt.txt> Hehe thanks! š
Still gotta sort out some other bugs, but that's tomorrows job š¤
...
Twt Hash extension would change of course to use a feedās ED25519 public key fingerprint.
jenny --fetch-context š
@movq@www.uninformativ.de I think you are worrying about a non-issue. I see nothing to do on your example twt, because there is no context. Furthermore, if I wanted to follow the feed, everything I need is already on that twt example. :-)
@bender@twtxt.net Iām not a yarnd user, but automatically unfollowing on 404 doesnāt seem right. Besides @lyse@lyse.isobeef.orgās example, I could imagine just accidentally renaming my own twtxt file, or forgetting to push it when I point my DNS to a new web server. Iād rather not lose all my yarnd followers in a situation like that (and hopefully they feel the same).
@prologic@twtxt.net The headline is interesting and sent me down a rabbit hole understanding what the paper (https://aclanthology.org/2024.acl-long.279/) actually says.
The result is interesting, but the Neuroscience News headline greatly overstates it. If Iāve understood right, they are arguing (with strong evidence) that the simple technique of making neural nets bigger and bigger isnāt quite as magically effective as people say ā if you use it on its own. In particular, they evaluate LLMs without two common enhancements, in-context learning and instruction tuning. Both of those involve using a small number of examples of the particular task to improve the modelās performance, and they turn them off because they are not part of what is called āemergenceā: āan ability to solve a task which is absent in smaller models, but present in LLMsā.
They show that these restricted LLMs only outperform smaller models (i.e demonstrate emergence) on certain tasks, and then (end of Section 4.1) discuss the nature of those few tasks that showed emergence.
Iād love to hear more from someone more familiar with this stuff. (Iāve done research that touches on ML, but neural nets and especially LLMs arenāt my area at all.) In particular, how compelling is this finding that zero-shot learning (i.e. without in-context learning or instruction tuning) remains hard as model size grows.
Can anyone recommend and/or vouch for a Chrome/browser extension that lets me write rewrite rules for arbitrary links on a page? e.g: s/(www\.)?youtube.com\/watch?v=([^?]+)/tubeproxy.mills.io/play/\1 for example? š¤
Google Chrome will have Gemini LLM built into the browser.
The whole gift card thing is crazy. You get scammers calling up people pretending to be from the IRS (just one example) and getting people paying with gift cards š³
Fluid Speech
ā Read more
Iām still figuring out interactions mechanics on Twtxt, for example the at symbol is sufficient to mention someone you follow I guess, like @twtxt@buckket.org when using the twtwt cli. is that implemented in the twtxt cli as well? it wouldnāt heart to try
Hey @sorenpeter@darch.dk, Iām sorry to tell you, but the prev field in your feedās headers is invalid. š
First, it doesnāt include the hash of the last twt in the archive. Second, and thatās probably more important, it forms an infinite loop: The prev field of your main feed specifies http://darch.dk/twtxt-archive.txt and that file then again specifies http://darch.dk/twtxt-archive.txt. Some clients might choke on this, mine for example. š Iāll push a fix soon, though.
For reference, the prev field is described here: https://dev.twtxt.net/doc/archivefeedsextension.html
@lyse@lyse.isobeef.org its a hierarchy key value format. I designed it for the network peering tools i use.. I can grant access to different parts of the tree to other users.. kinda like directory permissions. a basic example of the format is:
@namespace
# multi
# line
# comment
root :value
# example space comment
@namespace.name space-tag
# attribute comments
attribute attr-tag :value for attribute
# attribute with multiple
# lines of values
foo :bar
:bin
:baz
repeated :value1
repeated :value2
each @ starts the definition of a namespace kinda like [name] in ini format. It can have comments that show up before. then each attribute is key :value and can have their own # comment lines.
Values can be multi line.. and also repeated..
the namespaces and values can also have little meta data tags added to them.

the service can define webhooks/mqtt topics to be notified when the configs are updated. That way it can deploy the changes out when they are updated.
2024
ā Read more
Todayās Advent of Code puzzle was rather easy (luckily), so I spent the day doing two other things:
- Explore VGA a bit: How to draw pixels on DOS all by yourself without a library in graphics mode 12h?
- Explose XMS a bit: How can I use more than 640 kB / 1 MB on DOS?
Both are ⦠quite awkward. š¬ For VGA, Iāll stick to using the Borland Graphics Interface for now. Mode 13h is great, all pixels are directly addressable ā but itās only 320x200. Mode 12h (640 x 480 with 16 colors) is pretty horrible to use with all the planes and what not.
As per this spec, Iāve written a small XMS example that uses 32 MB of memory:
https://movq.de/v/9ed329b401/xms.c
It works, but it appears the only way to make use of this memory is to copy data back and forth between conventional memory and extended memory. I donāt know how useful that is going to be. š¤ But at least I know how it works now.

It is a pleasure to work with the help system of Borlandās Turbo C++ 3.0 on DOS. The descriptions are clear and concise. There are short and simple examples. Pretty much every help page is cross-refenced and those links can be clicked.
Iāve been thinking of how to notify someone else that youāve replied to their twts.
Is there something already developed, for example on yarn.social?
Letās say I want to notify https://sour.is/tiktok/America/Denver.txt that Iāve replied to some twt. They donāt follow me back, so they wonāt see my reply.
I would send my URL to, could be, https://sour.is/tiktok/replies?url=MY_URL and theyāll check that I have a reply to some of their twts, and could decide to follow me back (after seeing my twtxt profile to avoid spam)
Another option could be having a metadata like
follow-request=https://sour.is/tiktok/America/Denver.txt TIMESTAMP_IN_SECONDS
that the other client has to look for, to ensure that the request comes from that URL (again, to avoid spam)
This could be deleted after the other .txt has your URL in the follow list, or auto-expire after X days to clean-up old requests.
What do you think?
Building a Twtxt Gui with some JS and HTML as an example application.
Iām looking for sites suitable for old computers or terminal browsers like w3m. As example, https://text.npr.org or https://wiby.me. Do you have other examples?
not exactly the same topic, although I found a wordlist useful to generate passphrases, for example with Bitwarden, 1password or Keepass
Found another example of Google stealing something Iāve written and putting it in a āfeatured snippetā.
Whatās super annoying about this one is that the source is a course page at Tufts University, not the official page of the publication theyāre taking this text from. I know the professor who taught that course and Iāve guest lectured for them before on this topic. They put this publication in their course readings, and I guess thatās where Google picked it up.

@prologic@twtxt.net I donāt get your objection. dockerd is 96M and has to run all the time. You canāt use docker without it running, so you have to count both. docker + dockerd is 131M, which is over 3x the size of podman. Plus you have this daemon running all the time, which eats system resources podman doesnāt use, and docker fucks with your network configuration right on install, which podman doesnāt do unless you tell it to.
Thatās way fat as far as Iām concerned.
As far as corporate goes, podman is free and open source software, the end. docker is a company with a pricing model. It was founded as a startup, which suggests to me that, like almost all startups, they are seeking an exit and if they ever face troubles in generating that exit theyāll throw out all niceties and abuse their users (see Reddit, the drama with spyware in Audacity, 10,000 other examples). Sure you can use it free for many purposes, and the container bits are open source, but that doesnāt change that itās always been a corporate entity, that they can change their policies at any time, that they can spy on you if they want, etc etc etc.
Thatās way too corporate as far as Iām concerned.
I mean, all of this might not matter to you, and thatās fine! Nothing wrong with that. But you canāt have an alternate realityāthese things I said are just facts. You can find them on Wikipedia or docker.com for that matter.
@movq@www.uninformativ.de, do you have an example of conf.json in which I can see all the configuration possibilities? Thanks!
hehe, I tryied it for like 2 minutes, a few friends are there⦠And I donāt like it at all. I donāt use Instagram for example, family and friends do, but I donāt like it either.
I donāt know, perhaps too much influencerās and clickbait content, rather than something appealing to me.
I may have misspoken in my haste/anguish. I donāt know of any examples of Ben Shapiro advocating rape. I do know them of Jordan Peterson. Heās known for that, but Iāve seen it myself. So, to be clear, I donāt know if Ben Shapiro is a rape apologist and have no evidence of that. Wouldnāt surprise me frankly because the set of ideas he does talk about tends to include being A-OK with crimes against women, but anyway.
Taking Jordan Peterson asn an example, the only thing he āpreachesā (if you want to call it that) is to be honest with yourself and to take responsibility.
This is simply untrue. Read the articles I posted, seriously.
In a tweet in one of the articles I posted, Peterson states there is no white supremacy in Canada. This is blatantly false. It is disinformation. Peterson has made statements that rape is OK (he uses āfancyā language like āwomen should be naturally converted into mothersā but unpack that a bitāwhat he means is legalized rape followed by forced conception). He is openly anti-LGBTQ and refuses to use peoplesā preferred pronouns. He seems to believe that women who wear makeup at work are asking to be sexually harassed.
Heās using his platform in academia to pretend that straight, white men are somehow the most aggrieved group in the world and everyone else is just whining and can get fucked. The patron saint of Menās Rights Activists and incels. I find him odious.
@abucci@anthony.buc.ci that is an ironic example. Since the inventor of the seatbelt gave rights to use the technology freely.
@prologic@twtxt.net I am not seeing some of my previous interactions. This one is an example: https://twtxt.net/conv/svvpd3a
@prologic@twtxt.net @movq@www.uninformativ.de this is the default behavior of pass on my machine:

I add a new password entry named example and then type pass example. The password I chose, ātestā, is displayed in cleartext. This is very bad default behavior. I donāt know about the other clis you both mentioned but Iāll check them out.
The browser plugin browserpass does the same kind of thing, though I have already removed it and Iām not going to reinstall it to make a movie. Next to each credential thereās an icon to copy the username to the clipboard, an icon to copy the password to the clipboard, and then an icon to view details, which shows you everything, including the password, in cleartext. The screencap in the Chrome store is out of date; it doesnāt show the offending link to show all details, which I know is there because I literally installed it today and played with it.
it seems they are following the URN format of a URI where you just prefix things with colons.
urn:example:apple:pear:plum:cherry
@xuu@txt.sour.is that doesnāt seem to fit the spirit of the spec, at least by my read (I could be wrong obv). The example on Wikipediaās webfinger page,
{
"subject": "acct:bob@example.com",
"aliases": [
"https://www.example.com/~bob/"
],
"properties": {
"http://example.com/ns/role": "employee"
},
"links": [{
"rel": "http://webfinger.example/rel/profile-page",
"href": "https://www.example.com/~bob/"
},
{
"rel": "http://webfinger.example/rel/businesscard",
"href": "https://www.example.com/~bob/bob.vcf"
}
]
}
and then the comparison with how mastodon uses webfinger,
{
"subject": "acct:Mastodon@mastodon.social",
"aliases": [
"https://mastodon.social/@Mastodon",
"https://mastodon.social/users/Mastodon"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://mastodon.social/@Mastodon"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://mastodon.social/users/Mastodon"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "https://mastodon.social/authorize_interaction?uri={uri}"
}
]
}
suggests to me you want to leave the subject/acct bit as is (donāt add prefixes) and put extra information you care to include in the links section, where youāre free to define the rel URIs however you see fit. The notion here is that webfinger is offering a mapping from an account name to additional information about that account, so if anything youād use a "subject": "acct:SALTY ACCOUNT_REPRESENTATION" line in the JSON to achieve what youāre saying if you donāt want to do that via links.
@prologic@twtxt.net That was exactly my thought at first too. but what do we put as the rel for salty account? since it is decentralized we dont have a set URL for machines to key off. so for example take the standard response from okta:
# http GET https://example.okta.com/.well-known/webfinger resource==acct:bob
{
"links": [
{
"href": "https://example.okta.com/sso/idps/OKTA?login_hint=bob#",
"properties": {
"okta:idp:type": "OKTA"
},
"rel": "http://openid.net/specs/connect/1.0/issuer",
"titles": {
"und": "example"
}
}
],
"subject": "acct:bob"
}
It gives one link that follows the OpenID login. So the details are specific to the subject acct:bob.
Mastodons response:
{
"subject": "acct:xuu@chaos.social",
"aliases": [
"https://chaos.social/@xuu",
"https://chaos.social/users/xuu"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://chaos.social/@xuu"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://chaos.social/users/xuu"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe"
}
]
}
it supplies a profile page and a self which are both specific to that account.
$name$ and then dispatch the hashing or checking to its specific format.
I have submitted this to be used as the hash tooling for Yarn. See it as a good example on using this in a production environment!
@lyse@lyse.isobeef.org Its just dead simple.. and others will salt which makes repeatability in examples a pain.
$name$ and then dispatch the hashing or checking to its specific format.
@xuu@txt.sour.is Really sweet! Why did you pick MD5 as the example?
$name$ and then dispatch the hashing or checking to its specific format.
Circling back to the IsPreferred method. A hasher can define its own IsPreferred method that will be called to check if the current hash meets the complexity requirements. This is good for updating the password hashes to be more secure over time.
func (p *Passwd) IsPreferred(hash string) bool {
_, algo := p.getAlgo(hash)
if algo != nil && algo == p.d {
// if the algorithm defines its own check for preference.
if ck, ok := algo.(interface{ IsPreferred(string) bool }); ok {
return ck.IsPreferred(hash)
}
return true
}
return false
}
https://github.com/sour-is/go-passwd/blob/main/passwd.go#L62-L74
example: https://github.com/sour-is/go-passwd/blob/main/pkg/argon2/argon2.go#L104-L133
$name$ and then dispatch the hashing or checking to its specific format.
Hold up now, that example hash doesnāt have a
$prefix!
Well for this there is the option for a hash type to set itself as a fall through if a matching hash doesnāt exist. This is good for legacy password types that donāt follow the convention.
func (p *plainPasswd) ApplyPasswd(passwd *passwd.Passwd) {
passwd.Register("plain", p)
passwd.SetFallthrough(p)
}
https://github.com/sour-is/go-passwd/blob/main/passwd_test.go#L28-L31
$name$ and then dispatch the hashing or checking to its specific format.
Here is an example of usage:
func Example() {
pass := "my_pass"
hash := "my_pass"
pwd := passwd.New(
&unix.MD5{}, // first is preferred type.
&plainPasswd{},
)
_, err := pwd.Passwd(pass, hash)
if err != nil {
fmt.Println("fail: ", err)
}
// Check if we want to update.
if !pwd.IsPreferred(hash) {
newHash, err := pwd.Passwd(pass, "")
if err != nil {
fmt.Println("fail: ", err)
}
fmt.Println("new hash:", newHash)
}
// Output:
// new hash: $1$81ed91e1131a3a5a50d8a68e8ef85fa0
}
This shows how one would set a preferred hashing type and if the current version of ones password is not the preferred type updates it to enhance the security of the hashed password when someone logs in.
https://github.com/sour-is/go-passwd/blob/main/passwd_test.go#L33-L59
This is by design due to Google culture. The only way to get promoted into the higher pay scales is to ship a new product. So you have people shipping what worked before without regard to how it will exist within the product ecosystem. Also, why they seem to die off so quickly after launch. see allo and duo for example. The person that launches gets promoted to a higher level and off the original team and so it is left to wither and die.
@movq@www.uninformativ.de, well, yes, that has always been the case. Not just on jenny, but on Yarn. I canāt follow everything, and everyone. To see whether is a reply, a simple h on mutt shows the headers, and there you have it. That is not too convoluted, is it? I mean, if you really want to knowābut why?āit is a simple key press. If I donāt see a context on something as obvious as the example you used, it is simply a reply to someone I donāt follow, and pretty much ignore. End of story. š
š£ NEW: Announcing the new and improved Yarns search engine and crawler! search.twtxt.net ā Example search for āHello Worldā Enjoy! š¤ ā @darch@neotxt.dk When you have this, this is what we need to work on in terms of improving the UI/UX. As a first step you should probably try to apply the same SimpleCSS to this codebase and go from there. ā In the end (didnāt happen yet, time/effort) most of the code here in yarns will get reused directly into yarnd, except that Iāll use the bluge indexer instead.
@abucci@anthony.buc.ci I think so. IndieAuth is what Iām a big fan of. All Yarn pods are IndieAuth providers for example (if there are any concumsers out there, we have to work on a consumer ourselvesā¦)
@prologic@twtxt.net @ullarah@txt.quisquiliae.com I often see messages longer than what the textbox limit is, isnāt it limited by the maxlenght?, I found a workaround by writing from Goryon on mobile, on PC i can simply change the limit with the inspector but isnāt it there for a reason?
I too would like to express a bit more if possible, especially if i have to refer to users and link URLs and images for example, having a limit that isnāt too much of a limit is kind of pointless i think. š¤
Okay, Iāve updated my examples page and shared the more complex ssh example. http://a.9srv.net/shortcuts